diff options
Diffstat (limited to 'tk/generic')
104 files changed, 46826 insertions, 12614 deletions
diff --git a/tk/generic/default.h b/tk/generic/default.h index 1315608f33a..8db5f297b58 100644 --- a/tk/generic/default.h +++ b/tk/generic/default.h @@ -16,7 +16,8 @@ #ifndef _DEFAULT #define _DEFAULT -#if defined(__WIN32__) || defined(_WIN32) +#if defined(__WIN32__) || defined(_WIN32) || \ + defined(__CYGWIN__) || defined(__MINGW32__) # include "tkWinDefault.h" #else # if defined(MAC_TCL) @@ -27,3 +28,4 @@ #endif #endif /* _DEFAULT */ + diff --git a/tk/generic/ks_names.h b/tk/generic/ks_names.h index 759becc7b06..7c299e8b5f6 100644 --- a/tk/generic/ks_names.h +++ b/tk/generic/ks_names.h @@ -8,6 +8,8 @@ { "Clear", 0xFF0B }, { "Return", 0xFF0D }, { "Pause", 0xFF13 }, +{ "Scroll_Lock", 0xFF14 }, +{ "Sys_Req", 0xFF15 }, { "Escape", 0xFF1B }, { "Delete", 0xFFFF }, { "Multi_key", 0xFF20 }, @@ -919,3 +921,5 @@ { "hebrew_shin", 0xcf9 }, { "hebrew_taf", 0xcfa }, { "Hebrew_switch", 0xFF7E }, + + diff --git a/tk/generic/patchlevel.h b/tk/generic/patchlevel.h new file mode 100644 index 00000000000..8053233c2bf --- /dev/null +++ b/tk/generic/patchlevel.h @@ -0,0 +1,23 @@ +/* + * patchlevel.h -- + * + * This file does nothing except define a "patch level" for Tk. + * The patch level has the form "X.YpZ" where X.Y is the base + * release, and Z is a serial number that is used to sequence + * patches for a given release. Thus 4.0p1 is the first patch + * to release 4.0, 4.0p2 is the patch that follows 4.0p1, and + * so on. The "pZ" is omitted in an original new release, and + * it is replaced with "bZ" for beta releases or "aZ" for alpha + * releases (e.g. 4.0b1 is the first beta release of Tk 4.0). + * The patch level ensures that patches are applied in the + * correct order and only to appropriate sources. + * + * Copyright (c) 1994-1996 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: @(#) patchlevel.h 1.16 96/04/10 14:30:23 + */ + +#define TK_PATCH_LEVEL "4.1" diff --git a/tk/generic/prolog.ps b/tk/generic/prolog.ps new file mode 100644 index 00000000000..2ab137266ef --- /dev/null +++ b/tk/generic/prolog.ps @@ -0,0 +1,285 @@ +%%BeginProlog +50 dict begin + +% This is a standard prolog for Postscript generated by Tk's canvas +% widget. +% RCS: @(#) $Id$ + +% The definitions below just define all of the variables used in +% any of the procedures here. This is needed for obscure reasons +% explained on p. 716 of the Postscript manual (Section H.2.7, +% "Initializing Variables," in the section on Encapsulated Postscript). + +/baseline 0 def +/stipimage 0 def +/height 0 def +/justify 0 def +/lineLength 0 def +/spacing 0 def +/stipple 0 def +/strings 0 def +/xoffset 0 def +/yoffset 0 def +/tmpstip null def + +% Define the array ISOLatin1Encoding (which specifies how characters are +% encoded for ISO-8859-1 fonts), if it isn't already present (Postscript +% level 2 is supposed to define it, but level 1 doesn't). + +systemdict /ISOLatin1Encoding known not { + /ISOLatin1Encoding [ + /space /space /space /space /space /space /space /space + /space /space /space /space /space /space /space /space + /space /space /space /space /space /space /space /space + /space /space /space /space /space /space /space /space + /space /exclam /quotedbl /numbersign /dollar /percent /ampersand + /quoteright + /parenleft /parenright /asterisk /plus /comma /minus /period /slash + /zero /one /two /three /four /five /six /seven + /eight /nine /colon /semicolon /less /equal /greater /question + /at /A /B /C /D /E /F /G + /H /I /J /K /L /M /N /O + /P /Q /R /S /T /U /V /W + /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore + /quoteleft /a /b /c /d /e /f /g + /h /i /j /k /l /m /n /o + /p /q /r /s /t /u /v /w + /x /y /z /braceleft /bar /braceright /asciitilde /space + /space /space /space /space /space /space /space /space + /space /space /space /space /space /space /space /space + /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent + /dieresis /space /ring /cedilla /space /hungarumlaut /ogonek /caron + /space /exclamdown /cent /sterling /currency /yen /brokenbar /section + /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen + /registered /macron + /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph + /periodcentered + /cedillar /onesuperior /ordmasculine /guillemotright /onequarter + /onehalf /threequarters /questiondown + /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla + /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex + /Idieresis + /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply + /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn + /germandbls + /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla + /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex + /idieresis + /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide + /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn + /ydieresis + ] def +} if + +% font ISOEncode font +% This procedure changes the encoding of a font from the default +% Postscript encoding to ISOLatin1. It's typically invoked just +% before invoking "setfont". The body of this procedure comes from +% Section 5.6.1 of the Postscript book. + +/ISOEncode { + dup length dict begin + {1 index /FID ne {def} {pop pop} ifelse} forall + /Encoding ISOLatin1Encoding def + currentdict + end + + % I'm not sure why it's necessary to use "definefont" on this new + % font, but it seems to be important; just use the name "Temporary" + % for the font. + + /Temporary exch definefont +} bind def + +% StrokeClip +% +% This procedure converts the current path into a clip area under +% the assumption of stroking. It's a bit tricky because some Postscript +% interpreters get errors during strokepath for dashed lines. If +% this happens then turn off dashes and try again. + +/StrokeClip { + {strokepath} stopped { + (This Postscript printer gets limitcheck overflows when) = + (stippling dashed lines; lines will be printed solid instead.) = + [] 0 setdash strokepath} if + clip +} bind def + +% desiredSize EvenPixels closestSize +% +% The procedure below is used for stippling. Given the optimal size +% of a dot in a stipple pattern in the current user coordinate system, +% compute the closest size that is an exact multiple of the device's +% pixel size. This allows stipple patterns to be displayed without +% aliasing effects. + +/EvenPixels { + % Compute exact number of device pixels per stipple dot. + dup 0 matrix currentmatrix dtransform + dup mul exch dup mul add sqrt + + % Round to an integer, make sure the number is at least 1, and compute + % user coord distance corresponding to this. + dup round dup 1 lt {pop 1} if + exch div mul +} bind def + +% width height string StippleFill -- +% +% Given a path already set up and a clipping region generated from +% it, this procedure will fill the clipping region with a stipple +% pattern. "String" contains a proper image description of the +% stipple pattern and "width" and "height" give its dimensions. Each +% stipple dot is assumed to be about one unit across in the current +% user coordinate system. This procedure trashes the graphics state. + +/StippleFill { + % The following code is needed to work around a NeWSprint bug. + + /tmpstip 1 index def + + % Change the scaling so that one user unit in user coordinates + % corresponds to the size of one stipple dot. + 1 EvenPixels dup scale + + % Compute the bounding box occupied by the path (which is now + % the clipping region), and round the lower coordinates down + % to the nearest starting point for the stipple pattern. Be + % careful about negative numbers, since the rounding works + % differently on them. + + pathbbox + 4 2 roll + 5 index div dup 0 lt {1 sub} if cvi 5 index mul 4 1 roll + 6 index div dup 0 lt {1 sub} if cvi 6 index mul 3 2 roll + + % Stack now: width height string y1 y2 x1 x2 + % Below is a doubly-nested for loop to iterate across this area + % in units of the stipple pattern size, going up columns then + % across rows, blasting out a stipple-pattern-sized rectangle at + % each position + + 6 index exch { + 2 index 5 index 3 index { + % Stack now: width height string y1 y2 x y + + gsave + 1 index exch translate + 5 index 5 index true matrix tmpstip imagemask + grestore + } for + pop + } for + pop pop pop pop pop +} bind def + +% -- AdjustColor -- +% Given a color value already set for output by the caller, adjusts +% that value to a grayscale or mono value if requested by the CL +% variable. + +/AdjustColor { + CL 2 lt { + currentgray + CL 0 eq { + .5 lt {0} {1} ifelse + } if + setgray + } if +} bind def + +% x y strings spacing xoffset yoffset justify stipple DrawText -- +% This procedure does all of the real work of drawing text. The +% color and font must already have been set by the caller, and the +% following arguments must be on the stack: +% +% x, y - Coordinates at which to draw text. +% strings - An array of strings, one for each line of the text item, +% in order from top to bottom. +% spacing - Spacing between lines. +% xoffset - Horizontal offset for text bbox relative to x and y: 0 for +% nw/w/sw anchor, -0.5 for n/center/s, and -1.0 for ne/e/se. +% yoffset - Vertical offset for text bbox relative to x and y: 0 for +% nw/n/ne anchor, +0.5 for w/center/e, and +1.0 for sw/s/se. +% justify - 0 for left justification, 0.5 for center, 1 for right justify. +% stipple - Boolean value indicating whether or not text is to be +% drawn in stippled fashion. If text is stippled, +% procedure StippleText must have been defined to call +% StippleFill in the right way. +% +% Also, when this procedure is invoked, the color and font must already +% have been set for the text. + +/DrawText { + /stipple exch def + /justify exch def + /yoffset exch def + /xoffset exch def + /spacing exch def + /strings exch def + + % First scan through all of the text to find the widest line. + + /lineLength 0 def + strings { + stringwidth pop + dup lineLength gt {/lineLength exch def} {pop} ifelse + newpath + } forall + + % Compute the baseline offset and the actual font height. + + 0 0 moveto (TXygqPZ) false charpath + pathbbox dup /baseline exch def + exch pop exch sub /height exch def pop + newpath + + % Translate coordinates first so that the origin is at the upper-left + % corner of the text's bounding box. Remember that x and y for + % positioning are still on the stack. + + translate + lineLength xoffset mul + strings length 1 sub spacing mul height add yoffset mul translate + + % Now use the baseline and justification information to translate so + % that the origin is at the baseline and positioning point for the + % first line of text. + + justify lineLength mul baseline neg translate + + % Iterate over each of the lines to output it. For each line, + % compute its width again so it can be properly justified, then + % display it. + + strings { + dup stringwidth pop + justify neg mul 0 moveto + stipple { + + % The text is stippled, so turn it into a path and print + % by calling StippledText, which in turn calls StippleFill. + % Unfortunately, many Postscript interpreters will get + % overflow errors if we try to do the whole string at + % once, so do it a character at a time. + + gsave + /char (X) def + { + char 0 3 -1 roll put + currentpoint + gsave + char true charpath clip StippleText + grestore + char stringwidth translate + moveto + } forall + grestore + } {show} ifelse + 0 spacing neg translate + } forall +} bind def + +%%EndProlog + diff --git a/tk/generic/tk.decls b/tk/generic/tk.decls new file mode 100644 index 00000000000..51679e2ad3d --- /dev/null +++ b/tk/generic/tk.decls @@ -0,0 +1,1215 @@ +# tk.decls -- +# +# This file contains the declarations for all supported public +# functions that are exported by the Tk library via the stubs table. +# This file is used to generate the tkDecls.h, tkPlatDecls.h, +# tkStub.c, and tkPlatStub.c files. +# +# +# Copyright (c) 1998-1999 by Scriptics Corporation. +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id$ + +library tk + +# Define the tk interface with 3 sub interfaces: +# tkPlat - platform specific public +# tkInt - generic private +# tkPlatInt - platform specific private + +interface tk +hooks {tkPlat tkInt tkIntPlat tkIntXlib} + +# Declare each of the functions in the public Tk interface. Note that +# the an index should never be reused for a different function in order +# to preserve backwards compatibility. + +declare 0 generic { + void Tk_MainLoop (void) +} + +declare 1 generic { + XColor *Tk_3DBorderColor (Tk_3DBorder border) +} + +declare 2 generic { + GC Tk_3DBorderGC (Tk_Window tkwin, Tk_3DBorder border, \ + int which) +} + +declare 3 generic { + void Tk_3DHorizontalBevel (Tk_Window tkwin, \ + Drawable drawable, Tk_3DBorder border, int x, \ + int y, int width, int height, int leftIn, \ + int rightIn, int topBevel, int relief) +} + +declare 4 generic { + void Tk_3DVerticalBevel (Tk_Window tkwin, \ + Drawable drawable, Tk_3DBorder border, int x, \ + int y, int width, int height, int leftBevel, \ + int relief) +} + +declare 5 generic { + void Tk_AddOption (Tk_Window tkwin, char *name, \ + char *value, int priority) +} + +declare 6 generic { + void Tk_BindEvent (Tk_BindingTable bindingTable, \ + XEvent *eventPtr, Tk_Window tkwin, int numObjects, \ + ClientData *objectPtr) +} + +declare 7 generic { + void Tk_CanvasDrawableCoords (Tk_Canvas canvas, \ + double x, double y, short *drawableXPtr, \ + short *drawableYPtr) +} + +declare 8 generic { + void Tk_CanvasEventuallyRedraw (Tk_Canvas canvas, int x1, int y1, \ + int x2, int y2) +} + +declare 9 generic { + int Tk_CanvasGetCoord (Tcl_Interp *interp, \ + Tk_Canvas canvas, char *str, double *doublePtr) +} + +declare 10 generic { + Tk_CanvasTextInfo *Tk_CanvasGetTextInfo (Tk_Canvas canvas) +} + +declare 11 generic { + int Tk_CanvasPsBitmap (Tcl_Interp *interp, \ + Tk_Canvas canvas, Pixmap bitmap, int x, int y, \ + int width, int height) +} + +declare 12 generic { + int Tk_CanvasPsColor (Tcl_Interp *interp, \ + Tk_Canvas canvas, XColor *colorPtr) +} + +declare 13 generic { + int Tk_CanvasPsFont (Tcl_Interp *interp, \ + Tk_Canvas canvas, Tk_Font font) +} + +declare 14 generic { + void Tk_CanvasPsPath (Tcl_Interp *interp, \ + Tk_Canvas canvas, double *coordPtr, int numPoints) +} + +declare 15 generic { + int Tk_CanvasPsStipple (Tcl_Interp *interp, \ + Tk_Canvas canvas, Pixmap bitmap) +} + +declare 16 generic { + double Tk_CanvasPsY (Tk_Canvas canvas, double y) +} + +declare 17 generic { + void Tk_CanvasSetStippleOrigin (Tk_Canvas canvas, GC gc) +} + +declare 18 generic { + int Tk_CanvasTagsParseProc (ClientData clientData, Tcl_Interp *interp, \ + Tk_Window tkwin, char *value, char *widgRec, int offset) +} + +declare 19 generic { + char * Tk_CanvasTagsPrintProc (ClientData clientData, Tk_Window tkwin, \ + char *widgRec, int offset, Tcl_FreeProc **freeProcPtr) +} + +declare 20 generic { + Tk_Window Tk_CanvasTkwin (Tk_Canvas canvas) +} + +declare 21 generic { + void Tk_CanvasWindowCoords (Tk_Canvas canvas, double x, double y, \ + short *screenXPtr, short *screenYPtr) +} + +declare 22 generic { + void Tk_ChangeWindowAttributes (Tk_Window tkwin, unsigned long valueMask, \ + XSetWindowAttributes *attsPtr) +} + +declare 23 generic { + int Tk_CharBbox (Tk_TextLayout layout, int index, int *xPtr, \ + int *yPtr, int *widthPtr, int *heightPtr) +} + +declare 24 generic { + void Tk_ClearSelection (Tk_Window tkwin, Atom selection) +} + +declare 25 generic { + int Tk_ClipboardAppend (Tcl_Interp *interp,Tk_Window tkwin, \ + Atom target, Atom format, char* buffer) +} + +declare 26 generic { + int Tk_ClipboardClear (Tcl_Interp *interp, Tk_Window tkwin) +} + +declare 27 generic { + int Tk_ConfigureInfo (Tcl_Interp *interp, \ + Tk_Window tkwin, Tk_ConfigSpec *specs, \ + char *widgRec, char *argvName, int flags) +} + +declare 28 generic { + int Tk_ConfigureValue (Tcl_Interp *interp, \ + Tk_Window tkwin, Tk_ConfigSpec *specs, \ + char *widgRec, char *argvName, int flags) +} + +declare 29 generic { + int Tk_ConfigureWidget (Tcl_Interp *interp, \ + Tk_Window tkwin, Tk_ConfigSpec *specs, \ + int argc, char **argv, char *widgRec, \ + int flags) +} + +declare 30 generic { + void Tk_ConfigureWindow (Tk_Window tkwin, \ + unsigned int valueMask, XWindowChanges *valuePtr) +} + +declare 31 generic { + Tk_TextLayout Tk_ComputeTextLayout (Tk_Font font, \ + CONST char *str, int numChars, int wrapLength, \ + Tk_Justify justify, int flags, int *widthPtr, \ + int *heightPtr) +} + +declare 32 generic { + Tk_Window Tk_CoordsToWindow (int rootX, int rootY, Tk_Window tkwin) +} + +declare 33 generic { + unsigned long Tk_CreateBinding (Tcl_Interp *interp, \ + Tk_BindingTable bindingTable, ClientData object, \ + char *eventStr, char *command, int append) +} + +declare 34 generic { + Tk_BindingTable Tk_CreateBindingTable (Tcl_Interp *interp) +} + +declare 35 generic { + Tk_ErrorHandler Tk_CreateErrorHandler (Display *display, \ + int errNum, int request, int minorCode, \ + Tk_ErrorProc *errorProc, ClientData clientData) +} + +declare 36 generic { + void Tk_CreateEventHandler (Tk_Window token, \ + unsigned long mask, Tk_EventProc *proc, \ + ClientData clientData) +} + +declare 37 generic { + void Tk_CreateGenericHandler (Tk_GenericProc *proc, ClientData clientData) +} + +declare 38 generic { + void Tk_CreateImageType (Tk_ImageType *typePtr) +} + +declare 39 generic { + void Tk_CreateItemType (Tk_ItemType *typePtr) +} + +declare 40 generic { + void Tk_CreatePhotoImageFormat (Tk_PhotoImageFormat *formatPtr) +} + +declare 41 generic { + void Tk_CreateSelHandler (Tk_Window tkwin, \ + Atom selection, Atom target, \ + Tk_SelectionProc *proc, ClientData clientData, \ + Atom format) +} + +declare 42 generic { + Tk_Window Tk_CreateWindow (Tcl_Interp *interp, \ + Tk_Window parent, char *name, char *screenName) +} + +declare 43 generic { + Tk_Window Tk_CreateWindowFromPath (Tcl_Interp *interp, Tk_Window tkwin, \ + char *pathName, char *screenName) +} + +declare 44 generic { + int Tk_DefineBitmap (Tcl_Interp *interp, CONST char *name, char *source, \ + int width, int height) +} + +declare 45 generic { + void Tk_DefineCursor (Tk_Window window, Tk_Cursor cursor) +} + +declare 46 generic { + void Tk_DeleteAllBindings (Tk_BindingTable bindingTable, ClientData object) +} + +declare 47 generic { + int Tk_DeleteBinding (Tcl_Interp *interp, \ + Tk_BindingTable bindingTable, ClientData object, \ + char *eventStr) +} + +declare 48 generic { + void Tk_DeleteBindingTable (Tk_BindingTable bindingTable) +} + +declare 49 generic { + void Tk_DeleteErrorHandler (Tk_ErrorHandler handler) +} + +declare 50 generic { + void Tk_DeleteEventHandler (Tk_Window token, \ + unsigned long mask, Tk_EventProc *proc, \ + ClientData clientData) +} + +declare 51 generic { + void Tk_DeleteGenericHandler (Tk_GenericProc *proc, ClientData clientData) +} + +declare 52 generic { + void Tk_DeleteImage (Tcl_Interp *interp, char *name) +} + +declare 53 generic { + void Tk_DeleteSelHandler (Tk_Window tkwin, Atom selection, Atom target) +} + +declare 54 generic { + void Tk_DestroyWindow (Tk_Window tkwin) +} + +declare 55 generic { + char * Tk_DisplayName (Tk_Window tkwin) +} + +declare 56 generic { + int Tk_DistanceToTextLayout (Tk_TextLayout layout, int x, int y) +} + +declare 57 generic { + void Tk_Draw3DPolygon (Tk_Window tkwin, \ + Drawable drawable, Tk_3DBorder border, \ + XPoint *pointPtr, int numPoints, int borderWidth, \ + int leftRelief) +} + +declare 58 generic { + void Tk_Draw3DRectangle (Tk_Window tkwin, Drawable drawable, \ + Tk_3DBorder border, int x, int y, int width, int height, \ + int borderWidth, int relief) +} + +declare 59 generic { + void Tk_DrawChars (Display *display, Drawable drawable, GC gc, \ + Tk_Font tkfont, CONST char *source, int numBytes, int x, int y) +} + +declare 60 generic { + void Tk_DrawFocusHighlight (Tk_Window tkwin, GC gc, int width, \ + Drawable drawable) +} + +declare 61 generic { + void Tk_DrawTextLayout (Display *display, \ + Drawable drawable, GC gc, Tk_TextLayout layout, \ + int x, int y, int firstChar, int lastChar) +} + +declare 62 generic { + void Tk_Fill3DPolygon (Tk_Window tkwin, \ + Drawable drawable, Tk_3DBorder border, \ + XPoint *pointPtr, int numPoints, int borderWidth, \ + int leftRelief) +} + +declare 63 generic { + void Tk_Fill3DRectangle (Tk_Window tkwin, \ + Drawable drawable, Tk_3DBorder border, int x, \ + int y, int width, int height, int borderWidth, \ + int relief) +} + +declare 64 generic { + Tk_PhotoHandle Tk_FindPhoto (Tcl_Interp *interp, char *imageName) +} + +declare 65 generic { + Font Tk_FontId (Tk_Font font) +} + +declare 66 generic { + void Tk_Free3DBorder (Tk_3DBorder border) +} + +declare 67 generic { + void Tk_FreeBitmap (Display *display, Pixmap bitmap) +} + +declare 68 generic { + void Tk_FreeColor (XColor *colorPtr) +} + +declare 69 generic { + void Tk_FreeColormap (Display *display, Colormap colormap) +} + +declare 70 generic { + void Tk_FreeCursor (Display *display, Tk_Cursor cursor) +} + +declare 71 generic { + void Tk_FreeFont (Tk_Font f) +} + +declare 72 generic { + void Tk_FreeGC (Display *display, GC gc) +} + +declare 73 generic { + void Tk_FreeImage (Tk_Image image) +} + +declare 74 generic { + void Tk_FreeOptions (Tk_ConfigSpec *specs, \ + char *widgRec, Display *display, int needFlags) +} + +declare 75 generic { + void Tk_FreePixmap (Display *display, Pixmap pixmap) +} + +declare 76 generic { + void Tk_FreeTextLayout (Tk_TextLayout textLayout) +} + +declare 77 generic { + void Tk_FreeXId (Display *display, XID xid) +} + +declare 78 generic { + GC Tk_GCForColor (XColor *colorPtr, Drawable drawable) +} + +declare 79 generic { + void Tk_GeometryRequest (Tk_Window tkwin, int reqWidth, int reqHeight) +} + +declare 80 generic { + Tk_3DBorder Tk_Get3DBorder (Tcl_Interp *interp, Tk_Window tkwin, \ + Tk_Uid colorName) +} + +declare 81 generic { + void Tk_GetAllBindings (Tcl_Interp *interp, \ + Tk_BindingTable bindingTable, ClientData object) +} + +declare 82 generic { + int Tk_GetAnchor (Tcl_Interp *interp, \ + char *str, Tk_Anchor *anchorPtr) +} + +declare 83 generic { + char * Tk_GetAtomName (Tk_Window tkwin, Atom atom) +} + +declare 84 generic { + char * Tk_GetBinding (Tcl_Interp *interp, \ + Tk_BindingTable bindingTable, ClientData object, \ + char *eventStr) +} + +declare 85 generic { + Pixmap Tk_GetBitmap (Tcl_Interp *interp, Tk_Window tkwin, CONST char * str) +} + +declare 86 generic { + Pixmap Tk_GetBitmapFromData (Tcl_Interp *interp, \ + Tk_Window tkwin, char *source, int width, int height) +} + +declare 87 generic { + int Tk_GetCapStyle (Tcl_Interp *interp, char *str, int *capPtr) +} + +declare 88 generic { + XColor * Tk_GetColor (Tcl_Interp *interp, Tk_Window tkwin, Tk_Uid name) +} + +declare 89 generic { + XColor * Tk_GetColorByValue (Tk_Window tkwin, XColor *colorPtr) +} + +declare 90 generic { + Colormap Tk_GetColormap (Tcl_Interp *interp, Tk_Window tkwin, char *str) +} + +declare 91 generic { + Tk_Cursor Tk_GetCursor (Tcl_Interp *interp, Tk_Window tkwin, \ + Tk_Uid str) +} + +declare 92 generic { + Tk_Cursor Tk_GetCursorFromData (Tcl_Interp *interp, \ + Tk_Window tkwin, char *source, char *mask, \ + int width, int height, int xHot, int yHot, \ + Tk_Uid fg, Tk_Uid bg) +} + +declare 93 generic { + Tk_Font Tk_GetFont (Tcl_Interp *interp, \ + Tk_Window tkwin, CONST char *str) +} + +declare 94 generic { + Tk_Font Tk_GetFontFromObj (Tk_Window tkwin, Tcl_Obj *objPtr) +} + +declare 95 generic { + void Tk_GetFontMetrics (Tk_Font font, Tk_FontMetrics *fmPtr) +} + +declare 96 generic { + GC Tk_GetGC (Tk_Window tkwin, unsigned long valueMask, XGCValues *valuePtr) +} + +declare 97 generic { + Tk_Image Tk_GetImage (Tcl_Interp *interp, Tk_Window tkwin, char *name, \ + Tk_ImageChangedProc *changeProc, ClientData clientData) +} + +declare 98 generic { + ClientData Tk_GetImageMasterData (Tcl_Interp *interp, \ + char *name, Tk_ImageType **typePtrPtr) +} + +declare 99 generic { + Tk_ItemType * Tk_GetItemTypes (void) +} + +declare 100 generic { + int Tk_GetJoinStyle (Tcl_Interp *interp, char *str, int *joinPtr) +} + +declare 101 generic { + int Tk_GetJustify (Tcl_Interp *interp, \ + char *str, Tk_Justify *justifyPtr) +} + +declare 102 generic { + int Tk_GetNumMainWindows (void) +} + +declare 103 generic { + Tk_Uid Tk_GetOption (Tk_Window tkwin, char *name, char *className) +} + +declare 104 generic { + int Tk_GetPixels (Tcl_Interp *interp, \ + Tk_Window tkwin, char *str, int *intPtr) +} + +declare 105 generic { + Pixmap Tk_GetPixmap (Display *display, Drawable d, \ + int width, int height, int depth) +} + +declare 106 generic { + int Tk_GetRelief (Tcl_Interp *interp, char *name, int *reliefPtr) +} + +declare 107 generic { + void Tk_GetRootCoords (Tk_Window tkwin, int *xPtr, int *yPtr) +} + +declare 108 generic { + int Tk_GetScrollInfo (Tcl_Interp *interp, \ + int argc, char **argv, double *dblPtr, int *intPtr) +} + +declare 109 generic { + int Tk_GetScreenMM (Tcl_Interp *interp, \ + Tk_Window tkwin, char *str, double *doublePtr) +} + +declare 110 generic { + int Tk_GetSelection (Tcl_Interp *interp, \ + Tk_Window tkwin, Atom selection, Atom target, \ + Tk_GetSelProc *proc, ClientData clientData) +} + +declare 111 generic { + Tk_Uid Tk_GetUid (CONST char *str) +} + +declare 112 generic { + Visual * Tk_GetVisual (Tcl_Interp *interp, \ + Tk_Window tkwin, char *str, int *depthPtr, \ + Colormap *colormapPtr) +} + +declare 113 generic { + void Tk_GetVRootGeometry (Tk_Window tkwin, \ + int *xPtr, int *yPtr, int *widthPtr, int *heightPtr) +} + +declare 114 generic { + int Tk_Grab (Tcl_Interp *interp, Tk_Window tkwin, int grabGlobal) +} + +declare 115 generic { + void Tk_HandleEvent (XEvent *eventPtr) +} + +declare 116 generic { + Tk_Window Tk_IdToWindow (Display *display, Window window) +} + +declare 117 generic { + void Tk_ImageChanged (Tk_ImageMaster master, int x, int y, \ + int width, int height, int imageWidth, int imageHeight) +} + +declare 118 generic { + int Tk_Init (Tcl_Interp *interp) +} + +declare 119 generic { + Atom Tk_InternAtom (Tk_Window tkwin, char *name) +} + +declare 120 generic { + int Tk_IntersectTextLayout (Tk_TextLayout layout, int x, int y, \ + int width, int height) +} + +declare 121 generic { + void Tk_MaintainGeometry (Tk_Window slave, \ + Tk_Window master, int x, int y, int width, int height) +} + +declare 122 generic { + Tk_Window Tk_MainWindow (Tcl_Interp *interp) +} + +declare 123 generic { + void Tk_MakeWindowExist (Tk_Window tkwin) +} + +declare 124 generic { + void Tk_ManageGeometry (Tk_Window tkwin, \ + Tk_GeomMgr *mgrPtr, ClientData clientData) +} + +declare 125 generic { + void Tk_MapWindow (Tk_Window tkwin) +} + +declare 126 generic { + int Tk_MeasureChars (Tk_Font tkfont, \ + CONST char *source, int numBytes, int maxPixels, \ + int flags, int *lengthPtr) +} + +declare 127 generic { + void Tk_MoveResizeWindow (Tk_Window tkwin, \ + int x, int y, int width, int height) +} + +declare 128 generic { + void Tk_MoveWindow (Tk_Window tkwin, int x, int y) +} + +declare 129 generic { + void Tk_MoveToplevelWindow (Tk_Window tkwin, int x, int y) +} + +declare 130 generic { + char * Tk_NameOf3DBorder (Tk_3DBorder border) +} + +declare 131 generic { + char * Tk_NameOfAnchor (Tk_Anchor anchor) +} + +declare 132 generic { + char * Tk_NameOfBitmap (Display *display, Pixmap bitmap) +} + +declare 133 generic { + char * Tk_NameOfCapStyle (int cap) +} + +declare 134 generic { + char * Tk_NameOfColor (XColor *colorPtr) +} + +declare 135 generic { + char * Tk_NameOfCursor (Display *display, Tk_Cursor cursor) +} + +declare 136 generic { + char * Tk_NameOfFont (Tk_Font font) +} + +declare 137 generic { + char * Tk_NameOfImage (Tk_ImageMaster imageMaster) +} + +declare 138 generic { + char * Tk_NameOfJoinStyle (int join) +} + +declare 139 generic { + char * Tk_NameOfJustify (Tk_Justify justify) +} + +declare 140 generic { + char * Tk_NameOfRelief (int relief) +} + +declare 141 generic { + Tk_Window Tk_NameToWindow (Tcl_Interp *interp, \ + char *pathName, Tk_Window tkwin) +} + +declare 142 generic { + void Tk_OwnSelection (Tk_Window tkwin, \ + Atom selection, Tk_LostSelProc *proc, \ + ClientData clientData) +} + +declare 143 generic { + int Tk_ParseArgv (Tcl_Interp *interp, \ + Tk_Window tkwin, int *argcPtr, char **argv, \ + Tk_ArgvInfo *argTable, int flags) +} + +declare 144 generic { + void Tk_PhotoPutBlock (Tk_PhotoHandle handle, \ + Tk_PhotoImageBlock *blockPtr, int x, int y, \ + int width, int height) +} + +declare 145 generic { + void Tk_PhotoPutZoomedBlock (Tk_PhotoHandle handle, \ + Tk_PhotoImageBlock *blockPtr, int x, int y, \ + int width, int height, int zoomX, int zoomY, \ + int subsampleX, int subsampleY) +} + +declare 146 generic { + int Tk_PhotoGetImage (Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr) +} + +declare 147 generic { + void Tk_PhotoBlank (Tk_PhotoHandle handle) +} + +declare 148 generic { + void Tk_PhotoExpand (Tk_PhotoHandle handle, int width, int height ) +} + +declare 149 generic { + void Tk_PhotoGetSize (Tk_PhotoHandle handle, int *widthPtr, int *heightPtr) +} + +declare 150 generic { + void Tk_PhotoSetSize (Tk_PhotoHandle handle, int width, int height) +} + +declare 151 generic { + int Tk_PointToChar (Tk_TextLayout layout, int x, int y) +} + +declare 152 generic { + int Tk_PostscriptFontName (Tk_Font tkfont, Tcl_DString *dsPtr) +} + +declare 153 generic { + void Tk_PreserveColormap (Display *display, Colormap colormap) +} + +declare 154 generic { + void Tk_QueueWindowEvent (XEvent *eventPtr, Tcl_QueuePosition position) +} + +declare 155 generic { + void Tk_RedrawImage (Tk_Image image, int imageX, \ + int imageY, int width, int height, \ + Drawable drawable, int drawableX, int drawableY) +} + +declare 156 generic { + void Tk_ResizeWindow (Tk_Window tkwin, int width, int height) +} + +declare 157 generic { + int Tk_RestackWindow (Tk_Window tkwin, int aboveBelow, Tk_Window other) +} + +declare 158 generic { + Tk_RestrictProc *Tk_RestrictEvents (Tk_RestrictProc *proc, \ + ClientData arg, ClientData *prevArgPtr) +} + +declare 159 generic { + int Tk_SafeInit (Tcl_Interp *interp) +} + +declare 160 generic { + char * Tk_SetAppName (Tk_Window tkwin, char *name) +} + +declare 161 generic { + void Tk_SetBackgroundFromBorder (Tk_Window tkwin, Tk_3DBorder border) +} + +declare 162 generic { + void Tk_SetClass (Tk_Window tkwin, char *className) +} + +declare 163 generic { + void Tk_SetGrid (Tk_Window tkwin, int reqWidth, int reqHeight, \ + int gridWidth, int gridHeight) +} + +declare 164 generic { + void Tk_SetInternalBorder (Tk_Window tkwin, int width) +} + +declare 165 generic { + void Tk_SetWindowBackground (Tk_Window tkwin, unsigned long pixel) +} + +declare 166 generic { + void Tk_SetWindowBackgroundPixmap (Tk_Window tkwin, Pixmap pixmap) +} + +declare 167 generic { + void Tk_SetWindowBorder (Tk_Window tkwin, unsigned long pixel) +} + +declare 168 generic { + void Tk_SetWindowBorderWidth (Tk_Window tkwin, int width) +} + +declare 169 generic { + void Tk_SetWindowBorderPixmap (Tk_Window tkwin, Pixmap pixmap) +} + +declare 170 generic { + void Tk_SetWindowColormap (Tk_Window tkwin, Colormap colormap) +} + +declare 171 generic { + int Tk_SetWindowVisual (Tk_Window tkwin, Visual *visual, int depth,\ + Colormap colormap) +} + +declare 172 generic { + void Tk_SizeOfBitmap (Display *display, Pixmap bitmap, int *widthPtr, \ + int *heightPtr) +} + +declare 173 generic { + void Tk_SizeOfImage (Tk_Image image, int *widthPtr, int *heightPtr) +} + +declare 174 generic { + int Tk_StrictMotif (Tk_Window tkwin) +} + +declare 175 generic { + void Tk_TextLayoutToPostscript (Tcl_Interp *interp, Tk_TextLayout layout) +} + +declare 176 generic { + int Tk_TextWidth (Tk_Font font, CONST char *str, int numBytes) +} + +declare 177 generic { + void Tk_UndefineCursor (Tk_Window window) +} + +declare 178 generic { + void Tk_UnderlineChars (Display *display, \ + Drawable drawable, GC gc, Tk_Font tkfont, \ + CONST char *source, int x, int y, int firstByte, \ + int lastByte) +} + +declare 179 generic { + void Tk_UnderlineTextLayout (Display *display, Drawable drawable, GC gc, \ + Tk_TextLayout layout, int x, int y, \ + int underline) +} + +declare 180 generic { + void Tk_Ungrab (Tk_Window tkwin) +} + +declare 181 generic { + void Tk_UnmaintainGeometry (Tk_Window slave, Tk_Window master) +} + +declare 182 generic { + void Tk_UnmapWindow (Tk_Window tkwin) +} + +declare 183 generic { + void Tk_UnsetGrid (Tk_Window tkwin) +} + +declare 184 generic { + void Tk_UpdatePointer (Tk_Window tkwin, int x, int y, int state) +} + +# new functions for 8.1 + +declare 185 generic { + Pixmap Tk_AllocBitmapFromObj (Tcl_Interp *interp, Tk_Window tkwin, \ + Tcl_Obj *objPtr) +} + +declare 186 generic { + Tk_3DBorder Tk_Alloc3DBorderFromObj (Tcl_Interp *interp, Tk_Window tkwin, \ + Tcl_Obj *objPtr) +} + +declare 187 generic { + XColor * Tk_AllocColorFromObj (Tcl_Interp *interp, Tk_Window tkwin, \ + Tcl_Obj *objPtr) +} + +declare 188 generic { + Tk_Cursor Tk_AllocCursorFromObj (Tcl_Interp *interp, Tk_Window tkwin, \ + Tcl_Obj *objPtr) +} + +declare 189 generic { + Tk_Font Tk_AllocFontFromObj (Tcl_Interp *interp, Tk_Window tkwin, \ + Tcl_Obj *objPtr) + +} + +declare 190 generic { + Tk_OptionTable Tk_CreateOptionTable (Tcl_Interp *interp, \ + CONST Tk_OptionSpec *templatePtr) +} + +declare 191 generic { + void Tk_DeleteOptionTable (Tk_OptionTable optionTable) +} + +declare 192 generic { + void Tk_Free3DBorderFromObj (Tk_Window tkwin, Tcl_Obj *objPtr) +} + +declare 193 generic { + void Tk_FreeBitmapFromObj (Tk_Window tkwin, Tcl_Obj *objPtr) +} + +declare 194 generic { + void Tk_FreeColorFromObj (Tk_Window tkwin, Tcl_Obj *objPtr) +} + +declare 195 generic { + void Tk_FreeConfigOptions (char *recordPtr, Tk_OptionTable optionToken, \ + Tk_Window tkwin) + +} + +declare 196 generic { + void Tk_FreeSavedOptions (Tk_SavedOptions *savePtr) +} + +declare 197 generic { + void Tk_FreeCursorFromObj (Tk_Window tkwin, Tcl_Obj *objPtr) +} + +declare 198 generic { + void Tk_FreeFontFromObj (Tk_Window tkwin, Tcl_Obj *objPtr) +} + +declare 199 generic { + Tk_3DBorder Tk_Get3DBorderFromObj (Tk_Window tkwin, Tcl_Obj *objPtr) +} + +declare 200 generic { + int Tk_GetAnchorFromObj (Tcl_Interp *interp, Tcl_Obj *objPtr, \ + Tk_Anchor *anchorPtr) +} + +declare 201 generic { + Pixmap Tk_GetBitmapFromObj (Tk_Window tkwin, Tcl_Obj *objPtr) +} + +declare 202 generic { + XColor * Tk_GetColorFromObj (Tk_Window tkwin, Tcl_Obj *objPtr) +} + +declare 203 generic { + Tk_Cursor Tk_GetCursorFromObj (Tk_Window tkwin, Tcl_Obj *objPtr) +} + +declare 204 generic { + Tcl_Obj * Tk_GetOptionInfo (Tcl_Interp *interp, \ + char *recordPtr, Tk_OptionTable optionTable, \ + Tcl_Obj *namePtr, Tk_Window tkwin) +} + +declare 205 generic { + Tcl_Obj * Tk_GetOptionValue (Tcl_Interp *interp, char *recordPtr, \ + Tk_OptionTable optionTable, Tcl_Obj *namePtr, Tk_Window tkwin) +} + +declare 206 generic { + int Tk_GetJustifyFromObj (Tcl_Interp *interp, \ + Tcl_Obj *objPtr, Tk_Justify *justifyPtr) +} + +declare 207 generic { + int Tk_GetMMFromObj (Tcl_Interp *interp, \ + Tk_Window tkwin, Tcl_Obj *objPtr, double *doublePtr) +} + +declare 208 generic { + int Tk_GetPixelsFromObj (Tcl_Interp *interp, \ + Tk_Window tkwin, Tcl_Obj *objPtr, int *intPtr) +} + +declare 209 generic { + int Tk_GetReliefFromObj (Tcl_Interp *interp, \ + Tcl_Obj *objPtr, int *resultPtr) +} + +declare 210 generic { + int Tk_GetScrollInfoObj (Tcl_Interp *interp, \ + int objc, Tcl_Obj *CONST objv[], double *dblPtr, int *intPtr) +} + +declare 211 generic { + int Tk_InitOptions ( + Tcl_Interp *interp, char *recordPtr, \ + Tk_OptionTable optionToken, Tk_Window tkwin) +} + +declare 212 generic { + void Tk_MainEx (int argc, char **argv, Tcl_AppInitProc *appInitProc, \ + Tcl_Interp *interp) +} + +declare 213 generic { + void Tk_RestoreSavedOptions (Tk_SavedOptions *savePtr) +} + +declare 214 generic { + int Tk_SetOptions (Tcl_Interp *interp, char *recordPtr, \ + Tk_OptionTable optionTable, int objc, \ + Tcl_Obj *CONST objv[], Tk_Window tkwin, \ + Tk_SavedOptions *savePtr, int *maskPtr) +} + +declare 215 generic { + void Tk_InitConsoleChannels (Tcl_Interp *interp) +} + +declare 216 generic { + int Tk_CreateConsoleWindow (Tcl_Interp *interp) +} + +declare 217 generic { + void Tk_CreateSmoothMethod (Tcl_Interp *interp, Tk_SmoothMethod *method) +} + +#declare 218 generic { +# void Tk_CreateCanvasVisitor (Tcl_Interp *interp, VOID *typePtr) +#} + +#declare 219 generic { +# VOID *Tk_GetCanvasVisitor (Tcl_Interp *interp, CONST char *name) +#} + +declare 220 generic { + int Tk_GetDash (Tcl_Interp *interp, CONST char *value, Tk_Dash *dash) +} +declare 221 generic { + void Tk_CreateOutline (Tk_Outline *outline) +} +declare 222 generic { + void Tk_DeleteOutline (Display *display, Tk_Outline *outline) +} +declare 223 generic { + int Tk_ConfigOutlineGC (XGCValues *gcValues, Tk_Canvas canvas, \ + Tk_Item *item, Tk_Outline *outline) +} +declare 224 generic { + int Tk_ChangeOutlineGC (Tk_Canvas canvas, Tk_Item *item, \ + Tk_Outline *outline) +} +declare 225 generic { + int Tk_ResetOutlineGC (Tk_Canvas canvas, Tk_Item *item, \ + Tk_Outline *outline) +} +declare 226 generic { + int Tk_CanvasPsOutline (Tk_Canvas canvas, Tk_Item *item, \ + Tk_Outline *outline) +} +declare 227 generic { + void Tk_SetTSOrigin (Tk_Window tkwin, GC gc, int x, int y) +} +declare 228 generic { + int Tk_CanvasGetCoordFromObj (Tcl_Interp *interp, Tk_Canvas canvas, \ + Tcl_Obj *obj, double *doublePtr) +} +declare 229 generic { + void Tk_CanvasSetOffset (Tk_Canvas canvas, GC gc, Tk_TSOffset *offset) +} +declare 230 generic { + void Tk_DitherPhoto (Tk_PhotoHandle handle, int x, int y, int width, \ + int height) +} +declare 231 generic { + int Tk_PostscriptBitmap (Tcl_Interp *interp, Tk_Window tkwin, \ + Tk_PostscriptInfo psInfo, Pixmap bitmap, int startX, \ + int startY, int width, int height) +} +declare 232 generic { + int Tk_PostscriptColor (Tcl_Interp *interp, Tk_PostscriptInfo psInfo, \ + XColor *colorPtr) +} +declare 233 generic { + int Tk_PostscriptFont (Tcl_Interp *interp, Tk_PostscriptInfo psInfo, \ + Tk_Font font) +} +declare 234 generic { + int Tk_PostscriptImage (Tk_Image image, Tcl_Interp *interp, \ + Tk_Window tkwin, Tk_PostscriptInfo psinfo, int x, int y, \ + int width, int height, int prepass) +} +declare 235 generic { + void Tk_PostscriptPath (Tcl_Interp *interp, Tk_PostscriptInfo psInfo, \ + double *coordPtr, int numPoints) +} +declare 236 generic { + int Tk_PostscriptStipple (Tcl_Interp *interp, Tk_Window tkwin, \ + Tk_PostscriptInfo psInfo, Pixmap bitmap) +} +declare 237 generic { + double Tk_PostscriptY (double y, Tk_PostscriptInfo psInfo) +} +declare 238 generic { + int Tk_PostscriptPhoto (Tcl_Interp *interp, \ + Tk_PhotoImageBlock *blockPtr, Tk_PostscriptInfo psInfo, \ + int width, int height) +} + +# Define the platform specific public Tk interface. These functions are +# only available on the designated platform. + +interface tkPlat + +# Unix specific functions +# (none) + +# Windows specific functions + +declare 0 win { + Window Tk_AttachHWND (Tk_Window tkwin, HWND hwnd) +} + +declare 1 win { + HINSTANCE Tk_GetHINSTANCE (void) +} + +declare 2 win { + HWND Tk_GetHWND (Window window) +} + +declare 3 win { + Tk_Window Tk_HWNDToWindow (HWND hwnd) +} + +declare 4 win { + void Tk_PointerEvent (HWND hwnd, int x, int y) +} + +declare 5 win { + int Tk_TranslateWinEvent (HWND hwnd, \ + UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) +} + +# Mac specific functions + +declare 0 mac { + void Tk_MacSetEmbedHandler ( \ + Tk_MacEmbedRegisterWinProc *registerWinProcPtr, \ + Tk_MacEmbedGetGrafPortProc *getPortProcPtr, \ + Tk_MacEmbedMakeContainerExistProc *containerExistProcPtr, \ + Tk_MacEmbedGetClipProc *getClipProc, \ + Tk_MacEmbedGetOffsetInParentProc *getOffsetProc) +} + +declare 1 mac { + void Tk_MacTurnOffMenus (void) +} + +declare 2 mac { + void Tk_MacTkOwnsCursor (int tkOwnsIt) +} + +declare 3 mac { + void TkMacInitMenus (Tcl_Interp *interp) +} + +declare 4 mac { + void TkMacInitAppleEvents (Tcl_Interp *interp) +} + +declare 5 mac { + int TkMacConvertEvent (EventRecord *eventPtr) +} + +declare 6 mac { + int TkMacConvertTkEvent (EventRecord *eventPtr, Window window) +} + +declare 7 mac { + void TkGenWMConfigureEvent (Tk_Window tkwin, \ + int x, int y, int width, int height, int flags) +} + +declare 8 mac { + void TkMacInvalClipRgns (TkWindow *winPtr) +} + +declare 9 mac { + int TkMacHaveAppearance (void) +} + +declare 10 mac { + GWorldPtr TkMacGetDrawablePort (Drawable drawable) +} + diff --git a/tk/generic/tk.h b/tk/generic/tk.h index 5d1a05603dc..c4eb7145d56 100644 --- a/tk/generic/tk.h +++ b/tk/generic/tk.h @@ -6,8 +6,8 @@ * * Copyright (c) 1989-1994 The Regents of the University of California. * Copyright (c) 1994 The Australian National University. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * Copyright (c) 1998 by Scriptics Corporation. + * Copyright (c) 1994-1998 Sun Microsystems, Inc. + * Copyright (c) 1998-2000 Ajuba Solutions. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -19,41 +19,39 @@ #define _TK /* + * For C++ compilers, use extern "C" + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* * When version numbers change here, you must also go into the following files * and update the version numbers: * - * README - * unix/configure.in - * win/makefile.bc (Not for patch release updates) - * win/makefile.vc (Not for patch release updates) - * win/README - * library/tk.tcl - * - * The release level should be 0 for alpha, 1 for beta, and 2 for - * final/patch. The release serial value is the number that follows the - * "a", "b", or "p" in the patch level; for example, if the patch level - * is 4.3b2, TK_RELEASE_SERIAL is 2. It restarts at 1 whenever the - * release level is changed, except for the final release, which should - * be 0. + * library/tk.tcl (only if Major.minor changes, not patchlevel) + * unix/configure.in (2 LOC Major, 2 LOC minor, 1 LOC patch) + * win/configure.in (as above) + * win/makefile.vc (not patchlevel) + * README (sections 0 and 1) + * mac/README (not patchlevel) + * win/README (not patchlevel) + * unix/README (not patchlevel) + * unix/tk.spec (3 LOC Major/Minor, 2 LOC patch) + * win/aclocal.m4 (not patchlevel) * * You may also need to update some of these files when the numbers change * for the version of Tcl that this release of Tk is compiled against. */ #define TK_MAJOR_VERSION 8 -#define TK_MINOR_VERSION 0 -#define TK_RELEASE_LEVEL 2 -#define TK_RELEASE_SERIAL 4 - -#define TK_VERSION "8.0" -#define TK_PATCH_LEVEL "8.0.4" +#define TK_MINOR_VERSION 3 +#define TK_RELEASE_LEVEL TCL_FINAL_RELEASE +#define TK_RELEASE_SERIAL 2 -/* - * A special definition used to allow this header file to be included - * in resource files. - */ - -#ifndef RESOURCE_INCLUDED +#define TK_VERSION "8.3" +#define TK_PATCH_LEVEL "8.3.2" /* * The following definitions set up the proper options for Macintosh @@ -69,6 +67,14 @@ #ifndef _TCL # include <tcl.h> #endif + +/* + * A special definition used to allow this header file to be included + * in resource files. + */ + +#ifndef RESOURCE_INCLUDED + #ifndef _XLIB_H # ifdef MAC_TCL # include <Xlib.h> @@ -105,6 +111,8 @@ typedef struct Tk_ErrorHandler_ *Tk_ErrorHandler; typedef struct Tk_Font_ *Tk_Font; typedef struct Tk_Image__ *Tk_Image; typedef struct Tk_ImageMaster_ *Tk_ImageMaster; +typedef struct Tk_OptionTable_ *Tk_OptionTable; +typedef struct Tk_PostscriptInfo_ *Tk_PostscriptInfo; typedef struct Tk_TextLayout_ *Tk_TextLayout; typedef struct Tk_Window_ *Tk_Window; typedef struct Tk_3DBorder_ *Tk_3DBorder; @@ -116,56 +124,167 @@ typedef struct Tk_3DBorder_ *Tk_3DBorder; typedef char *Tk_Uid; /* - * Structure used to specify how to handle argv options. + * The enum below defines the valid types for Tk configuration options + * as implemented by Tk_InitOptions, Tk_SetOptions, etc. */ -typedef struct { - char *key; /* The key string that flags the option in the - * argv array. */ - int type; /* Indicates option type; see below. */ - char *src; /* Value to be used in setting dst; usage - * depends on type. */ - char *dst; /* Address of value to be modified; usage - * depends on type. */ - char *help; /* Documentation message describing this option. */ -} Tk_ArgvInfo; +typedef enum { + TK_OPTION_BOOLEAN, + TK_OPTION_INT, + TK_OPTION_DOUBLE, + TK_OPTION_STRING, + TK_OPTION_STRING_TABLE, + TK_OPTION_COLOR, + TK_OPTION_FONT, + TK_OPTION_BITMAP, + TK_OPTION_BORDER, + TK_OPTION_RELIEF, + TK_OPTION_CURSOR, + TK_OPTION_JUSTIFY, + TK_OPTION_ANCHOR, + TK_OPTION_SYNONYM, + TK_OPTION_PIXELS, + TK_OPTION_WINDOW, +/* CYGNUS LOCAL: Support -version argument. */ + TK_OPTION_VERSION, + TK_OPTION_END +} Tk_OptionType; /* - * Legal values for the type field of a Tk_ArgvInfo: see the user - * documentation for details. + * Structures of the following type are used by widgets to specify + * their configuration options. Typically each widget has a static + * array of these structures, where each element of the array describes + * a single configuration option. The array is passed to + * Tk_CreateOptionTable. */ -#define TK_ARGV_CONSTANT 15 -#define TK_ARGV_INT 16 -#define TK_ARGV_STRING 17 -#define TK_ARGV_UID 18 -#define TK_ARGV_REST 19 -#define TK_ARGV_FLOAT 20 -#define TK_ARGV_FUNC 21 -#define TK_ARGV_GENFUNC 22 -#define TK_ARGV_HELP 23 -#define TK_ARGV_CONST_OPTION 24 -#define TK_ARGV_OPTION_VALUE 25 -#define TK_ARGV_OPTION_NAME_VALUE 26 -/* CYGNUS LOCAL: Support -version argument. */ -#define TK_ARGV_VERSION 27 -#define TK_ARGV_END 28 +typedef struct Tk_OptionSpec { + Tk_OptionType type; /* Type of option, such as TK_OPTION_COLOR; + * see definitions above. Last option in + * table must have type TK_OPTION_END. */ + char *optionName; /* Name used to specify option in Tcl + * commands. */ + char *dbName; /* Name for option in option database. */ + char *dbClass; /* Class for option in database. */ + char *defValue; /* Default value for option if not specified + * in command line, the option database, + * or the system. */ + int objOffset; /* Where in record to store a Tcl_Obj * that + * holds the value of this option, specified + * as an offset in bytes from the start of + * the record. Use the Tk_Offset macro to + * generate values for this. -1 means don't + * store the Tcl_Obj in the record. */ + int internalOffset; /* Where in record to store the internal + * representation of the value of this option, + * such as an int or XColor *. This field + * is specified as an offset in bytes + * from the start of the record. Use the + * Tk_Offset macro to generate values for it. + * -1 means don't store the internal + * representation in the record. */ + int flags; /* Any combination of the values defined + * below. */ + ClientData clientData; /* An alternate place to put option-specific + * data. Used for the monochrome default value + * for colors, etc. */ + int typeMask; /* An arbitrary bit mask defined by the + * class manager; typically bits correspond + * to certain kinds of options such as all + * those that require a redisplay when they + * change. Tk_SetOptions returns the bit-wise + * OR of the typeMasks of all options that + * were changed. */ +} Tk_OptionSpec; /* - * Flag bits for passing to Tk_ParseArgv: + * Flag values for Tk_OptionSpec structures. These flags are shared by + * Tk_ConfigSpec structures, so be sure to coordinate any changes + * carefully. */ -#define TK_ARGV_NO_DEFAULTS 0x1 -#define TK_ARGV_NO_LEFTOVERS 0x2 -#define TK_ARGV_NO_ABBREV 0x4 -#define TK_ARGV_DONT_SKIP_FIRST_ARG 0x8 +#define TK_OPTION_NULL_OK 1 +#define TK_OPTION_DONT_SET_DEFAULT 8 + +/* + * Macro to use to fill in "offset" fields of the Tk_OptionSpec. + * struct. Computes number of bytes from beginning of structure + * to a given field. + */ + +#ifdef offsetof +#define Tk_Offset(type, field) ((int) offsetof(type, field)) +#else +#define Tk_Offset(type, field) ((int) ((char *) &((type *) 0)->field)) +#endif + +/* + * The following two structures are used for error handling. When + * configuration options are being modified, the old values are + * saved in a Tk_SavedOptions structure. If an error occurs, then the + * contents of the structure can be used to restore all of the old + * values. The contents of this structure are for the private use + * Tk. No-one outside Tk should ever read or write any of the fields + * of these structures. + */ + +typedef struct Tk_SavedOption { + struct TkOption *optionPtr; /* Points to information that describes + * the option. */ + Tcl_Obj *valuePtr; /* The old value of the option, in + * the form of a Tcl object; may be + * NULL if the value wasn't saved as + * an object. */ + double internalForm; /* The old value of the option, in + * some internal representation such + * as an int or (XColor *). Valid + * only if optionPtr->specPtr->objOffset + * is < 0. The space must be large + * enough to accommodate a double, a + * long, or a pointer; right now it + * looks like a double is big + * enough. Also, using a double + * guarantees that the field is + * properly aligned for storing large + * values. */ +} Tk_SavedOption; + +#ifdef TCL_MEM_DEBUG +# define TK_NUM_SAVED_OPTIONS 2 +#else +# define TK_NUM_SAVED_OPTIONS 20 +#endif + +typedef struct Tk_SavedOptions { + char *recordPtr; /* The data structure in which to + * restore configuration options. */ + Tk_Window tkwin; /* Window associated with recordPtr; + * needed to restore certain options. */ + int numItems; /* The number of valid items in + * items field. */ + Tk_SavedOption items[TK_NUM_SAVED_OPTIONS]; + /* Items used to hold old values. */ + struct Tk_SavedOptions *nextPtr; /* Points to next structure in list; + * needed if too many options changed + * to hold all the old values in a + * single structure. NULL means no + * more structures. */ +} Tk_SavedOptions; /* * Structure used to describe application-specific configuration * options: indicates procedures to call to parse an option and - * to return a text string describing an option. + * to return a text string describing an option. THESE ARE + * DEPRECATED; PLEASE USE THE NEW STRUCTURES LISTED ABOVE. + */ + +/* + * This is a temporary flag used while tkObjConfig and new widgets + * are in development. */ +#ifndef __NO_OLD_CONFIG + typedef int (Tk_OptionParseProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, char *value, char *widgRec, int offset)); @@ -219,60 +338,82 @@ typedef struct Tk_ConfigSpec { * documentation for details. */ -#define TK_CONFIG_BOOLEAN 1 -#define TK_CONFIG_INT 2 -#define TK_CONFIG_DOUBLE 3 -#define TK_CONFIG_STRING 4 -#define TK_CONFIG_UID 5 -#define TK_CONFIG_COLOR 6 -#define TK_CONFIG_FONT 7 -#define TK_CONFIG_BITMAP 8 -#define TK_CONFIG_BORDER 9 -#define TK_CONFIG_RELIEF 10 -#define TK_CONFIG_CURSOR 11 -#define TK_CONFIG_ACTIVE_CURSOR 12 -#define TK_CONFIG_JUSTIFY 13 -#define TK_CONFIG_ANCHOR 14 -#define TK_CONFIG_SYNONYM 15 -#define TK_CONFIG_CAP_STYLE 16 -#define TK_CONFIG_JOIN_STYLE 17 -#define TK_CONFIG_PIXELS 18 -#define TK_CONFIG_MM 19 -#define TK_CONFIG_WINDOW 20 -#define TK_CONFIG_CUSTOM 21 -#define TK_CONFIG_END 22 - -/* - * Macro to use to fill in "offset" fields of Tk_ConfigInfos. - * Computes number of bytes from beginning of structure to a - * given field. - */ - -#ifdef offsetof -#define Tk_Offset(type, field) ((int) offsetof(type, field)) -#else -#define Tk_Offset(type, field) ((int) ((char *) &((type *) 0)->field)) -#endif +typedef enum { + TK_CONFIG_BOOLEAN, TK_CONFIG_INT, TK_CONFIG_DOUBLE, TK_CONFIG_STRING, + TK_CONFIG_UID, TK_CONFIG_COLOR, TK_CONFIG_FONT, TK_CONFIG_BITMAP, + TK_CONFIG_BORDER, TK_CONFIG_RELIEF, TK_CONFIG_CURSOR, + TK_CONFIG_ACTIVE_CURSOR, TK_CONFIG_JUSTIFY, TK_CONFIG_ANCHOR, + TK_CONFIG_SYNONYM, TK_CONFIG_CAP_STYLE, TK_CONFIG_JOIN_STYLE, + TK_CONFIG_PIXELS, TK_CONFIG_MM, TK_CONFIG_WINDOW, TK_CONFIG_CUSTOM, + TK_CONFIG_END +} Tk_ConfigTypes; /* * Possible values for flags argument to Tk_ConfigureWidget: */ #define TK_CONFIG_ARGV_ONLY 1 +#define TK_CONFIG_OBJS 0x80 /* - * Possible flag values for Tk_ConfigInfo structures. Any bits at + * Possible flag values for Tk_ConfigSpec structures. Any bits at * or above TK_CONFIG_USER_BIT may be used by clients for selecting * certain entries. Before changing any values here, coordinate with - * tkConfig.c (internal-use-only flags are defined there). + * tkOldConfig.c (internal-use-only flags are defined there). */ -#define TK_CONFIG_COLOR_ONLY 1 -#define TK_CONFIG_MONO_ONLY 2 -#define TK_CONFIG_NULL_OK 4 +#define TK_CONFIG_NULL_OK 1 +#define TK_CONFIG_COLOR_ONLY 2 +#define TK_CONFIG_MONO_ONLY 4 #define TK_CONFIG_DONT_SET_DEFAULT 8 #define TK_CONFIG_OPTION_SPECIFIED 0x10 #define TK_CONFIG_USER_BIT 0x100 +#endif /* __NO_OLD_CONFIG */ + +/* + * Structure used to specify how to handle argv options. + */ + +typedef struct { + char *key; /* The key string that flags the option in the + * argv array. */ + int type; /* Indicates option type; see below. */ + char *src; /* Value to be used in setting dst; usage + * depends on type. */ + char *dst; /* Address of value to be modified; usage + * depends on type. */ + char *help; /* Documentation message describing this option. */ +} Tk_ArgvInfo; + +/* + * Legal values for the type field of a Tk_ArgvInfo: see the user + * documentation for details. + */ + +#define TK_ARGV_CONSTANT 15 +#define TK_ARGV_INT 16 +#define TK_ARGV_STRING 17 +#define TK_ARGV_UID 18 +#define TK_ARGV_REST 19 +#define TK_ARGV_FLOAT 20 +#define TK_ARGV_FUNC 21 +#define TK_ARGV_GENFUNC 22 +#define TK_ARGV_HELP 23 +#define TK_ARGV_CONST_OPTION 24 +#define TK_ARGV_OPTION_VALUE 25 +#define TK_ARGV_OPTION_NAME_VALUE 26 +/* CYGNUS LOCAL: Support -version argument. */ +#define TK_ARGV_VERSION 27 +#define TK_ARGV_END 28 + +/* + * Flag bits for passing to Tk_ParseArgv: + */ + +#define TK_ARGV_NO_DEFAULTS 0x1 +#define TK_ARGV_NO_LEFTOVERS 0x2 +#define TK_ARGV_NO_ABBREV 0x4 +#define TK_ARGV_DONT_SKIP_FIRST_ARG 0x8 /* * Enumerated type for describing actions to be taken in response @@ -297,12 +438,12 @@ typedef enum { * Relief values returned by Tk_GetRelief: */ -#define TK_RELIEF_RAISED 1 -#define TK_RELIEF_FLAT 2 -#define TK_RELIEF_SUNKEN 4 -#define TK_RELIEF_GROOVE 8 -#define TK_RELIEF_RIDGE 16 -#define TK_RELIEF_SOLID 32 +#define TK_RELIEF_FLAT 0 +#define TK_RELIEF_GROOVE 1 +#define TK_RELIEF_RAISED 2 +#define TK_RELIEF_RIDGE 3 +#define TK_RELIEF_SOLID 4 +#define TK_RELIEF_SUNKEN 5 /* * "Which" argument values for Tk_3DBorderGC: @@ -638,6 +779,21 @@ typedef struct Tk_FakeWin { *-------------------------------------------------------------- */ +typedef enum { + TK_STATE_NULL = -1, TK_STATE_ACTIVE, TK_STATE_DISABLED, + TK_STATE_NORMAL, TK_STATE_HIDDEN +} Tk_State; + +typedef struct Tk_SmoothMethod { + char *name; + int (*coordProc) _ANSI_ARGS_((Tk_Canvas canvas, + double *pointPtr, int numPoints, int numSteps, + XPoint xPoints[], double dblPoints[])); + void (*postscriptProc) _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, double *coordPtr, + int numPoints, int numSteps)); +} Tk_SmoothMethod; + /* * For each item in a canvas widget there exists one record with * the following structure. Each actual item is represented by @@ -677,9 +833,9 @@ typedef struct Tk_Item { * items in this canvas. Later items * in list are drawn just below earlier * ones. */ - int reserved1; /* This padding is for compatibility */ - char *reserved2; /* with Jan Nijtmans dash patch */ - int reserved3; + Tk_State state; /* state of item */ + char *reserved1; /* reserved for future use */ + int redraw_flags; /* some flags used in the canvas */ /* *------------------------------------------------------------------ @@ -692,11 +848,25 @@ typedef struct Tk_Item { } Tk_Item; /* + * Flag bits for canvases (redraw_flags): + * + * TK_ITEM_STATE_DEPENDANT - 1 means that object needs to be + * redrawn if the canvas state changes. + * TK_ITEM_DONT_REDRAW - 1 means that the object redraw is already + * been prepared, so the general canvas code + * doesn't need to do that any more. + */ + +#define TK_ITEM_STATE_DEPENDANT 1 +#define TK_ITEM_DONT_REDRAW 2 + +/* * Records of the following type are used to describe a type of * item (e.g. lines, circles, etc.) that can form part of a * canvas widget. */ +#ifdef USE_OLD_CANVAS typedef int Tk_ItemCreateProc _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, char **argv)); @@ -706,6 +876,17 @@ typedef int Tk_ItemConfigureProc _ANSI_ARGS_((Tcl_Interp *interp, typedef int Tk_ItemCoordProc _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, char **argv)); +#else +typedef int Tk_ItemCreateProc _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int argc, + Tcl_Obj *CONST objv[])); +typedef int Tk_ItemConfigureProc _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int argc, + Tcl_Obj *CONST objv[], int flags)); +typedef int Tk_ItemCoordProc _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int argc, + Tcl_Obj *CONST argv[])); +#endif typedef void Tk_ItemDeleteProc _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); typedef void Tk_ItemDisplayProc _ANSI_ARGS_((Tk_Canvas canvas, @@ -735,6 +916,8 @@ typedef void Tk_ItemInsertProc _ANSI_ARGS_((Tk_Canvas canvas, typedef void Tk_ItemDCharsProc _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, int first, int last)); +#ifndef __NO_OLD_CONFIG + typedef struct Tk_ItemType { char *name; /* The name of this type of item, such * as "line". */ @@ -755,7 +938,7 @@ typedef struct Tk_ItemType { * this type. */ int alwaysRedraw; /* Non-zero means displayProc should * be called even when the item has - * been moved off-screen. */ + * been moved off-screen. */ Tk_ItemPointProc *pointProc; /* Computes distance from item to * a given point. */ Tk_ItemAreaProc *areaProc; /* Computes whether item is inside, @@ -788,6 +971,8 @@ typedef struct Tk_ItemType { char *reserved4; } Tk_ItemType; +#endif + /* * The following structure provides information about the selection and * the insertion cursor. It is needed by only a few items, such as @@ -806,16 +991,17 @@ typedef struct Tk_CanvasTextInfo { Tk_Item *selItemPtr; /* Pointer to selected item. NULL means * selection isn't in this canvas. * Writable by items. */ - int selectFirst; /* Index of first selected character. - * Writable by items. */ - int selectLast; /* Index of last selected character. - * Writable by items. */ + int selectFirst; /* Character index of first selected + * character. Writable by items. */ + int selectLast; /* Character index of last selected + * character. Writable by items. */ Tk_Item *anchorItemPtr; /* Item corresponding to "selectAnchor": * not necessarily selItemPtr. Read-only * to items. */ - int selectAnchor; /* Fixed end of selection (i.e. "select to" - * operation will use this as one end of the - * selection). Writable by items. */ + int selectAnchor; /* Character index of fixed end of + * selection (i.e. "select to" operation will + * use this as one end of the selection). + * Writable by items. */ Tk_3DBorder insertBorder; /* Used to draw vertical bar for insertion * cursor. Read-only to items. */ int insertWidth; /* Total width of insertion cursor. Read-only @@ -833,6 +1019,59 @@ typedef struct Tk_CanvasTextInfo { } Tk_CanvasTextInfo; /* + * Structures used for Dashing and Outline. + */ + +typedef struct Tk_Dash { + int number; + union { + char *pt; + char array[sizeof(char *)]; + } pattern; +} Tk_Dash; + +typedef struct Tk_TSOffset { + int flags; /* flags; see below for possible values */ + int xoffset; /* x offset */ + int yoffset; /* y offset */ +} Tk_TSOffset; + +/* + * Bit fields in Tk_Offset->flags: + */ + +#define TK_OFFSET_INDEX 1 +#define TK_OFFSET_RELATIVE 2 +#define TK_OFFSET_LEFT 4 +#define TK_OFFSET_CENTER 8 +#define TK_OFFSET_RIGHT 16 +#define TK_OFFSET_TOP 32 +#define TK_OFFSET_MIDDLE 64 +#define TK_OFFSET_BOTTOM 128 + +typedef struct Tk_Outline { + GC gc; /* Graphics context. */ + double width; /* Width of outline. */ + double activeWidth; /* Width of outline. */ + double disabledWidth; /* Width of outline. */ + int offset; /* Dash offset */ + Tk_Dash dash; /* Dash pattern */ + Tk_Dash activeDash; /* Dash pattern if state is active*/ + Tk_Dash disabledDash; /* Dash pattern if state is disabled*/ + VOID *reserved1; /* reserved for future expansion */ + VOID *reserved2; + VOID *reserved3; + Tk_TSOffset tsoffset; /* stipple offset for outline*/ + XColor *color; /* Outline color. */ + XColor *activeColor; /* Outline color if state is active. */ + XColor *disabledColor; /* Outline color if state is disabled. */ + Pixmap stipple; /* Outline Stipple pattern. */ + Pixmap activeStipple; /* Outline Stipple pattern if state is active. */ + Pixmap disabledStipple; /* Outline Stipple pattern if state is disabled. */ +} Tk_Outline; + + +/* *-------------------------------------------------------------- * * Procedure prototypes and structures used for managing images: @@ -841,9 +1080,15 @@ typedef struct Tk_CanvasTextInfo { */ typedef struct Tk_ImageType Tk_ImageType; +#ifdef USE_OLD_IMAGE +typedef int (Tk_ImageCreateProc) _ANSI_ARGS_((Tcl_Interp *interp, + char *name, int argc, char **argv, Tk_ImageType *typePtr, + Tk_ImageMaster master, ClientData *masterDataPtr)); +#else typedef int (Tk_ImageCreateProc) _ANSI_ARGS_((Tcl_Interp *interp, char *name, int objc, Tcl_Obj *CONST objv[], Tk_ImageType *typePtr, Tk_ImageMaster master, ClientData *masterDataPtr)); +#endif typedef ClientData (Tk_ImageGetProc) _ANSI_ARGS_((Tk_Window tkwin, ClientData masterData)); typedef void (Tk_ImageDisplayProc) _ANSI_ARGS_((ClientData instanceData, @@ -855,6 +1100,9 @@ typedef void (Tk_ImageDeleteProc) _ANSI_ARGS_((ClientData masterData)); typedef void (Tk_ImageChangedProc) _ANSI_ARGS_((ClientData clientData, int x, int y, int width, int height, int imageWidth, int imageHeight)); +typedef int (Tk_ImagePostscriptProc) _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, Tk_PostscriptInfo psinfo, + int x, int y, int width, int height, int prepass)); /* * The following structure represents a particular type of image @@ -884,6 +1132,9 @@ struct Tk_ImageType { * will not be called until after freeProc * has been called for each instance of the * image. */ + Tk_ImagePostscriptProc *postscriptProc; + /* Procedure to call to produce postscript + * output for the image. */ struct Tk_ImageType *nextPtr; /* Next in list of all image types currently * known. Filled in by Tk, not by image @@ -918,10 +1169,9 @@ typedef struct Tk_PhotoImageBlock { * pixels in successive lines. */ int pixelSize; /* Address difference between successive * pixels in the same line. */ - int offset[3]; /* Address differences between the red, green - * and blue components of the pixel and the - * pixel as a whole. */ - int reserved; /* Reserved for extensions (dash patch) */ + int offset[4]; /* Address differences between the red, green, + * blue and alpha components of the pixel and + * the pixel as a whole. */ } Tk_PhotoImageBlock; /* @@ -930,6 +1180,7 @@ typedef struct Tk_PhotoImageBlock { */ typedef struct Tk_PhotoImageFormat Tk_PhotoImageFormat; +#ifdef USE_OLD_IMAGE typedef int (Tk_ImageFileMatchProc) _ANSI_ARGS_((Tcl_Channel chan, char *fileName, char *formatString, int *widthPtr, int *heightPtr)); typedef int (Tk_ImageStringMatchProc) _ANSI_ARGS_((Tcl_Obj *dataObj, @@ -946,6 +1197,25 @@ typedef int (Tk_ImageFileWriteProc) _ANSI_ARGS_((Tcl_Interp *interp, typedef int (Tk_ImageStringWriteProc) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_DString *dataPtr, char *formatString, Tk_PhotoImageBlock *blockPtr)); +#else +typedef int (Tk_ImageFileMatchProc) _ANSI_ARGS_((Tcl_Channel chan, + CONST char *fileName, Tcl_Obj *format, int *widthPtr, + int *heightPtr, Tcl_Interp *interp)); +typedef int (Tk_ImageStringMatchProc) _ANSI_ARGS_((Tcl_Obj *dataObj, + Tcl_Obj *format, int *widthPtr, int *heightPtr, + Tcl_Interp *interp)); +typedef int (Tk_ImageFileReadProc) _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Channel chan, CONST char *fileName, Tcl_Obj *format, + Tk_PhotoHandle imageHandle, int destX, int destY, + int width, int height, int srcX, int srcY)); +typedef int (Tk_ImageStringReadProc) _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *dataObj, Tcl_Obj *format, Tk_PhotoHandle imageHandle, + int destX, int destY, int width, int height, int srcX, int srcY)); +typedef int (Tk_ImageFileWriteProc) _ANSI_ARGS_((Tcl_Interp *interp, + CONST char *fileName, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr)); +typedef int (Tk_ImageStringWriteProc) _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr)); +#endif /* * The following structure represents a particular file format for @@ -980,6 +1250,17 @@ struct Tk_PhotoImageFormat { * currently known. Filled in by Tk, not * by image format handler. */ }; + +EXTERN void Tk_CreateOldImageType _ANSI_ARGS_(( + Tk_ImageType *typePtr)); +EXTERN void Tk_CreateOldPhotoImageFormat _ANSI_ARGS_(( + Tk_PhotoImageFormat *formatPtr)); + +#if !defined(USE_TK_STUBS) && defined(USE_OLD_IMAGE) +#define Tk_CreateImageType Tk_CreateOldImageType +#define Tk_CreatePhotoImageFormat Tk_CreateOldPhotoImageFormat +#endif + /* *-------------------------------------------------------------- @@ -1018,11 +1299,35 @@ struct Tk_PhotoImageFormat { #define Tk_DoWhenIdle Tcl_DoWhenIdle #define Tk_Sleep Tcl_Sleep +/* Additional stuff that has moved to Tcl: */ + +#define Tk_AfterCmd Tcl_AfterCmd #define Tk_EventuallyFree Tcl_EventuallyFree #define Tk_FreeProc Tcl_FreeProc #define Tk_Preserve Tcl_Preserve #define Tk_Release Tcl_Release -#define Tk_FileeventCmd Tcl_FileEventCmd + +/* Removed Tk_Main, use macro instead */ +#define Tk_Main(argc, argv, proc) \ + Tk_MainEx(argc, argv, proc, Tcl_CreateInterp()) + +char *Tk_InitStubs _ANSI_ARGS_((Tcl_Interp *interp, char *version, int exact)); + +#ifndef USE_TK_STUBS + +#define Tk_InitStubs(interp, version, exact) \ + Tcl_PkgRequire(interp, "Tk", version, exact) + +#endif + +void Tk_InitImageArgs _ANSI_ARGS_((Tcl_Interp *interp, int argc, char ***argv)); + +#if !defined(USE_TK_STUBS) || !defined(USE_OLD_IMAGE) + +#define Tk_InitImageArgs(interp, argc, argv) /**/ + +#endif + /* *-------------------------------------------------------------- @@ -1046,6 +1351,7 @@ typedef Tk_RestrictAction (Tk_RestrictProc) _ANSI_ARGS_(( typedef int (Tk_SelectionProc) _ANSI_ARGS_((ClientData clientData, int offset, char *buffer, int maxBytes)); + /* *-------------------------------------------------------------- * @@ -1054,512 +1360,26 @@ typedef int (Tk_SelectionProc) _ANSI_ARGS_((ClientData clientData, *-------------------------------------------------------------- */ -EXTERN XColor * Tk_3DBorderColor _ANSI_ARGS_((Tk_3DBorder border)); -EXTERN GC Tk_3DBorderGC _ANSI_ARGS_((Tk_Window tkwin, - Tk_3DBorder border, int which)); -EXTERN void Tk_3DHorizontalBevel _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, int x, - int y, int width, int height, int leftIn, - int rightIn, int topBevel, int relief)); -EXTERN void Tk_3DVerticalBevel _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, int x, - int y, int width, int height, int leftBevel, - int relief)); -EXTERN void Tk_AddOption _ANSI_ARGS_((Tk_Window tkwin, char *name, - char *value, int priority)); -EXTERN void Tk_BindEvent _ANSI_ARGS_((Tk_BindingTable bindingTable, - XEvent *eventPtr, Tk_Window tkwin, int numObjects, - ClientData *objectPtr)); -EXTERN void Tk_CanvasDrawableCoords _ANSI_ARGS_((Tk_Canvas canvas, - double x, double y, short *drawableXPtr, - short *drawableYPtr)); -EXTERN void Tk_CanvasEventuallyRedraw _ANSI_ARGS_(( - Tk_Canvas canvas, int x1, int y1, int x2, - int y2)); -EXTERN int Tk_CanvasGetCoord _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, char *string, - double *doublePtr)); -EXTERN Tk_CanvasTextInfo *Tk_CanvasGetTextInfo _ANSI_ARGS_((Tk_Canvas canvas)); -EXTERN int Tk_CanvasPsBitmap _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Pixmap bitmap, int x, int y, - int width, int height)); -EXTERN int Tk_CanvasPsColor _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, XColor *colorPtr)); -EXTERN int Tk_CanvasPsFont _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Tk_Font font)); -EXTERN void Tk_CanvasPsPath _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, double *coordPtr, int numPoints)); -EXTERN int Tk_CanvasPsStipple _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, Pixmap bitmap)); -EXTERN double Tk_CanvasPsY _ANSI_ARGS_((Tk_Canvas canvas, double y)); -EXTERN void Tk_CanvasSetStippleOrigin _ANSI_ARGS_(( - Tk_Canvas canvas, GC gc)); -EXTERN int Tk_CanvasTagsParseProc _ANSI_ARGS_(( - ClientData clientData, Tcl_Interp *interp, - Tk_Window tkwin, char *value, char *widgRec, - int offset)); -EXTERN char * Tk_CanvasTagsPrintProc _ANSI_ARGS_(( - ClientData clientData, Tk_Window tkwin, - char *widgRec, int offset, - Tcl_FreeProc **freeProcPtr)); -EXTERN Tk_Window Tk_CanvasTkwin _ANSI_ARGS_((Tk_Canvas canvas)); -EXTERN void Tk_CanvasWindowCoords _ANSI_ARGS_((Tk_Canvas canvas, - double x, double y, short *screenXPtr, - short *screenYPtr)); -EXTERN void Tk_ChangeWindowAttributes _ANSI_ARGS_((Tk_Window tkwin, - unsigned long valueMask, - XSetWindowAttributes *attsPtr)); -EXTERN int Tk_CharBbox _ANSI_ARGS_((Tk_TextLayout layout, - int index, int *xPtr, int *yPtr, int *widthPtr, - int *heightPtr)); -EXTERN void Tk_ClearSelection _ANSI_ARGS_((Tk_Window tkwin, - Atom selection)); -EXTERN int Tk_ClipboardAppend _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Atom target, Atom format, - char* buffer)); -EXTERN int Tk_ClipboardClear _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin)); -EXTERN int Tk_ConfigureInfo _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specs, - char *widgRec, char *argvName, int flags)); -EXTERN int Tk_ConfigureValue _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specs, - char *widgRec, char *argvName, int flags)); -EXTERN int Tk_ConfigureWidget _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specs, - int argc, char **argv, char *widgRec, - int flags)); -EXTERN void Tk_ConfigureWindow _ANSI_ARGS_((Tk_Window tkwin, - unsigned int valueMask, XWindowChanges *valuePtr)); -EXTERN Tk_TextLayout Tk_ComputeTextLayout _ANSI_ARGS_((Tk_Font font, - CONST char *string, int numChars, int wrapLength, - Tk_Justify justify, int flags, int *widthPtr, - int *heightPtr)); -EXTERN Tk_Window Tk_CoordsToWindow _ANSI_ARGS_((int rootX, int rootY, - Tk_Window tkwin)); -EXTERN unsigned long Tk_CreateBinding _ANSI_ARGS_((Tcl_Interp *interp, - Tk_BindingTable bindingTable, ClientData object, - char *eventString, char *command, int append)); -EXTERN Tk_BindingTable Tk_CreateBindingTable _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN Tk_ErrorHandler Tk_CreateErrorHandler _ANSI_ARGS_((Display *display, - int errNum, int request, int minorCode, - Tk_ErrorProc *errorProc, ClientData clientData)); -EXTERN void Tk_CreateEventHandler _ANSI_ARGS_((Tk_Window token, - unsigned long mask, Tk_EventProc *proc, - ClientData clientData)); -EXTERN void Tk_CreateGenericHandler _ANSI_ARGS_(( - Tk_GenericProc *proc, ClientData clientData)); -EXTERN void Tk_CreateImageType _ANSI_ARGS_(( - Tk_ImageType *typePtr)); -EXTERN void Tk_CreateItemType _ANSI_ARGS_((Tk_ItemType *typePtr)); -EXTERN void Tk_CreatePhotoImageFormat _ANSI_ARGS_(( - Tk_PhotoImageFormat *formatPtr)); -EXTERN void Tk_CreateSelHandler _ANSI_ARGS_((Tk_Window tkwin, - Atom selection, Atom target, - Tk_SelectionProc *proc, ClientData clientData, - Atom format)); -EXTERN Tk_Window Tk_CreateWindow _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window parent, char *name, char *screenName)); -EXTERN Tk_Window Tk_CreateWindowFromPath _ANSI_ARGS_(( - Tcl_Interp *interp, Tk_Window tkwin, - char *pathName, char *screenName)); -EXTERN int Tk_DefineBitmap _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Uid name, char *source, int width, - int height)); -EXTERN void Tk_DefineCursor _ANSI_ARGS_((Tk_Window window, - Tk_Cursor cursor)); -EXTERN void Tk_DeleteAllBindings _ANSI_ARGS_(( - Tk_BindingTable bindingTable, ClientData object)); -EXTERN int Tk_DeleteBinding _ANSI_ARGS_((Tcl_Interp *interp, - Tk_BindingTable bindingTable, ClientData object, - char *eventString)); -EXTERN void Tk_DeleteBindingTable _ANSI_ARGS_(( - Tk_BindingTable bindingTable)); -EXTERN void Tk_DeleteErrorHandler _ANSI_ARGS_(( - Tk_ErrorHandler handler)); -EXTERN void Tk_DeleteEventHandler _ANSI_ARGS_((Tk_Window token, - unsigned long mask, Tk_EventProc *proc, - ClientData clientData)); -EXTERN void Tk_DeleteGenericHandler _ANSI_ARGS_(( - Tk_GenericProc *proc, ClientData clientData)); -EXTERN void Tk_DeleteImage _ANSI_ARGS_((Tcl_Interp *interp, - char *name)); -EXTERN void Tk_DeleteSelHandler _ANSI_ARGS_((Tk_Window tkwin, - Atom selection, Atom target)); -EXTERN void Tk_DestroyWindow _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN char * Tk_DisplayName _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN int Tk_DistanceToTextLayout _ANSI_ARGS_(( - Tk_TextLayout layout, int x, int y)); -EXTERN void Tk_Draw3DPolygon _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, - XPoint *pointPtr, int numPoints, int borderWidth, - int leftRelief)); -EXTERN void Tk_Draw3DRectangle _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, int x, - int y, int width, int height, int borderWidth, - int relief)); -EXTERN void Tk_DrawChars _ANSI_ARGS_((Display *display, - Drawable drawable, GC gc, Tk_Font tkfont, - CONST char *source, int numChars, int x, - int y)); -EXTERN void Tk_DrawFocusHighlight _ANSI_ARGS_((Tk_Window tkwin, - GC gc, int width, Drawable drawable)); -EXTERN void Tk_DrawTextLayout _ANSI_ARGS_((Display *display, - Drawable drawable, GC gc, Tk_TextLayout layout, - int x, int y, int firstChar, int lastChar)); -EXTERN void Tk_Fill3DPolygon _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, - XPoint *pointPtr, int numPoints, int borderWidth, - int leftRelief)); -EXTERN void Tk_Fill3DRectangle _ANSI_ARGS_((Tk_Window tkwin, - Drawable drawable, Tk_3DBorder border, int x, - int y, int width, int height, int borderWidth, - int relief)); -EXTERN Tk_PhotoHandle Tk_FindPhoto _ANSI_ARGS_((Tcl_Interp *interp, - char *imageName)); -EXTERN Font Tk_FontId _ANSI_ARGS_((Tk_Font font)); -EXTERN void Tk_Free3DBorder _ANSI_ARGS_((Tk_3DBorder border)); -EXTERN void Tk_FreeBitmap _ANSI_ARGS_((Display *display, - Pixmap bitmap)); -EXTERN void Tk_FreeColor _ANSI_ARGS_((XColor *colorPtr)); -EXTERN void Tk_FreeColormap _ANSI_ARGS_((Display *display, - Colormap colormap)); -EXTERN void Tk_FreeCursor _ANSI_ARGS_((Display *display, - Tk_Cursor cursor)); -EXTERN void Tk_FreeFont _ANSI_ARGS_((Tk_Font)); -EXTERN void Tk_FreeGC _ANSI_ARGS_((Display *display, GC gc)); -EXTERN void Tk_FreeImage _ANSI_ARGS_((Tk_Image image)); -EXTERN void Tk_FreeOptions _ANSI_ARGS_((Tk_ConfigSpec *specs, - char *widgRec, Display *display, int needFlags)); -EXTERN void Tk_FreePixmap _ANSI_ARGS_((Display *display, - Pixmap pixmap)); -EXTERN void Tk_FreeTextLayout _ANSI_ARGS_(( - Tk_TextLayout textLayout)); -EXTERN void Tk_FreeXId _ANSI_ARGS_((Display *display, XID xid)); -EXTERN GC Tk_GCForColor _ANSI_ARGS_((XColor *colorPtr, - Drawable drawable)); -EXTERN void Tk_GeometryRequest _ANSI_ARGS_((Tk_Window tkwin, - int reqWidth, int reqHeight)); -EXTERN Tk_3DBorder Tk_Get3DBorder _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_Uid colorName)); -EXTERN void Tk_GetAllBindings _ANSI_ARGS_((Tcl_Interp *interp, - Tk_BindingTable bindingTable, ClientData object)); -EXTERN int Tk_GetAnchor _ANSI_ARGS_((Tcl_Interp *interp, - char *string, Tk_Anchor *anchorPtr)); -EXTERN char * Tk_GetAtomName _ANSI_ARGS_((Tk_Window tkwin, - Atom atom)); -EXTERN char * Tk_GetBinding _ANSI_ARGS_((Tcl_Interp *interp, - Tk_BindingTable bindingTable, ClientData object, - char *eventString)); -EXTERN Pixmap Tk_GetBitmap _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_Uid string)); -EXTERN Pixmap Tk_GetBitmapFromData _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *source, - int width, int height)); -EXTERN int Tk_GetCapStyle _ANSI_ARGS_((Tcl_Interp *interp, - char *string, int *capPtr)); -EXTERN XColor * Tk_GetColor _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_Uid name)); -EXTERN XColor * Tk_GetColorByValue _ANSI_ARGS_((Tk_Window tkwin, - XColor *colorPtr)); -EXTERN Colormap Tk_GetColormap _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string)); -EXTERN Tk_Cursor Tk_GetCursor _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_Uid string)); -EXTERN Tk_Cursor Tk_GetCursorFromData _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *source, char *mask, - int width, int height, int xHot, int yHot, - Tk_Uid fg, Tk_Uid bg)); -EXTERN Tk_Font Tk_GetFont _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, CONST char *string)); -EXTERN Tk_Font Tk_GetFontFromObj _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tcl_Obj *objPtr)); -EXTERN void Tk_GetFontMetrics _ANSI_ARGS_((Tk_Font font, - Tk_FontMetrics *fmPtr)); -EXTERN GC Tk_GetGC _ANSI_ARGS_((Tk_Window tkwin, - unsigned long valueMask, XGCValues *valuePtr)); -/* CYGNUS LOCAL. */ -EXTERN GC Tk_GetGCColor _ANSI_ARGS_((Tk_Window tkwin, - unsigned long valueMask, XGCValues *valuePtr, - XColor *foreground, XColor *background)); -EXTERN Tk_Image Tk_GetImage _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *name, - Tk_ImageChangedProc *changeProc, - ClientData clientData)); -EXTERN ClientData Tk_GetImageMasterData _ANSI_ARGS_ ((Tcl_Interp *interp, - char *name, Tk_ImageType **typePtrPtr)); -EXTERN Tk_ItemType * Tk_GetItemTypes _ANSI_ARGS_((void)); -EXTERN int Tk_GetJoinStyle _ANSI_ARGS_((Tcl_Interp *interp, - char *string, int *joinPtr)); -EXTERN int Tk_GetJustify _ANSI_ARGS_((Tcl_Interp *interp, - char *string, Tk_Justify *justifyPtr)); -EXTERN int Tk_GetNumMainWindows _ANSI_ARGS_((void)); -EXTERN Tk_Uid Tk_GetOption _ANSI_ARGS_((Tk_Window tkwin, char *name, - char *className)); -EXTERN int Tk_GetPixels _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string, int *intPtr)); -EXTERN Pixmap Tk_GetPixmap _ANSI_ARGS_((Display *display, Drawable d, - int width, int height, int depth)); -EXTERN int Tk_GetRelief _ANSI_ARGS_((Tcl_Interp *interp, - char *name, int *reliefPtr)); -EXTERN void Tk_GetRootCoords _ANSI_ARGS_ ((Tk_Window tkwin, - int *xPtr, int *yPtr)); -EXTERN int Tk_GetScrollInfo _ANSI_ARGS_((Tcl_Interp *interp, - int argc, char **argv, double *dblPtr, - int *intPtr)); -EXTERN int Tk_GetScreenMM _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string, double *doublePtr)); -EXTERN int Tk_GetSelection _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Atom selection, Atom target, - Tk_GetSelProc *proc, ClientData clientData)); -EXTERN Tk_Uid Tk_GetUid _ANSI_ARGS_((CONST char *string)); -EXTERN Visual * Tk_GetVisual _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string, int *depthPtr, - Colormap *colormapPtr)); -EXTERN void Tk_GetVRootGeometry _ANSI_ARGS_((Tk_Window tkwin, - int *xPtr, int *yPtr, int *widthPtr, - int *heightPtr)); -EXTERN int Tk_Grab _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, int grabGlobal)); -EXTERN void Tk_HandleEvent _ANSI_ARGS_((XEvent *eventPtr)); -EXTERN Tk_Window Tk_IdToWindow _ANSI_ARGS_((Display *display, - Window window)); -EXTERN void Tk_ImageChanged _ANSI_ARGS_(( - Tk_ImageMaster master, int x, int y, - int width, int height, int imageWidth, - int imageHeight)); -EXTERN int Tk_Init _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN Atom Tk_InternAtom _ANSI_ARGS_((Tk_Window tkwin, - char *name)); -EXTERN int Tk_IntersectTextLayout _ANSI_ARGS_(( - Tk_TextLayout layout, int x, int y, int width, - int height)); -EXTERN void Tk_Main _ANSI_ARGS_((int argc, char **argv, - Tcl_AppInitProc *appInitProc)); -EXTERN void Tk_MainLoop _ANSI_ARGS_((void)); -EXTERN void Tk_MaintainGeometry _ANSI_ARGS_((Tk_Window slave, - Tk_Window master, int x, int y, int width, - int height)); -EXTERN Tk_Window Tk_MainWindow _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN void Tk_MakeWindowExist _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void Tk_ManageGeometry _ANSI_ARGS_((Tk_Window tkwin, - Tk_GeomMgr *mgrPtr, ClientData clientData)); -EXTERN void Tk_MapWindow _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN int Tk_MeasureChars _ANSI_ARGS_((Tk_Font tkfont, - CONST char *source, int maxChars, int maxPixels, - int flags, int *lengthPtr)); -EXTERN void Tk_MoveResizeWindow _ANSI_ARGS_((Tk_Window tkwin, - int x, int y, int width, int height)); -EXTERN void Tk_MoveWindow _ANSI_ARGS_((Tk_Window tkwin, int x, - int y)); -EXTERN void Tk_MoveToplevelWindow _ANSI_ARGS_((Tk_Window tkwin, - int x, int y)); -EXTERN char * Tk_NameOf3DBorder _ANSI_ARGS_((Tk_3DBorder border)); -EXTERN char * Tk_NameOfAnchor _ANSI_ARGS_((Tk_Anchor anchor)); -EXTERN char * Tk_NameOfBitmap _ANSI_ARGS_((Display *display, - Pixmap bitmap)); -EXTERN char * Tk_NameOfCapStyle _ANSI_ARGS_((int cap)); -EXTERN char * Tk_NameOfColor _ANSI_ARGS_((XColor *colorPtr)); -EXTERN char * Tk_NameOfCursor _ANSI_ARGS_((Display *display, - Tk_Cursor cursor)); -EXTERN char * Tk_NameOfFont _ANSI_ARGS_((Tk_Font font)); -EXTERN char * Tk_NameOfImage _ANSI_ARGS_(( - Tk_ImageMaster imageMaster)); -EXTERN char * Tk_NameOfJoinStyle _ANSI_ARGS_((int join)); -EXTERN char * Tk_NameOfJustify _ANSI_ARGS_((Tk_Justify justify)); -EXTERN char * Tk_NameOfRelief _ANSI_ARGS_((int relief)); -EXTERN Tk_Window Tk_NameToWindow _ANSI_ARGS_((Tcl_Interp *interp, - char *pathName, Tk_Window tkwin)); -EXTERN void Tk_OwnSelection _ANSI_ARGS_((Tk_Window tkwin, - Atom selection, Tk_LostSelProc *proc, - ClientData clientData)); -EXTERN int Tk_ParseArgv _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, int *argcPtr, char **argv, - Tk_ArgvInfo *argTable, int flags)); -EXTERN void Tk_PhotoPutBlock _ANSI_ARGS_((Tk_PhotoHandle handle, - Tk_PhotoImageBlock *blockPtr, int x, int y, - int width, int height)); -EXTERN void Tk_PhotoPutZoomedBlock _ANSI_ARGS_(( - Tk_PhotoHandle handle, - Tk_PhotoImageBlock *blockPtr, int x, int y, - int width, int height, int zoomX, int zoomY, - int subsampleX, int subsampleY)); -EXTERN int Tk_PhotoGetImage _ANSI_ARGS_((Tk_PhotoHandle handle, - Tk_PhotoImageBlock *blockPtr)); -EXTERN void Tk_PhotoBlank _ANSI_ARGS_((Tk_PhotoHandle handle)); -EXTERN void Tk_PhotoExpand _ANSI_ARGS_((Tk_PhotoHandle handle, - int width, int height )); -EXTERN void Tk_PhotoGetSize _ANSI_ARGS_((Tk_PhotoHandle handle, - int *widthPtr, int *heightPtr)); -EXTERN void Tk_PhotoSetSize _ANSI_ARGS_((Tk_PhotoHandle handle, - int width, int height)); -EXTERN int Tk_PointToChar _ANSI_ARGS_((Tk_TextLayout layout, - int x, int y)); -EXTERN int Tk_PostscriptFontName _ANSI_ARGS_((Tk_Font tkfont, - Tcl_DString *dsPtr)); -EXTERN void Tk_PreserveColormap _ANSI_ARGS_((Display *display, - Colormap colormap)); -EXTERN void Tk_QueueWindowEvent _ANSI_ARGS_((XEvent *eventPtr, - Tcl_QueuePosition position)); -EXTERN void Tk_RedrawImage _ANSI_ARGS_((Tk_Image image, int imageX, - int imageY, int width, int height, - Drawable drawable, int drawableX, int drawableY)); -EXTERN void Tk_ResizeWindow _ANSI_ARGS_((Tk_Window tkwin, - int width, int height)); -EXTERN int Tk_RestackWindow _ANSI_ARGS_((Tk_Window tkwin, - int aboveBelow, Tk_Window other)); -EXTERN Tk_RestrictProc *Tk_RestrictEvents _ANSI_ARGS_((Tk_RestrictProc *proc, - ClientData arg, ClientData *prevArgPtr)); -EXTERN int Tk_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN char * Tk_SetAppName _ANSI_ARGS_((Tk_Window tkwin, - char *name)); -EXTERN void Tk_SetBackgroundFromBorder _ANSI_ARGS_(( - Tk_Window tkwin, Tk_3DBorder border)); -EXTERN void Tk_SetClass _ANSI_ARGS_((Tk_Window tkwin, - char *className)); -EXTERN void Tk_SetGrid _ANSI_ARGS_((Tk_Window tkwin, - int reqWidth, int reqHeight, int gridWidth, - int gridHeight)); -EXTERN void Tk_SetInternalBorder _ANSI_ARGS_((Tk_Window tkwin, - int width)); -EXTERN void Tk_SetWindowBackground _ANSI_ARGS_((Tk_Window tkwin, - unsigned long pixel)); -EXTERN void Tk_SetWindowBackgroundPixmap _ANSI_ARGS_(( - Tk_Window tkwin, Pixmap pixmap)); -EXTERN void Tk_SetWindowBorder _ANSI_ARGS_((Tk_Window tkwin, - unsigned long pixel)); -EXTERN void Tk_SetWindowBorderWidth _ANSI_ARGS_((Tk_Window tkwin, - int width)); -EXTERN void Tk_SetWindowBorderPixmap _ANSI_ARGS_((Tk_Window tkwin, - Pixmap pixmap)); -EXTERN void Tk_SetWindowColormap _ANSI_ARGS_((Tk_Window tkwin, - Colormap colormap)); -EXTERN int Tk_SetWindowVisual _ANSI_ARGS_((Tk_Window tkwin, - Visual *visual, int depth, - Colormap colormap)); -EXTERN void Tk_SizeOfBitmap _ANSI_ARGS_((Display *display, - Pixmap bitmap, int *widthPtr, - int *heightPtr)); -EXTERN void Tk_SizeOfImage _ANSI_ARGS_((Tk_Image image, - int *widthPtr, int *heightPtr)); -EXTERN int Tk_StrictMotif _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void Tk_TextLayoutToPostscript _ANSI_ARGS_(( - Tcl_Interp *interp, Tk_TextLayout layout)); -EXTERN int Tk_TextWidth _ANSI_ARGS_((Tk_Font font, - CONST char *string, int numChars)); -EXTERN void Tk_UndefineCursor _ANSI_ARGS_((Tk_Window window)); -EXTERN void Tk_UnderlineChars _ANSI_ARGS_((Display *display, - Drawable drawable, GC gc, Tk_Font tkfont, - CONST char *source, int x, int y, int firstChar, - int lastChar)); -EXTERN void Tk_UnderlineTextLayout _ANSI_ARGS_(( - Display *display, Drawable drawable, GC gc, - Tk_TextLayout layout, int x, int y, - int underline)); -EXTERN void Tk_Ungrab _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void Tk_UnmaintainGeometry _ANSI_ARGS_((Tk_Window slave, - Tk_Window master)); -EXTERN void Tk_UnmapWindow _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void Tk_UnsetGrid _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void Tk_UpdatePointer _ANSI_ARGS_((Tk_Window tkwin, - int x, int y, int state)); +#include "tkDecls.h" /* * Tcl commands exported by Tk: */ -EXTERN int Tk_BellObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *CONST objv[])); -EXTERN int Tk_BindCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_BindtagsCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ButtonCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_CanvasCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_CheckbuttonCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ClipboardCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ChooseColorCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_DestroyCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_EntryCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_EventCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_FrameCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_FocusCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_FontObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *CONST objv[])); -EXTERN int Tk_GetOpenFileCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_GetSaveFileCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_GrabCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_GridCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ImageCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[])); -EXTERN int Tk_LabelCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ListboxCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_LowerCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_MenuCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_MenubuttonCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_MessageBoxCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_MessageCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_OptionCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_PackCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_PlaceCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_RadiobuttonCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_RaiseCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ScaleCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ScrollbarCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_SelectionCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_SendCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_TextCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_TkObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *CONST objv[])); -EXTERN int Tk_TkwaitCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_ToplevelCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_UpdateCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -EXTERN int Tk_WinfoObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *CONST objv[])); -EXTERN int Tk_WmCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); #endif /* RESOURCE_INCLUDED */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT +/* + * end block for C++ + */ + +#ifdef __cplusplus +} +#endif + #endif /* _TK */ + + diff --git a/tk/generic/tk3d.c b/tk/generic/tk3d.c index 62139b5e333..3073d2dfcbd 100644 --- a/tk/generic/tk3d.c +++ b/tk/generic/tk3d.c @@ -13,33 +13,150 @@ * RCS: @(#) $Id$ */ -#include <tk3d.h> +#include "tk3d.h" /* - * Hash table to map from a border's values (color, etc.) to a - * Border structure for those values. + * The following table defines the string values for reliefs, which are + * used by Tk_GetReliefFromObj. */ -static Tcl_HashTable borderTable; -typedef struct { - Tk_Uid colorName; /* Color for border. */ - Colormap colormap; /* Colormap used for allocating border - * colors. */ - Screen *screen; /* Screen on which border will be drawn. */ -} BorderKey; - -static int initialized = 0; /* 0 means static structures haven't - * been initialized yet. */ +static char *reliefStrings[] = {"flat", "groove", "raised", "ridge", "solid", + "sunken", (char *) NULL}; /* * Forward declarations for procedures defined in this file: */ -static void BorderInit _ANSI_ARGS_((void)); +static void BorderInit _ANSI_ARGS_((TkDisplay *dispPtr)); +static void DupBorderObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr, + Tcl_Obj *dupObjPtr)); +static void FreeBorderObjProc _ANSI_ARGS_((Tcl_Obj *objPtr)); static int Intersect _ANSI_ARGS_((XPoint *a1Ptr, XPoint *a2Ptr, XPoint *b1Ptr, XPoint *b2Ptr, XPoint *iPtr)); +static void InitBorderObj _ANSI_ARGS_((Tcl_Obj *objPtr)); static void ShiftLine _ANSI_ARGS_((XPoint *p1Ptr, XPoint *p2Ptr, int distance, XPoint *p3Ptr)); + +/* + * The following structure defines the implementation of the "border" Tcl + * object, used for drawing. The border object remembers the hash table entry + * associated with a border. The actual allocation and deallocation of the + * border should be done by the configuration package when the border option + * is set. + */ + +static Tcl_ObjType borderObjType = { + "border", /* name */ + FreeBorderObjProc, /* freeIntRepProc */ + DupBorderObjProc, /* dupIntRepProc */ + NULL, /* updateStringProc */ + NULL /* setFromAnyProc */ +}; + +/* + *---------------------------------------------------------------------- + * + * Tk_Alloc3DBorderFromObj -- + * + * Given a Tcl_Obj *, map the value to a corresponding + * Tk_3DBorder structure based on the tkwin given. + * + * Results: + * The return value is a token for a data structure describing a + * 3-D border. This token may be passed to procedures such as + * Tk_Draw3DRectangle and Tk_Free3DBorder. If an error prevented + * the border from being created then NULL is returned and an error + * message will be left in the interp's result. + * + * Side effects: + * The border is added to an internal database with a reference + * count. For each call to this procedure, there should eventually + * be a call to FreeBorderObjProc so that the database is + * cleaned up when borders aren't in use anymore. + * + *---------------------------------------------------------------------- + */ + +Tk_3DBorder +Tk_Alloc3DBorderFromObj(interp, tkwin, objPtr) + Tcl_Interp *interp; /* Interp for error results. */ + Tk_Window tkwin; /* Need the screen the border is used on.*/ + Tcl_Obj *objPtr; /* Object giving name of color for window + * background. */ +{ + TkBorder *borderPtr; + + if (objPtr->typePtr != &borderObjType) { + InitBorderObj(objPtr); + } + borderPtr = (TkBorder *) objPtr->internalRep.twoPtrValue.ptr1; + + /* + * If the object currently points to a TkBorder, see if it's the + * one we want. If so, increment its reference count and return. + */ + + if (borderPtr != NULL) { + if (borderPtr->resourceRefCount == 0) { + /* + * This is a stale reference: it refers to a border that's + * no longer in use. Clear the reference. + */ + + FreeBorderObjProc(objPtr); + borderPtr = NULL; + } else if ((Tk_Screen(tkwin) == borderPtr->screen) + && (Tk_Colormap(tkwin) == borderPtr->colormap)) { + borderPtr->resourceRefCount++; + return (Tk_3DBorder) borderPtr; + } + } + + /* + * The object didn't point to the border that we wanted. Search + * the list of borders with the same name to see if one of the + * others is the right one. + */ + + /* + * If the cached value is NULL, either the object type was not a + * color going in, or the object is a color type but had + * previously been freed. + * + * If the value is not NULL, the internal rep is the value + * of the color the last time this object was accessed. Check + * the screen and colormap of the last access, and if they + * match, we are done. + */ + + if (borderPtr != NULL) { + TkBorder *firstBorderPtr = + (TkBorder *) Tcl_GetHashValue(borderPtr->hashPtr); + FreeBorderObjProc(objPtr); + for (borderPtr = firstBorderPtr ; borderPtr != NULL; + borderPtr = borderPtr->nextPtr) { + if ((Tk_Screen(tkwin) == borderPtr->screen) + && (Tk_Colormap(tkwin) == borderPtr->colormap)) { + borderPtr->resourceRefCount++; + borderPtr->objRefCount++; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) borderPtr; + return (Tk_3DBorder) borderPtr; + } + } + } + + /* + * Still no luck. Call Tk_Get3DBorder to allocate a new border. + */ + + borderPtr = (TkBorder *) Tk_Get3DBorder(interp, tkwin, + Tcl_GetString(objPtr)); + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) borderPtr; + if (borderPtr != NULL) { + borderPtr->objRefCount++; + } + return (Tk_3DBorder) borderPtr; +} /* *-------------------------------------------------------------- @@ -49,12 +166,11 @@ static void ShiftLine _ANSI_ARGS_((XPoint *p1Ptr, XPoint *p2Ptr, * Create a data structure for displaying a 3-D border. * * Results: - * The return value is a token for a data structure - * describing a 3-D border. This token may be passed - * to Tk_Draw3DRectangle and Tk_Free3DBorder. If an - * error prevented the border from being created then - * NULL is returned and an error message will be left - * in interp->result. + * The return value is a token for a data structure describing a + * 3-D border. This token may be passed to procedures such as + * Tk_Draw3DRectangle and Tk_Free3DBorder. If an error prevented + * the border from being created then NULL is returned and an error + * message will be left in the interp's result. * * Side effects: * Data structures, graphics contexts, etc. are allocated. @@ -69,71 +185,75 @@ Tk_Get3DBorder(interp, tkwin, colorName) Tcl_Interp *interp; /* Place to store an error message. */ Tk_Window tkwin; /* Token for window in which border will * be drawn. */ - Tk_Uid colorName; /* String giving name of color + char *colorName; /* String giving name of color * for window background. */ { - BorderKey key; Tcl_HashEntry *hashPtr; - register TkBorder *borderPtr; + TkBorder *borderPtr, *existingBorderPtr; int new; XGCValues gcValues; + XColor *bgColorPtr; + TkDisplay *dispPtr; - if (!initialized) { - BorderInit(); - } - - /* - * First, check to see if there's already a border that will work - * for this request. - */ + dispPtr = ((TkWindow *) tkwin)->dispPtr; - key.colorName = colorName; - key.colormap = Tk_Colormap(tkwin); - key.screen = Tk_Screen(tkwin); + if (!dispPtr->borderInit) { + BorderInit(dispPtr); + } - hashPtr = Tcl_CreateHashEntry(&borderTable, (char *) &key, &new); + hashPtr = Tcl_CreateHashEntry(&dispPtr->borderTable, colorName, &new); if (!new) { - borderPtr = (TkBorder *) Tcl_GetHashValue(hashPtr); - borderPtr->refCount++; + existingBorderPtr = (TkBorder *) Tcl_GetHashValue(hashPtr); + for (borderPtr = existingBorderPtr; borderPtr != NULL; + borderPtr = borderPtr->nextPtr) { + if ((Tk_Screen(tkwin) == borderPtr->screen) + && (Tk_Colormap(tkwin) == borderPtr->colormap)) { + borderPtr->resourceRefCount++; + return (Tk_3DBorder) borderPtr; + } + } } else { - XColor *bgColorPtr; + existingBorderPtr = NULL; + } - /* - * No satisfactory border exists yet. Initialize a new one. - */ - - bgColorPtr = Tk_GetColor(interp, tkwin, colorName); - if (bgColorPtr == NULL) { + /* + * No satisfactory border exists yet. Initialize a new one. + */ + + bgColorPtr = Tk_GetColor(interp, tkwin, colorName); + if (bgColorPtr == NULL) { + if (new) { Tcl_DeleteHashEntry(hashPtr); - return NULL; } - - borderPtr = TkpGetBorder(); - borderPtr->screen = Tk_Screen(tkwin); - borderPtr->visual = Tk_Visual(tkwin); - borderPtr->depth = Tk_Depth(tkwin); - borderPtr->colormap = key.colormap; - borderPtr->refCount = 1; - borderPtr->bgColorPtr = bgColorPtr; - borderPtr->darkColorPtr = NULL; - borderPtr->lightColorPtr = NULL; - borderPtr->shadow = None; - borderPtr->bgGC = None; - borderPtr->darkGC = None; - borderPtr->lightGC = None; - borderPtr->hashPtr = hashPtr; - Tcl_SetHashValue(hashPtr, borderPtr); - - /* - * Create the information for displaying the background color, - * but delay the allocation of shadows until they are actually - * needed for drawing. - */ - - gcValues.foreground = borderPtr->bgColorPtr->pixel; - borderPtr->bgGC = Tk_GetGCColor(tkwin, GCForeground, &gcValues, - borderPtr->bgColorPtr, NULL); + return NULL; } + + borderPtr = TkpGetBorder(); + borderPtr->screen = Tk_Screen(tkwin); + borderPtr->visual = Tk_Visual(tkwin); + borderPtr->depth = Tk_Depth(tkwin); + borderPtr->colormap = Tk_Colormap(tkwin); + borderPtr->resourceRefCount = 1; + borderPtr->objRefCount = 0; + borderPtr->bgColorPtr = bgColorPtr; + borderPtr->darkColorPtr = NULL; + borderPtr->lightColorPtr = NULL; + borderPtr->shadow = None; + borderPtr->bgGC = None; + borderPtr->darkGC = None; + borderPtr->lightGC = None; + borderPtr->hashPtr = hashPtr; + borderPtr->nextPtr = existingBorderPtr; + Tcl_SetHashValue(hashPtr, borderPtr); + + /* + * Create the information for displaying the background color, + * but delay the allocation of shadows until they are actually + * needed for drawing. + */ + + gcValues.foreground = borderPtr->bgColorPtr->pixel; + borderPtr->bgGC = Tk_GetGC(tkwin, GCForeground, &gcValues); return (Tk_3DBorder) borderPtr; } @@ -209,7 +329,7 @@ Tk_NameOf3DBorder(border) { TkBorder *borderPtr = (TkBorder *) border; - return ((BorderKey *) borderPtr->hashPtr->key.words)->colorName; + return borderPtr->hashPtr->key.string; } /* @@ -304,34 +424,51 @@ void Tk_Free3DBorder(border) Tk_3DBorder border; /* Token for border to be released. */ { - register TkBorder *borderPtr = (TkBorder *) border; + TkBorder *borderPtr = (TkBorder *) border; Display *display = DisplayOfScreen(borderPtr->screen); + TkBorder *prevPtr; - borderPtr->refCount--; - if (borderPtr->refCount == 0) { - TkpFreeBorder(borderPtr); - if (borderPtr->bgColorPtr != NULL) { - Tk_FreeColor(borderPtr->bgColorPtr); - } - if (borderPtr->darkColorPtr != NULL) { - Tk_FreeColor(borderPtr->darkColorPtr); - } - if (borderPtr->lightColorPtr != NULL) { - Tk_FreeColor(borderPtr->lightColorPtr); - } - if (borderPtr->shadow != None) { - Tk_FreeBitmap(display, borderPtr->shadow); - } - if (borderPtr->bgGC != None) { - Tk_FreeGC(display, borderPtr->bgGC); - } - if (borderPtr->darkGC != None) { - Tk_FreeGC(display, borderPtr->darkGC); + borderPtr->resourceRefCount--; + if (borderPtr->resourceRefCount > 0) { + return; + } + + prevPtr = (TkBorder *) Tcl_GetHashValue(borderPtr->hashPtr); + TkpFreeBorder(borderPtr); + if (borderPtr->bgColorPtr != NULL) { + Tk_FreeColor(borderPtr->bgColorPtr); + } + if (borderPtr->darkColorPtr != NULL) { + Tk_FreeColor(borderPtr->darkColorPtr); + } + if (borderPtr->lightColorPtr != NULL) { + Tk_FreeColor(borderPtr->lightColorPtr); + } + if (borderPtr->shadow != None) { + Tk_FreeBitmap(display, borderPtr->shadow); + } + if (borderPtr->bgGC != None) { + Tk_FreeGC(display, borderPtr->bgGC); + } + if (borderPtr->darkGC != None) { + Tk_FreeGC(display, borderPtr->darkGC); + } + if (borderPtr->lightGC != None) { + Tk_FreeGC(display, borderPtr->lightGC); + } + if (prevPtr == borderPtr) { + if (borderPtr->nextPtr == NULL) { + Tcl_DeleteHashEntry(borderPtr->hashPtr); + } else { + Tcl_SetHashValue(borderPtr->hashPtr, borderPtr->nextPtr); } - if (borderPtr->lightGC != None) { - Tk_FreeGC(display, borderPtr->lightGC); + } else { + while (prevPtr->nextPtr != borderPtr) { + prevPtr = prevPtr->nextPtr; } - Tcl_DeleteHashEntry(borderPtr->hashPtr); + prevPtr->nextPtr = borderPtr->nextPtr; + } + if (borderPtr->objRefCount == 0) { ckfree((char *) borderPtr); } } @@ -339,6 +476,106 @@ Tk_Free3DBorder(border) /* *---------------------------------------------------------------------- * + * Tk_Free3DBorderFromObj -- + * + * This procedure is called to release a border allocated by + * Tk_Alloc3DBorderFromObj. It does not throw away the Tcl_Obj *; + * it only gets rid of the hash table entry for this border + * and clears the cached value that is normally stored in the object. + * + * Results: + * None. + * + * Side effects: + * The reference count associated with the border represented by + * objPtr is decremented, and the border's resources are released + * to X if there are no remaining uses for it. + * + *---------------------------------------------------------------------- + */ + +void +Tk_Free3DBorderFromObj(tkwin, objPtr) + Tk_Window tkwin; /* The window this border lives in. Needed + * for the screen and colormap values. */ + Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */ +{ + Tk_Free3DBorder(Tk_Get3DBorderFromObj(tkwin, objPtr)); + FreeBorderObjProc(objPtr); +} + +/* + *--------------------------------------------------------------------------- + * + * FreeBorderObjProc -- + * + * This proc is called to release an object reference to a border. + * Called when the object's internal rep is released or when + * the cached borderPtr needs to be changed. + * + * Results: + * None. + * + * Side effects: + * The object reference count is decremented. When both it + * and the hash ref count go to zero, the border's resources + * are released. + * + *--------------------------------------------------------------------------- + */ + +static void +FreeBorderObjProc(objPtr) + Tcl_Obj *objPtr; /* The object we are releasing. */ +{ + TkBorder *borderPtr = (TkBorder *) objPtr->internalRep.twoPtrValue.ptr1; + + if (borderPtr != NULL) { + borderPtr->objRefCount--; + if ((borderPtr->objRefCount == 0) + && (borderPtr->resourceRefCount == 0)) { + ckfree((char *) borderPtr); + } + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL; + } +} + +/* + *--------------------------------------------------------------------------- + * + * DupBorderObjProc -- + * + * When a cached border object is duplicated, this is called to + * update the internal reps. + * + * Results: + * None. + * + * Side effects: + * The border's objRefCount is incremented and the internal rep + * of the copy is set to point to it. + * + *--------------------------------------------------------------------------- + */ + +static void +DupBorderObjProc(srcObjPtr, dupObjPtr) + Tcl_Obj *srcObjPtr; /* The object we are copying from. */ + Tcl_Obj *dupObjPtr; /* The object we are copying to. */ +{ + TkBorder *borderPtr = (TkBorder *) srcObjPtr->internalRep.twoPtrValue.ptr1; + + dupObjPtr->typePtr = srcObjPtr->typePtr; + dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) borderPtr; + + if (borderPtr != NULL) { + borderPtr->objRefCount++; + } +} + +/* + *---------------------------------------------------------------------- + * * Tk_SetBackgroundFromBorder -- * * Change the background of a window to one appropriate for a given @@ -366,6 +603,35 @@ Tk_SetBackgroundFromBorder(tkwin, border) /* *---------------------------------------------------------------------- * + * Tk_GetReliefFromObj -- + * + * Return an integer value based on the value of the objPtr. + * + * Results: + * The return value is a standard Tcl result. If an error occurs during + * conversion, an error message is left in the interpreter's result + * unless "interp" is NULL. + * + * Side effects: + * The object gets converted by Tcl_GetIndexFromObj. + * + *---------------------------------------------------------------------- + */ + +int +Tk_GetReliefFromObj(interp, objPtr, resultPtr) + Tcl_Interp *interp; /* Used for error reporting. */ + Tcl_Obj *objPtr; /* The object we are trying to get the + * value from. */ + int *resultPtr; /* Where to place the answer. */ +{ + return Tcl_GetIndexFromObj(interp, objPtr, reliefStrings, "relief", 0, + resultPtr); +} + +/* + *---------------------------------------------------------------------- + * * Tk_GetRelief -- * * Parse a relief description and return the corresponding @@ -408,8 +674,11 @@ Tk_GetRelief(interp, name, reliefPtr) } else if ((c == 's') && (strncmp(name, "sunken", length) == 0)) { *reliefPtr = TK_RELIEF_SUNKEN; } else { - sprintf(interp->result, "bad relief type \"%.50s\": must be %s", + char buf[200]; + + sprintf(buf, "bad relief type \"%.50s\": must be %s", name, "flat, groove, raised, ridge, solid, or sunken"); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; @@ -707,6 +976,17 @@ Tk_Fill3DRectangle(tkwin, drawable, border, x, y, width, if (relief == TK_RELIEF_FLAT) { borderWidth = 0; + } else { + /* + * We need to make this extra check, otherwise we will leave + * garbage in thin frames [Bug: 3596] + */ + if (width < 2*borderWidth) { + borderWidth = width/2; + } + if (height < 2*borderWidth) { + borderWidth = height/2; + } } doubleBorder = 2*borderWidth; @@ -783,10 +1063,11 @@ Tk_Fill3DPolygon(tkwin, drawable, border, pointPtr, numPoints, */ static void -BorderInit() +BorderInit(dispPtr) + TkDisplay * dispPtr; /* Used to access thread-specific data. */ { - initialized = 1; - Tcl_InitHashTable(&borderTable, sizeof(BorderKey)/sizeof(int)); + dispPtr->borderInit = 1; + Tcl_InitHashTable(&dispPtr->borderTable, TCL_STRING_KEYS); } /* @@ -948,3 +1229,181 @@ Intersect(a1Ptr, a2Ptr, b1Ptr, b2Ptr, iPtr) } return 0; } + +/* + *---------------------------------------------------------------------- + * + * Tk_Get3DBorderFromObj -- + * + * Returns the border referred to by a Tcl object. The border must + * already have been allocated via a call to Tk_Alloc3DBorderFromObj + * or Tk_Get3DBorder. + * + * Results: + * Returns the Tk_3DBorder that matches the tkwin and the string rep + * of the name of the border given in objPtr. + * + * Side effects: + * If the object is not already a border, the conversion will free + * any old internal representation. + * + *---------------------------------------------------------------------- + */ + +Tk_3DBorder +Tk_Get3DBorderFromObj(tkwin, objPtr) + Tk_Window tkwin; + Tcl_Obj *objPtr; /* The object whose string value selects + * a border. */ +{ + TkBorder *borderPtr = NULL; + Tcl_HashEntry *hashPtr; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + + if (objPtr->typePtr != &borderObjType) { + InitBorderObj(objPtr); + } + + /* + * If we are lucky (and the user doesn't use too many different + * displays, screens, or colormaps...) then the TkBorder + * structure we need will be cached in the internal + * representation of the Tcl_Obj. Check it out... + */ + + borderPtr = (TkBorder *) objPtr->internalRep.twoPtrValue.ptr1; + if ((borderPtr != NULL) + && (borderPtr->resourceRefCount > 0) + && (Tk_Screen(tkwin) == borderPtr->screen) + && (Tk_Colormap(tkwin) == borderPtr->colormap)) { + /* + * The object already points to the right border structure. + * Just return it. + */ + return (Tk_3DBorder) borderPtr; + } + + /* + * If we make it here, it means we aren't so lucky. Either there + * was no cached TkBorder in the Tcl_Obj, or the TkBorder that was + * there is for the wrong screen/colormap. Either way, we have + * to search for the right TkBorder. For each color name, there is + * linked list of TkBorder structures, one structure for each + * screen/colormap combination. The head of the linked list is + * recorded in a hash table (where the key is the color name) + * attached to the TkDisplay structure. Walk this list to find + * the right TkBorder structure. + */ + + hashPtr = Tcl_FindHashEntry(&dispPtr->borderTable, Tcl_GetString(objPtr)); + if (hashPtr == NULL) { + goto error; + } + for (borderPtr = (TkBorder *) Tcl_GetHashValue(hashPtr); + (borderPtr != NULL); borderPtr = borderPtr->nextPtr) { + if ((Tk_Screen(tkwin) == borderPtr->screen) + && (Tk_Colormap(tkwin) == borderPtr->colormap)) { + FreeBorderObjProc(objPtr); + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) borderPtr; + borderPtr->objRefCount++; + return (Tk_3DBorder) borderPtr; + } + } + + error: + panic("Tk_Get3DBorderFromObj called with non-existent border!"); + /* + * The following code isn't reached; it's just there to please compilers. + */ + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * InitBorderObj -- + * + * Attempt to generate a border internal form for the Tcl object + * "objPtr". + * + * Results: + * The return value is a standard Tcl result. If an error occurs during + * conversion, an error message is left in the interpreter's result + * unless "interp" is NULL. + * + * Side effects: + * If no error occurs, a blank internal format for a border value + * is intialized. The final form cannot be done without a Tk_Window. + * + *---------------------------------------------------------------------- + */ + +static void +InitBorderObj(objPtr) + Tcl_Obj *objPtr; /* The object to convert. */ +{ + Tcl_ObjType *typePtr; + + /* + * Free the old internalRep before setting the new one. + */ + + Tcl_GetString(objPtr); + typePtr = objPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(objPtr); + } + objPtr->typePtr = &borderObjType; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL; +} + +/* + *---------------------------------------------------------------------- + * + * TkDebugBorder -- + * + * This procedure returns debugging information about a border. + * + * Results: + * The return value is a list with one sublist for each TkBorder + * corresponding to "name". Each sublist has two elements that + * contain the resourceRefCount and objRefCount fields from the + * TkBorder structure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_Obj * +TkDebugBorder(tkwin, name) + Tk_Window tkwin; /* The window in which the border will be + * used (not currently used). */ + char *name; /* Name of the desired color. */ +{ + TkBorder *borderPtr; + Tcl_HashEntry *hashPtr; + Tcl_Obj *resultPtr, *objPtr; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + + resultPtr = Tcl_NewObj(); + hashPtr = Tcl_FindHashEntry(&dispPtr->borderTable, name); + if (hashPtr != NULL) { + borderPtr = (TkBorder *) Tcl_GetHashValue(hashPtr); + if (borderPtr == NULL) { + panic("TkDebugBorder found empty hash table entry"); + } + for ( ; (borderPtr != NULL); borderPtr = borderPtr->nextPtr) { + objPtr = Tcl_NewObj(); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewIntObj(borderPtr->resourceRefCount)); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewIntObj(borderPtr->objRefCount)); + Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); + } + } + return resultPtr; +} + + diff --git a/tk/generic/tk3d.h b/tk/generic/tk3d.h index 71115f2cf5f..c62cf12de5a 100644 --- a/tk/generic/tk3d.h +++ b/tk/generic/tk3d.h @@ -4,7 +4,7 @@ * Declarations of types and functions shared by the 3d border * module. * - * Copyright (c) 1996 by Sun Microsystems, Inc. + * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -23,13 +23,13 @@ #endif /* - * One of the following data structures is allocated for - * each 3-D border currently in use. Structures of this - * type are indexed by borderTable, so that a single - * structure can be shared for several uses. + * One of the following data structures is allocated for each 3-D border + * currently in use. Structures of this type are indexed by + * borderTable, so that a single structure can be shared for several + * uses. */ -typedef struct { +typedef struct TkBorder { Screen *screen; /* Screen on which the border will be used. */ Visual *visual; /* Visual for all windows and pixmaps using * the border. */ @@ -37,8 +37,18 @@ typedef struct { * the border will be used. */ Colormap colormap; /* Colormap out of which pixels are * allocated. */ - int refCount; /* Number of different users of - * this border. */ + int resourceRefCount; /* Number of active uses of this color (each + * active use corresponds to a call to + * Tk_Alloc3DBorderFromObj or Tk_Get3DBorder). + * If this count is 0, then this structure + * is no longer valid and it isn't present + * in borderTable: it is being kept around + * only because there are objects referring + * to it. The structure is freed when + * resourceRefCount and objRefCount are + * both 0. */ + int objRefCount; /* The number of Tcl objects that reference + * this structure. */ XColor *bgColorPtr; /* Background color (intensity * between lightColorPtr and * darkColorPtr). */ @@ -63,6 +73,11 @@ typedef struct { * haven't been allocated yet. */ Tcl_HashEntry *hashPtr; /* Entry in borderTable (needed in * order to delete structure). */ + struct TkBorder *nextPtr; /* Points to the next TkBorder structure with + * the same color name. Borders with the + * same name but different screens or + * colormaps are chained together off a + * single entry in borderTable. */ } TkBorder; @@ -85,3 +100,4 @@ EXTERN void TkpFreeBorder _ANSI_ARGS_((TkBorder *borderPtr)); # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TK3D */ + diff --git a/tk/generic/tkArgv.c b/tk/generic/tkArgv.c index b44939ed7c4..ee86ad75cd4 100644 --- a/tk/generic/tkArgv.c +++ b/tk/generic/tkArgv.c @@ -5,7 +5,7 @@ * argv-argc parsing. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -24,8 +24,8 @@ static Tk_ArgvInfo defaultTable[] = { {"-help", TK_ARGV_HELP, (char *) NULL, (char *) NULL, "Print summary of command-line options and abort"}, - {"-version", TK_ARGV_VERSION, (char *) NULL, (char *) NULL, - "Print version number and abort"}, + {"-version", TK_ARGV_VERSION, (char *) NULL, (char *) NULL, + "Print version number and abort"}, {NULL, TK_ARGV_END, (char *) NULL, (char *) NULL, (char *) NULL} }; @@ -47,7 +47,7 @@ static void PrintUsage _ANSI_ARGS_((Tcl_Interp *interp, * * Results: * The return value is a standard Tcl return value. If an - * error occurs then an error message is left in interp->result. + * error occurs then an error message is left in the interp's result. * Under normal conditions, both *argcPtr and *argv are modified * to return the arguments that couldn't be processed here (they * didn't match the option table, or followed an TK_ARGV_REST @@ -294,13 +294,17 @@ Tk_ParseArgv(interp, tkwin, argcPtr, argv, argTable, flags) argc -= 2; break; case TK_ARGV_VERSION: - Tcl_AppendResult(interp, "Tk version ", TK_VERSION, "-foundry-971110", + Tcl_AppendResult(interp, "Tk version ", TK_VERSION, "-snavigator-99r1", (char *) NULL); return TCL_ERROR; - default: - sprintf(interp->result, "bad argument type %d in Tk_ArgvInfo", + default: { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "bad argument type %d in Tk_ArgvInfo", infoPtr->type); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; + } } } @@ -334,7 +338,7 @@ Tk_ParseArgv(interp, tkwin, argcPtr, argv, argTable, flags) * Generate a help string describing command-line options. * * Results: - * Interp->result will be modified to hold a help string + * The interp's result will be modified to hold a help string * describing all the options in argTable, plus all those * in the default table unless TK_ARGV_NO_DEFAULTS is * specified in flags. @@ -359,7 +363,7 @@ PrintUsage(interp, argTable, flags) int width, i, numSpaces; #define NUM_SPACES 20 static char spaces[] = " "; - char tmp[30]; + char tmp[TCL_DOUBLE_SPACE]; /* * First, compute the width of the widest option key, so that we @@ -437,3 +441,4 @@ PrintUsage(interp, argTable, flags) (char *) NULL); } } + diff --git a/tk/generic/tkAtom.c b/tk/generic/tkAtom.c index 7bd2a1e80ff..45260d940e0 100644 --- a/tk/generic/tkAtom.c +++ b/tk/generic/tkAtom.c @@ -215,3 +215,4 @@ AtomInit(dispPtr) } } } + diff --git a/tk/generic/tkBind.c b/tk/generic/tkBind.c index 38a39b7e5b1..233f3c308c4 100644 --- a/tk/generic/tkBind.c +++ b/tk/generic/tkBind.c @@ -5,18 +5,22 @@ * with X events or sequences of X events. * * Copyright (c) 1989-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 1998 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id$ + * RCS: @(#) $Id$ */ #include "tkPort.h" #include "tkInt.h" +#ifdef __WIN32__ +#include "tkWinInt.h" +#endif + /* * File structure: * @@ -340,6 +344,8 @@ typedef struct BindInfo { PendingBinding *pendingList;/* The list of pending C bindings, kept in * case a C or Tcl binding causes the target * window to be deleted. */ + int deleted; /* 1 the application has been deleted but + * the structure has been preserved. */ } BindInfo; /* @@ -374,6 +380,7 @@ static Tcl_HashTable nameTable; /* keyArray hashed by keysym name. */ */ static int initialized = 0; +TCL_DECLARE_MUTEX(bindMutex) /* * A hash table is kept to map from the string names of event @@ -396,19 +403,15 @@ typedef struct { * e.g. for double-clicks. * TRIPLE - Non-zero means triplicate this event, * e.g. for triple-clicks. + * QUADRUPLE - Non-zero means quadruple this event, + * e.g. for 4-fold-clicks. + * MULT_CLICKS - Combination of all of above. */ #define DOUBLE 1 #define TRIPLE 2 - -/* - * The following special modifier mask bits are defined, to indicate - * logical modifiers such as Meta and Alt that may float among the - * actual modifier bits. - */ - -#define META_MASK (AnyModifier<<1) -#define ALT_MASK (AnyModifier<<2) +#define QUADRUPLE 4 +#define MULT_CLICKS 7 static ModInfo modArray[] = { {"Control", ControlMask, 0}, @@ -441,6 +444,7 @@ static ModInfo modArray[] = { {"M5", Mod5Mask, 0}, {"Double", 0, DOUBLE}, {"Triple", 0, TRIPLE}, + {"Quadruple", 0, QUADRUPLE}, {"Any", 0, 0}, /* Ignored: historical relic. */ {NULL, 0, 0} }; @@ -574,6 +578,20 @@ static int flagArray[TK_LASTEVENT] = { }; /* + * The following table is used to map between the location where an + * generated event should be queued and the string used to specify the + * location. + */ + +static TkStateMap queuePosition[] = { + {-1, "now"}, + {TCL_QUEUE_HEAD, "head"}, + {TCL_QUEUE_MARK, "mark"}, + {TCL_QUEUE_TAIL, "tail"}, + {-2, NULL} +}; + +/* * The following tables are used as a two-way map between X's internal * numeric values for fields in an XEvent and the strings used in Tcl. The * tables are used both when constructing an XEvent from user input and @@ -638,8 +656,6 @@ static PatSeq * FindSequence _ANSI_ARGS_((Tcl_Interp *interp, static void GetAllVirtualEvents _ANSI_ARGS_((Tcl_Interp *interp, VirtualEventTable *vetPtr)); static char * GetField _ANSI_ARGS_((char *p, char *copy, int size)); -static KeySym GetKeySym _ANSI_ARGS_((TkDisplay *dispPtr, - XEvent *eventPtr)); static void GetPatternString _ANSI_ARGS_((PatSeq *psPtr, Tcl_DString *dsPtr)); static int GetVirtualEvent _ANSI_ARGS_((Tcl_Interp *interp, @@ -647,17 +663,21 @@ static int GetVirtualEvent _ANSI_ARGS_((Tcl_Interp *interp, static Tk_Uid GetVirtualEventUid _ANSI_ARGS_((Tcl_Interp *interp, char *virtString)); static int HandleEventGenerate _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window main, int argc, char **argv)); -static void InitKeymapInfo _ANSI_ARGS_((TkDisplay *dispPtr)); + Tk_Window main, int objc, + Tcl_Obj *CONST objv[])); static void InitVirtualEventTable _ANSI_ARGS_(( VirtualEventTable *vetPtr)); static PatSeq * MatchPatterns _ANSI_ARGS_((TkDisplay *dispPtr, BindingTable *bindPtr, PatSeq *psPtr, PatSeq *bestPtr, ClientData *objectPtr, PatSeq **sourcePtrPtr)); +static int NameToWindow _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window main, Tcl_Obj *objPtr, + Tk_Window *tkwinPtr)); static int ParseEventDescription _ANSI_ARGS_((Tcl_Interp *interp, char **eventStringPtr, Pattern *patPtr, unsigned long *eventMaskPtr)); +static void DoWarp _ANSI_ARGS_((ClientData clientData)); /* * The following define is used as a short circuit for the callback @@ -705,37 +725,41 @@ TkBindInit(mainPtr) */ if (!initialized) { - Tcl_HashEntry *hPtr; - ModInfo *modPtr; - EventInfo *eiPtr; - int dummy; + Tcl_MutexLock(&bindMutex); + if (!initialized) { + Tcl_HashEntry *hPtr; + ModInfo *modPtr; + EventInfo *eiPtr; + int dummy; #ifdef REDO_KEYSYM_LOOKUP - KeySymInfo *kPtr; - - Tcl_InitHashTable(&keySymTable, TCL_STRING_KEYS); - Tcl_InitHashTable(&nameTable, TCL_ONE_WORD_KEYS); - for (kPtr = keyArray; kPtr->name != NULL; kPtr++) { - hPtr = Tcl_CreateHashEntry(&keySymTable, kPtr->name, &dummy); - Tcl_SetHashValue(hPtr, kPtr->value); - hPtr = Tcl_CreateHashEntry(&nameTable, (char *) kPtr->value, - &dummy); - Tcl_SetHashValue(hPtr, kPtr->name); - } + KeySymInfo *kPtr; + + Tcl_InitHashTable(&keySymTable, TCL_STRING_KEYS); + Tcl_InitHashTable(&nameTable, TCL_ONE_WORD_KEYS); + for (kPtr = keyArray; kPtr->name != NULL; kPtr++) { + hPtr = Tcl_CreateHashEntry(&keySymTable, kPtr->name, &dummy); + Tcl_SetHashValue(hPtr, kPtr->value); + hPtr = Tcl_CreateHashEntry(&nameTable, (char *) kPtr->value, + &dummy); + Tcl_SetHashValue(hPtr, kPtr->name); + } #endif /* REDO_KEYSYM_LOOKUP */ - Tcl_InitHashTable(&modTable, TCL_STRING_KEYS); - for (modPtr = modArray; modPtr->name != NULL; modPtr++) { - hPtr = Tcl_CreateHashEntry(&modTable, modPtr->name, &dummy); - Tcl_SetHashValue(hPtr, modPtr); - } + Tcl_InitHashTable(&modTable, TCL_STRING_KEYS); + for (modPtr = modArray; modPtr->name != NULL; modPtr++) { + hPtr = Tcl_CreateHashEntry(&modTable, modPtr->name, &dummy); + Tcl_SetHashValue(hPtr, modPtr); + } - Tcl_InitHashTable(&eventTable, TCL_STRING_KEYS); - for (eiPtr = eventArray; eiPtr->name != NULL; eiPtr++) { - hPtr = Tcl_CreateHashEntry(&eventTable, eiPtr->name, &dummy); - Tcl_SetHashValue(hPtr, eiPtr); + Tcl_InitHashTable(&eventTable, TCL_STRING_KEYS); + for (eiPtr = eventArray; eiPtr->name != NULL; eiPtr++) { + hPtr = Tcl_CreateHashEntry(&eventTable, eiPtr->name, &dummy); + Tcl_SetHashValue(hPtr, eiPtr); + } + initialized = 1; } - initialized = 1; + Tcl_MutexUnlock(&bindMutex); } mainPtr->bindingTable = Tk_CreateBindingTable(mainPtr->interp); @@ -746,6 +770,7 @@ TkBindInit(mainPtr) bindInfoPtr->screenInfo.curScreenIndex = -1; bindInfoPtr->screenInfo.bindingDepth = 0; bindInfoPtr->pendingList = NULL; + bindInfoPtr->deleted = 0; mainPtr->bindInfo = (TkBindInfo) bindInfoPtr; TkpInitializeMenuBindings(mainPtr->interp, mainPtr->bindingTable); @@ -779,6 +804,8 @@ TkBindFree(mainPtr) bindInfoPtr = (BindInfo *) mainPtr->bindInfo; DeleteVirtualEventTable(&bindInfoPtr->virtualEventTable); + bindInfoPtr->deleted = 1; + Tcl_EventuallyFree((ClientData) bindInfoPtr, Tcl_Free); mainPtr->bindInfo = NULL; } @@ -791,7 +818,7 @@ TkBindFree(mainPtr) * * Results: * The return value is a token for the new table, which must - * be passed to procedures like Tk_CreatBinding. + * be passed to procedures like Tk_CreateBinding. * * Side effects: * Memory is allocated for the new table. @@ -893,7 +920,7 @@ Tk_DeleteBindingTable(bindingTable) * Results: * The return value is 0 if an error occurred while setting * up the binding. In this case, an error message will be - * left in interp->result. If all went well then the return + * left in the interp's result. If all went well then the return * value is a mask of the event types that must be made * available to Tk_BindEvent in order to properly detect when * this binding triggers. This value can be used to determine @@ -998,7 +1025,7 @@ Tk_CreateBinding(interp, bindingTable, object, eventString, command, append) * Results: * The return value is 0 if an error occurred while setting * up the binding. In this case, an error message will be - * left in interp->result. If all went well then the return + * left in the interp's result. If all went well then the return * value is a mask of the event types that must be made * available to Tk_BindEvent in order to properly detect when * this binding triggers. This value can be used to determine @@ -1082,7 +1109,7 @@ TkCreateBindingProcedure(interp, bindingTable, object, eventString, * * Results: * The result is a standard Tcl return value. If an error - * occurs then interp->result will contain an error message. + * occurs then the interp's result will contain an error message. * * Side effects: * The binding given by object and eventString is removed @@ -1177,7 +1204,7 @@ Tk_DeleteBinding(interp, bindingTable, object, eventString) * given by bindingTable. If there is no binding for * eventString, or if eventString is improperly formed, * then NULL is returned and an error message is left in - * interp->result. The return value is semi-static: it + * the interp's result. The return value is semi-static: it * will persist until the binding is changed or deleted. * * Side effects: @@ -1220,7 +1247,7 @@ Tk_GetBinding(interp, bindingTable, object, eventString) * associated with a given object. * * Results: - * There is no return value. Interp->result is modified to + * There is no return value. The interp's result is modified to * hold a Tcl list with one entry for each binding associated * with object in bindingTable. Each entry in the list * contains the event string associated with one binding. @@ -1384,9 +1411,9 @@ Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr) { BindingTable *bindPtr; TkDisplay *dispPtr; + ScreenInfo *screenPtr; BindInfo *bindInfoPtr; TkDisplay *oldDispPtr; - ScreenInfo *screenPtr; XEvent *ringPtr; PatSeq *vMatchDetailList, *vMatchNoDetailList; int flags, oldScreen, i, deferModal; @@ -1496,7 +1523,7 @@ Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr) detail.clientData = 0; flags = flagArray[ringPtr->type]; if (flags & KEY) { - detail.keySym = GetKeySym(dispPtr, ringPtr); + detail.keySym = TkpGetKeySym(dispPtr, ringPtr); if (detail.keySym == NoSymbol) { detail.keySym = 0; } @@ -1617,12 +1644,12 @@ Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr) unsigned int oldSize, newSize; oldSize = sizeof(staticPending) - - sizeof(staticPending.matchArray) - + matchSpace * sizeof(PatSeq*); + - sizeof(staticPending.matchArray) + + matchSpace * sizeof(PatSeq*); matchSpace *= 2; newSize = sizeof(staticPending) - - sizeof(staticPending.matchArray) - + matchSpace * sizeof(PatSeq*); + - sizeof(staticPending.matchArray) + + matchSpace * sizeof(PatSeq*); new = (PendingBinding *) ckalloc(newSize); memcpy((VOID *) new, (VOID *) pendingPtr, oldSize); if (pendingPtr != &staticPending) { @@ -1653,7 +1680,7 @@ Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr) * * There are two tricks here: * 1. Bindings can be invoked from in the middle of Tcl commands, - * where interp->result is significant (for example, a widget + * where the interp's result is significant (for example, a widget * might be deleted because of an error in creating it, so the * result contains an error message that is eventually going to * be returned by the creating command). To preserve the result, @@ -1684,6 +1711,13 @@ Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr) } if (matchCount > 0) { + /* + * Remember the list of pending C binding callbacks, so we can mark + * them as deleted and not call them if the act of evaluating a C + * or Tcl binding deletes a C binding callback or even the whole + * window. + */ + pendingPtr->nextPtr = bindInfoPtr->pendingList; pendingPtr->tkwin = tkwin; pendingPtr->deleted = 0; @@ -1703,10 +1737,20 @@ Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr) end = p + Tcl_DStringLength(&scripts); i = 0; + /* + * Be carefule when dereferencing screenPtr or bindInfoPtr. If we + * evaluate something that destroys ".", bindInfoPtr would have been + * freed, but we can tell that by first checking to see if + * winPtr->mainPtr == NULL. + */ + + Tcl_Preserve((ClientData) bindInfoPtr); while (p < end) { int code; - screenPtr->bindingDepth++; + if (!bindInfoPtr->deleted) { + screenPtr->bindingDepth++; + } Tcl_AllowExceptions(interp); if (*p == '\0') { @@ -1732,7 +1776,10 @@ Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr) p += strlen(p); } p++; - screenPtr->bindingDepth--; + + if (!bindInfoPtr->deleted) { + screenPtr->bindingDepth--; + } if (code != TCL_OK) { if (code == TCL_CONTINUE) { /* @@ -1762,8 +1809,8 @@ Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr) } } - if ((screenPtr->bindingDepth != 0) && - ((oldDispPtr != screenPtr->curDispPtr) + if (!bindInfoPtr->deleted && (screenPtr->bindingDepth != 0) + && ((oldDispPtr != screenPtr->curDispPtr) || (oldScreen != screenPtr->curScreenIndex))) { /* @@ -1780,19 +1827,27 @@ Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr) Tcl_DStringFree(&scripts); if (matchCount > 0) { - PendingBinding **curPtrPtr; + if (!bindInfoPtr->deleted) { + /* + * Delete the pending list from the list of pending scripts + * for this window. + */ + + PendingBinding **curPtrPtr; - for (curPtrPtr = &bindInfoPtr->pendingList; ; ) { - if (*curPtrPtr == pendingPtr) { - *curPtrPtr = pendingPtr->nextPtr; - break; + for (curPtrPtr = &bindInfoPtr->pendingList; ; ) { + if (*curPtrPtr == pendingPtr) { + *curPtrPtr = pendingPtr->nextPtr; + break; + } + curPtrPtr = &(*curPtrPtr)->nextPtr; } - curPtrPtr = &(*curPtrPtr)->nextPtr; } if (pendingPtr != &staticPending) { ckfree((char *) pendingPtr); } } + Tcl_Release((ClientData) bindInfoPtr); } /* @@ -2016,6 +2071,14 @@ MatchPatterns(dispPtr, bindPtr, psPtr, bestPtr, objectPtr, sourcePtrPtr) if ((modMask & ALT_MASK) && (dispPtr->altModMask != 0)) { modMask = (modMask & ~ALT_MASK) | dispPtr->altModMask; } + + if ((state & META_MASK) && (dispPtr->metaModMask != 0)) { + state = (state & ~META_MASK) | dispPtr->metaModMask; + } + if ((state & ALT_MASK) && (dispPtr->altModMask != 0)) { + state = (state & ~ALT_MASK) | dispPtr->altModMask; + } + if ((state & modMask) != modMask) { goto nextSequence; } @@ -2167,7 +2230,8 @@ MatchPatterns(dispPtr, bindPtr, psPtr, bestPtr, objectPtr, sourcePtrPtr) bestPtr = matchPtr; bestSourcePtr = sourcePtr; - nextSequence: continue; + nextSequence: + continue; } *sourcePtrPtr = bestSourcePtr; @@ -2211,8 +2275,11 @@ ExpandPercents(winPtr, before, eventPtr, keySym, dsPtr) int number, flags, length; #define NUM_SIZE 40 char *string; + Tcl_DString buf; char numStorage[NUM_SIZE+1]; + Tcl_DStringInit(&buf); + if (eventPtr->type < TK_LASTEVENT) { flags = flagArray[eventPtr->type]; } else { @@ -2246,8 +2313,10 @@ ExpandPercents(winPtr, before, eventPtr, keySym, dsPtr) number = eventPtr->xany.serial; goto doNumber; case 'a': - TkpPrintWindowId(numStorage, eventPtr->xconfigure.above); - string = numStorage; + if (flags & CONFIG) { + TkpPrintWindowId(numStorage, eventPtr->xconfigure.above); + string = numStorage; + } goto doString; case 'b': number = eventPtr->xbutton.button; @@ -2361,37 +2430,8 @@ ExpandPercents(winPtr, before, eventPtr, keySym, dsPtr) goto doNumber; case 'A': if (flags & KEY) { - int numChars; - - /* - * If we're using input methods and this is a keypress - * event, invoke XmbTkFindStateString. Otherwise just use - * the older XTkFindStateString. - */ - -#ifdef TK_USE_INPUT_METHODS - Status status; - if ((winPtr->inputContext != NULL) - && (eventPtr->type == KeyPress)) { - numChars = XmbLookupString(winPtr->inputContext, - &eventPtr->xkey, numStorage, NUM_SIZE, - (KeySym *) NULL, &status); - if ((status != XLookupChars) - && (status != XLookupBoth)) { - numChars = 0; - } - } else { - numChars = XLookupString(&eventPtr->xkey, numStorage, - NUM_SIZE, (KeySym *) NULL, - (XComposeStatus *) NULL); - } -#else /* TK_USE_INPUT_METHODS */ - numChars = XLookupString(&eventPtr->xkey, numStorage, - NUM_SIZE, (KeySym *) NULL, - (XComposeStatus *) NULL); -#endif /* TK_USE_INPUT_METHODS */ - numStorage[numChars] = '\0'; - string = numStorage; + Tcl_DStringFree(&buf); + string = TkpGetString(winPtr, eventPtr, &buf); } goto doString; case 'B': @@ -2492,6 +2532,7 @@ ExpandPercents(winPtr, before, eventPtr, keySym, dsPtr) Tcl_DStringSetLength(dsPtr, length + spaceNeeded); before += 2; } + Tcl_DStringFree(&buf); } /* @@ -2524,7 +2565,7 @@ ChangeScreen(interp, dispName, screenIndex) { Tcl_DString cmd; int code; - char screen[30]; + char screen[TCL_INTEGER_SPACE]; Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, "tkScreenChanged ", 16); @@ -2558,87 +2599,96 @@ ChangeScreen(interp, dispName, screenIndex) */ int -Tk_EventCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ +Tk_EventObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - int i; - size_t length; - char *option; + int index; Tk_Window tkwin; VirtualEventTable *vetPtr; TkBindInfo bindInfo; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg1?\"", (char *) NULL); - return TCL_ERROR; - } - - option = argv[1]; - length = strlen(option); - if (length == 0) { - goto badopt; - } + static char *optionStrings[] = { + "add", "delete", "generate", "info", + NULL + }; + enum options { + EVENT_ADD, EVENT_DELETE, EVENT_GENERATE, EVENT_INFO + }; tkwin = (Tk_Window) clientData; bindInfo = ((TkWindow *) tkwin)->mainPtr->bindInfo; vetPtr = &((BindInfo *) bindInfo)->virtualEventTable; - if (strncmp(option, "add", length) == 0) { - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " add virtual sequence ?sequence ...?\"", (char *) NULL); - return TCL_ERROR; - } - for (i = 3; i < argc; i++) { - if (CreateVirtualEvent(interp, vetPtr, argv[2], argv[i]) - != TCL_OK) { + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + + switch ((enum options) index) { + case EVENT_ADD: { + int i; + char *name, *event; + + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, + "virtual sequence ?sequence ...?"); return TCL_ERROR; } + name = Tcl_GetStringFromObj(objv[2], NULL); + for (i = 3; i < objc; i++) { + event = Tcl_GetStringFromObj(objv[i], NULL); + if (CreateVirtualEvent(interp, vetPtr, name, event) != TCL_OK) { + return TCL_ERROR; + } + } + break; } - } else if (strncmp(option, "delete", length) == 0) { - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " delete virtual ?sequence sequence ...?\"", - (char *) NULL); - return TCL_ERROR; - } - if (argc == 3) { - return DeleteVirtualEvent(interp, vetPtr, argv[2], NULL); - } - for (i = 3; i < argc; i++) { - if (DeleteVirtualEvent(interp, vetPtr, argv[2], argv[i]) - != TCL_OK) { + case EVENT_DELETE: { + int i; + char *name, *event; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, + "virtual ?sequence sequence ...?"); return TCL_ERROR; } + name = Tcl_GetStringFromObj(objv[2], NULL); + if (objc == 3) { + return DeleteVirtualEvent(interp, vetPtr, name, NULL); + } + for (i = 3; i < objc; i++) { + event = Tcl_GetStringFromObj(objv[i], NULL); + if (DeleteVirtualEvent(interp, vetPtr, name, event) != TCL_OK) { + return TCL_ERROR; + } + } + break; } - } else if (strncmp(option, "generate", length) == 0) { - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " generate window event ?options?\"", (char *) NULL); - return TCL_ERROR; + case EVENT_GENERATE: { + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, "window event ?options?"); + return TCL_ERROR; + } + return HandleEventGenerate(interp, tkwin, objc - 2, objv + 2); } - return HandleEventGenerate(interp, tkwin, argc - 2, argv + 2); - } else if (strncmp(option, "info", length) == 0) { - if (argc == 2) { - GetAllVirtualEvents(interp, vetPtr); - return TCL_OK; - } else if (argc == 3) { - return GetVirtualEvent(interp, vetPtr, argv[2]); - } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " info ?virtual?\"", (char *) NULL); - return TCL_ERROR; + case EVENT_INFO: { + if (objc == 2) { + GetAllVirtualEvents(interp, vetPtr); + return TCL_OK; + } else if (objc == 3) { + return GetVirtualEvent(interp, vetPtr, + Tcl_GetStringFromObj(objv[2], NULL)); + } else { + Tcl_WrongNumArgs(interp, 2, objv, "?virtual?"); + return TCL_ERROR; + } } - } else { - badopt: - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": should be add, delete, generate, info", (char *) NULL); - return TCL_ERROR; } return TCL_OK; } @@ -2725,8 +2775,8 @@ DeleteVirtualEventTable(vetPtr) * Results: * The return value is TCL_ERROR if an error occured while * creating the virtual binding. In this case, an error message - * will be left in interp->result. If all went well then the return - * value is TCL_OK. + * will be left in the interp's result. If all went well then the + * return value is TCL_OK. * * Side effects: * The virtual event may cause future calls to Tk_BindEvent to @@ -2831,7 +2881,7 @@ CreateVirtualEvent(interp, vetPtr, virtString, eventString) * * Results: * The result is a standard Tcl return value. If an error - * occurs then interp->result will contain an error message. + * occurs then the interp's result will contain an error message. * It is not an error to attempt to delete a virtual event that * does not exist or a definition that does not exist. * @@ -2883,7 +2933,10 @@ DeleteVirtualEvent(interp, vetPtr, virtString, eventString) eventPSPtr = FindSequence(interp, &vetPtr->patternTable, NULL, eventString, 0, 0, &eventMask); if (eventPSPtr == NULL) { - return (interp->result[0] != '\0') ? TCL_ERROR : TCL_OK; + char *string; + + string = Tcl_GetStringResult(interp); + return (string[0] != '\0') ? TCL_ERROR : TCL_OK; } } @@ -2924,7 +2977,7 @@ DeleteVirtualEvent(interp, vetPtr, virtString, eventString) } else { for ( ; ; prevPtr = prevPtr->nextSeqPtr) { if (prevPtr == NULL) { - panic("Tk_DeleteVirtualEvent couldn't find on hash chain"); + panic("DeleteVirtualEvent couldn't find on hash chain"); } if (prevPtr->nextSeqPtr == psPtr) { prevPtr->nextSeqPtr = psPtr->nextSeqPtr; @@ -2985,12 +3038,12 @@ DeleteVirtualEvent(interp, vetPtr, virtString, eventString) * given virtual event. * * Results: - * The return value is TCL_OK and interp->result is filled with the + * The return value is TCL_OK and the interp's result is filled with the * string representation of the physical events associated with the * virtual event; if there are no physical events for the given virtual - * event, interp->result is filled with and empty string. If the + * event, the interp's result is filled with and empty string. If the * virtual event string is improperly formed, then TCL_ERROR is - * returned and an error message is left in interp->result. + * returned and an error message is left in the interp's result. * * Side effects: * None. @@ -3042,7 +3095,7 @@ GetVirtualEvent(interp, vetPtr, virtString) * event defined. * * Results: - * There is no return value. Interp->result is modified to + * There is no return value. The interp's result is modified to * hold a Tcl list with one entry for each virtual event in * nameTable. * @@ -3111,56 +3164,75 @@ GetAllVirtualEvents(interp, vetPtr) *--------------------------------------------------------------------------- */ static int -HandleEventGenerate(interp, mainwin, argc, argv) - Tcl_Interp *interp; /* Interp for error messages and name lookup. */ - Tk_Window mainwin; /* Main window associated with interp. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ +HandleEventGenerate(interp, mainWin, objc, objv) + Tcl_Interp *interp; /* Interp for errors return and name lookup. */ + Tk_Window mainWin; /* Main window associated with interp. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { + XEvent event; + char *name, *p, *windowName; + int count, flags, synch, i, number, warp; + Tcl_QueuePosition pos; Pattern pat; - Tk_Window tkwin; - char *p; + Tk_Window tkwin, tkwin2; + TkWindow *mainPtr; unsigned long eventMask; - int count, i, state, flags, synch; - Tcl_QueuePosition pos; - XEvent event; + static char *fieldStrings[] = { + "-when", "-above", "-borderwidth", "-button", + "-count", "-delta", "-detail", "-focus", + "-height", + "-keycode", "-keysym", "-mode", "-override", + "-place", "-root", "-rootx", "-rooty", + "-sendevent", "-serial", "-state", "-subwindow", + "-time", "-warp", "-width", "-window", + "-x", "-y", NULL + }; + enum field { + EVENT_WHEN, EVENT_ABOVE, EVENT_BORDER, EVENT_BUTTON, + EVENT_COUNT, EVENT_DELTA, EVENT_DETAIL, EVENT_FOCUS, + EVENT_HEIGHT, + EVENT_KEYCODE, EVENT_KEYSYM, EVENT_MODE, EVENT_OVERRIDE, + EVENT_PLACE, EVENT_ROOT, EVENT_ROOTX, EVENT_ROOTY, + EVENT_SEND, EVENT_SERIAL, EVENT_STATE, EVENT_SUBWINDOW, + EVENT_TIME, EVENT_WARP, EVENT_WIDTH, EVENT_WINDOW, + EVENT_X, EVENT_Y + }; + + windowName = Tcl_GetStringFromObj(objv[0], NULL); + if (!windowName[0]) { + tkwin = mainWin; + } else if (NameToWindow(interp, mainWin, objv[0], &tkwin) != TCL_OK) { + return TCL_ERROR; + } - if (argv[0][0] == '.') { - tkwin = Tk_NameToWindow(interp, argv[0], mainwin); - if (tkwin == NULL) { - return TCL_ERROR; - } - } else { - if (TkpScanWindowId(NULL, argv[0], &i) != TCL_OK) { - Tcl_AppendResult(interp, "bad window name/identifier \"", - argv[0], "\"", (char *) NULL); - return TCL_ERROR; - } - tkwin = Tk_IdToWindow(Tk_Display(mainwin), (Window) i); - if ((tkwin == NULL) || (((TkWindow *) mainwin)->mainPtr - != ((TkWindow *) tkwin)->mainPtr)) { - Tcl_AppendResult(interp, "window id \"", argv[0], - "\" doesn't exist in this application", (char *) NULL); - return TCL_ERROR; - } + mainPtr = (TkWindow *) mainWin; + if ((tkwin == NULL) + || (mainPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr)) { + char *name; + + name = Tcl_GetStringFromObj(objv[0], NULL); + Tcl_AppendResult(interp, "window id \"", name, + "\" doesn't exist in this application", (char *) NULL); + return TCL_ERROR; } - p = argv[1]; + name = Tcl_GetStringFromObj(objv[1], NULL); + + p = name; + eventMask = 0; count = ParseEventDescription(interp, &p, &pat, &eventMask); if (count == 0) { return TCL_ERROR; } if (count != 1) { - interp->result = "Double or Triple modifier not allowed"; + Tcl_SetResult(interp, "Double or Triple modifier not allowed", + TCL_STATIC); return TCL_ERROR; } if (*p != '\0') { - interp->result = "only one event specification allowed"; - return TCL_ERROR; - } - if (argc & 1) { - Tcl_AppendResult(interp, "value for \"", argv[argc - 1], - "\" missing", (char *) NULL); + Tcl_SetResult(interp, "only one event specification allowed", + TCL_STATIC); return TCL_ERROR; } @@ -3168,41 +3240,18 @@ HandleEventGenerate(interp, mainwin, argc, argv) event.xany.type = pat.eventType; event.xany.serial = NextRequest(Tk_Display(tkwin)); event.xany.send_event = False; - event.xany.window = Tk_WindowId(tkwin); + if (windowName[0]) { + event.xany.window = Tk_WindowId(tkwin); + } else { + event.xany.window = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); + } event.xany.display = Tk_Display(tkwin); flags = flagArray[event.xany.type]; if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { event.xkey.state = pat.needMods; if ((flags & KEY) && (event.xany.type != MouseWheelEvent)) { - /* - * When mapping from a keysym to a keycode, need information about - * the modifier state that should be used so that when they call - * XKeycodeToKeysym taking into account the xkey.state, they will - * get back the original keysym. - */ - - if (pat.detail.keySym == NoSymbol) { - event.xkey.keycode = 0; - } else { - event.xkey.keycode = XKeysymToKeycode(event.xany.display, - pat.detail.keySym); - } - if (event.xkey.keycode != 0) { - for (state = 0; state < 4; state++) { - if (XKeycodeToKeysym(event.xany.display, - event.xkey.keycode, state) == pat.detail.keySym) { - if (state & 1) { - event.xkey.state |= ShiftMask; - } - if (state & 2) { - TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - event.xkey.state |= dispPtr->modeModMask; - } - break; - } - } - } + TkpSetKeycodeAndState(tkwin, pat.detail.keySym, &event); } else if (flags & BUTTON) { event.xbutton.button = pat.detail.button; } else if (flags & VIRTUAL) { @@ -3219,383 +3268,495 @@ HandleEventGenerate(interp, mainwin, argc, argv) */ synch = 1; + warp = 0; pos = TCL_QUEUE_TAIL; - for (i = 2; i < argc; i += 2) { - char *field, *value; - Tk_Window tkwin2; - int number; - KeySym keysym; + for (i = 2; i < objc; i += 2) { + Tcl_Obj *optionPtr, *valuePtr; + int index; - field = argv[i]; - value = argv[i+1]; - - if (strcmp(field, "-when") == 0) { - if (strcmp(value, "now") == 0) { - synch = 1; - } else if (strcmp(value, "head") == 0) { - pos = TCL_QUEUE_HEAD; - synch = 0; - } else if (strcmp(value, "mark") == 0) { - pos = TCL_QUEUE_MARK; - synch = 0; - } else if (strcmp(value, "tail") == 0) { - pos = TCL_QUEUE_TAIL; - synch = 0; - } else { - Tcl_AppendResult(interp, "bad position \"", value, - "\": should be now, head, mark, tail", (char *) NULL); - return TCL_ERROR; - } - } else if (strcmp(field, "-above") == 0) { - if (value[0] == '.') { - tkwin2 = Tk_NameToWindow(interp, value, mainwin); - if (tkwin2 == NULL) { - return TCL_ERROR; - } - number = Tk_WindowId(tkwin2); - } else if (TkpScanWindowId(interp, value, &number) - != TCL_OK) { - return TCL_ERROR; - } - if (flags & CONFIG) { - event.xconfigure.above = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-borderwidth") == 0) { - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & (CREATE|CONFIG)) { - event.xcreatewindow.border_width = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-button") == 0) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & BUTTON) { - event.xbutton.button = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-count") == 0) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & EXPOSE) { - event.xexpose.count = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-delta") == 0) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if ((flags & KEY) && (event.xkey.type == MouseWheelEvent)) { - event.xkey.keycode = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-detail") == 0) { - number = TkFindStateNum(interp, field, notifyDetail, value); - if (number < 0) { - return TCL_ERROR; - } - if (flags & FOCUS) { - event.xfocus.detail = number; - } else if (flags & CROSSING) { - event.xcrossing.detail = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-focus") == 0) { - if (Tcl_GetBoolean(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & CROSSING) { - event.xcrossing.focus = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-height") == 0) { - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if (flags & EXPOSE) { - event.xexpose.height = number; - } else if (flags & CONFIG) { - event.xconfigure.height = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-keycode") == 0) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; - } - if ((flags & KEY) && (event.xkey.type != MouseWheelEvent)) { - event.xkey.keycode = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-keysym") == 0) { - keysym = TkStringToKeysym(value); - if (keysym == NoSymbol) { - Tcl_AppendResult(interp, "unknown keysym \"", value, - "\"", (char *) NULL); - return TCL_ERROR; - } + optionPtr = objv[i]; + valuePtr = objv[i + 1]; + + if (Tcl_GetIndexFromObj(interp, optionPtr, fieldStrings, "option", + TCL_EXACT, &index) != TCL_OK) { + return TCL_ERROR; + } + if (objc & 1) { /* - * When mapping from a keysym to a keycode, need information about - * the modifier state that should be used so that when they call - * XKeycodeToKeysym taking into account the xkey.state, they will - * get back the original keysym. + * This test occurs after Tcl_GetIndexFromObj() so that + * "event generate <Button> -xyz" will return the error message + * that "-xyz" is a bad option, rather than that the value + * for "-xyz" is missing. */ - number = XKeysymToKeycode(event.xany.display, keysym); - if (number == 0) { - Tcl_AppendResult(interp, "no keycode for keysym \"", value, - "\"", (char *) NULL); - return TCL_ERROR; - } - for (state = 0; state < 4; state++) { - if (XKeycodeToKeysym(event.xany.display, (unsigned) number, - state) == keysym) { - if (state & 1) { - event.xkey.state |= ShiftMask; - } - if (state & 2) { - TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - event.xkey.state |= dispPtr->modeModMask; - } - break; + Tcl_AppendResult(interp, "value for \"", + Tcl_GetStringFromObj(optionPtr, NULL), "\" missing", + (char *) NULL); + return TCL_ERROR; + } + + switch ((enum field) index) { + case EVENT_WARP: { + if (Tcl_GetBooleanFromObj(interp, valuePtr, &warp) != TCL_OK) { + return TCL_ERROR; } - } - if ((flags & KEY) && (event.xkey.type != MouseWheelEvent)) { - event.xkey.keycode = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-mode") == 0) { - number = TkFindStateNum(interp, field, notifyMode, value); - if (number < 0) { - return TCL_ERROR; - } - if (flags & CROSSING) { - event.xcrossing.mode = number; - } else if (flags & FOCUS) { - event.xfocus.mode = number; - } else { - goto badopt; + if (!(flags & (KEY_BUTTON_MOTION_VIRTUAL))) { + goto badopt; + } + break; } - } else if (strcmp(field, "-override") == 0) { - if (Tcl_GetBoolean(interp, value, &number) != TCL_OK) { - return TCL_ERROR; + case EVENT_WHEN: { + pos = (Tcl_QueuePosition) TkFindStateNumObj(interp, optionPtr, + queuePosition, valuePtr); + if ((int) pos < -1) { + return TCL_ERROR; + } + synch = 0; + if ((int) pos == -1) { + synch = 1; + } + break; } - if (flags & CREATE) { - event.xcreatewindow.override_redirect = number; - } else if (flags & MAP) { - event.xmap.override_redirect = number; - } else if (flags & REPARENT) { - event.xreparent.override_redirect = number; - } else if (flags & CONFIG) { - event.xconfigure.override_redirect = number; - } else { - goto badopt; + case EVENT_ABOVE: { + if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) { + return TCL_ERROR; + } + if (flags & CONFIG) { + event.xconfigure.above = Tk_WindowId(tkwin2); + } else { + goto badopt; + } + break; } - } else if (strcmp(field, "-place") == 0) { - number = TkFindStateNum(interp, field, circPlace, value); - if (number < 0) { - return TCL_ERROR; + case EVENT_BORDER: { + if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) { + return TCL_ERROR; + } + if (flags & (CREATE|CONFIG)) { + event.xcreatewindow.border_width = number; + } else { + goto badopt; + } + break; } - if (flags & CIRC) { - event.xcirculate.place = number; - } else { - goto badopt; + case EVENT_BUTTON: { + if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { + return TCL_ERROR; + } + if (flags & BUTTON) { + event.xbutton.button = number; + } else { + goto badopt; + } + break; } - } else if (strcmp(field, "-root") == 0) { - if (value[0] == '.') { - tkwin2 = Tk_NameToWindow(interp, value, mainwin); - if (tkwin2 == NULL) { + case EVENT_COUNT: { + if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { return TCL_ERROR; } - number = Tk_WindowId(tkwin2); - } else if (TkpScanWindowId(interp, value, &number) - != TCL_OK) { - return TCL_ERROR; + if (flags & EXPOSE) { + event.xexpose.count = number; + } else { + goto badopt; + } + break; } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.root = number; - } else { - goto badopt; + case EVENT_DELTA: { + if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { + return TCL_ERROR; + } + if ((flags & KEY) && (event.xkey.type == MouseWheelEvent)) { + event.xkey.keycode = number; + } else { + goto badopt; + } + break; } - } else if (strcmp(field, "-rootx") == 0) { - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; + case EVENT_DETAIL: { + number = TkFindStateNumObj(interp, optionPtr, notifyDetail, + valuePtr); + if (number < 0) { + return TCL_ERROR; + } + if (flags & FOCUS) { + event.xfocus.detail = number; + } else if (flags & CROSSING) { + event.xcrossing.detail = number; + } else { + goto badopt; + } + break; } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.x_root = number; - } else { - goto badopt; + case EVENT_FOCUS: { + if (Tcl_GetBooleanFromObj(interp, valuePtr, &number) != TCL_OK) { + return TCL_ERROR; + } + if (flags & CROSSING) { + event.xcrossing.focus = number; + } else { + goto badopt; + } + break; } - } else if (strcmp(field, "-rooty") == 0) { - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; + case EVENT_HEIGHT: { + if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) { + return TCL_ERROR; + } + if (flags & EXPOSE) { + event.xexpose.height = number; + } else if (flags & CONFIG) { + event.xconfigure.height = number; + } else { + goto badopt; + } + break; } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.y_root = number; - } else { - goto badopt; + case EVENT_KEYCODE: { + if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { + return TCL_ERROR; + } + if ((flags & KEY) && (event.xkey.type != MouseWheelEvent)) { + event.xkey.keycode = number; + } else { + goto badopt; + } + break; } - } else if (strcmp(field, "-sendevent") == 0) { - if (isdigit(UCHAR(value[0]))) { - /* - * Allow arbitrary integer values for the field; they - * are needed by a few of the tests in the Tk test suite. - */ - - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { + case EVENT_KEYSYM: { + KeySym keysym; + char *value; + + value = Tcl_GetStringFromObj(valuePtr, NULL); + keysym = TkStringToKeysym(value); + if (keysym == NoSymbol) { + Tcl_AppendResult(interp, "unknown keysym \"", value, "\"", + (char *) NULL); return TCL_ERROR; } - } else { - if (Tcl_GetBoolean(interp, value, &number) != TCL_OK) { + + TkpSetKeycodeAndState(tkwin, keysym, &event); + if (event.xkey.keycode == 0) { + Tcl_AppendResult(interp, "no keycode for keysym \"", value, + "\"", (char *) NULL); return TCL_ERROR; } + if (!(flags & KEY) || (event.xkey.type == MouseWheelEvent)) { + goto badopt; + } + break; } - event.xany.send_event = number; - } else if (strcmp(field, "-serial") == 0) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; + case EVENT_MODE: { + number = TkFindStateNumObj(interp, optionPtr, notifyMode, + valuePtr); + if (number < 0) { + return TCL_ERROR; + } + if (flags & CROSSING) { + event.xcrossing.mode = number; + } else if (flags & FOCUS) { + event.xfocus.mode = number; + } else { + goto badopt; + } + break; } - event.xany.serial = number; - } else if (strcmp(field, "-state") == 0) { - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { + case EVENT_OVERRIDE: { + if (Tcl_GetBooleanFromObj(interp, valuePtr, &number) != TCL_OK) { return TCL_ERROR; } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { - event.xkey.state = number; + if (flags & CREATE) { + event.xcreatewindow.override_redirect = number; + } else if (flags & MAP) { + event.xmap.override_redirect = number; + } else if (flags & REPARENT) { + event.xreparent.override_redirect = number; + } else if (flags & CONFIG) { + event.xconfigure.override_redirect = number; } else { - event.xcrossing.state = number; + goto badopt; } - } else if (flags & VISIBILITY) { - number = TkFindStateNum(interp, field, visNotify, value); + break; + } + case EVENT_PLACE: { + number = TkFindStateNumObj(interp, optionPtr, circPlace, + valuePtr); if (number < 0) { return TCL_ERROR; } - event.xvisibility.state = number; - } else { - goto badopt; - } - } else if (strcmp(field, "-subwindow") == 0) { - if (value[0] == '.') { - tkwin2 = Tk_NameToWindow(interp, value, mainwin); - if (tkwin2 == NULL) { + if (flags & CIRC) { + event.xcirculate.place = number; + } else { + goto badopt; + } + break; + } + case EVENT_ROOT: { + if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) { return TCL_ERROR; } - number = Tk_WindowId(tkwin2); - } else if (TkpScanWindowId(interp, value, &number) - != TCL_OK) { - return TCL_ERROR; + if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { + event.xkey.root = Tk_WindowId(tkwin2); + } else { + goto badopt; + } + break; } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.subwindow = number; - } else { - goto badopt; + case EVENT_ROOTX: { + if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) { + return TCL_ERROR; + } + if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { + event.xkey.x_root = number; + } else { + goto badopt; + } + break; } - } else if (strcmp(field, "-time") == 0) { - if (Tcl_GetInt(interp, value, &number) != TCL_OK) { - return TCL_ERROR; + case EVENT_ROOTY: { + if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) { + return TCL_ERROR; + } + if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { + event.xkey.y_root = number; + } else { + goto badopt; + } + break; } - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.time = (Time) number; - } else if (flags & PROP) { - event.xproperty.time = (Time) number; - } else { - goto badopt; + case EVENT_SEND: { + CONST char *value; + + value = Tcl_GetStringFromObj(valuePtr, NULL); + if (isdigit(UCHAR(value[0]))) { + /* + * Allow arbitrary integer values for the field; they + * are needed by a few of the tests in the Tk test suite. + */ + + if (Tcl_GetIntFromObj(interp, valuePtr, &number) + != TCL_OK) { + return TCL_ERROR; + } + } else { + if (Tcl_GetBooleanFromObj(interp, valuePtr, &number) + != TCL_OK) { + return TCL_ERROR; + } + } + event.xany.send_event = number; + break; } - } else if (strcmp(field, "-width") == 0) { - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; + case EVENT_SERIAL: { + if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { + return TCL_ERROR; + } + event.xany.serial = number; + break; } - if (flags & EXPOSE) { - event.xexpose.width = number; - } else if (flags & (CREATE|CONFIG)) { - event.xcreatewindow.width = number; - } else { - goto badopt; + case EVENT_STATE: { + if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { + if (Tcl_GetIntFromObj(interp, valuePtr, &number) + != TCL_OK) { + return TCL_ERROR; + } + if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { + event.xkey.state = number; + } else { + event.xcrossing.state = number; + } + } else if (flags & VISIBILITY) { + number = TkFindStateNumObj(interp, optionPtr, visNotify, + valuePtr); + if (number < 0) { + return TCL_ERROR; + } + event.xvisibility.state = number; + } else { + goto badopt; + } + break; } - } else if (strcmp(field, "-window") == 0) { - if (value[0] == '.') { - tkwin2 = Tk_NameToWindow(interp, value, mainwin); - if (tkwin2 == NULL) { + case EVENT_SUBWINDOW: { + if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) { return TCL_ERROR; } - number = Tk_WindowId(tkwin2); - } else if (TkpScanWindowId(interp, value, &number) - != TCL_OK) { - return TCL_ERROR; + if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { + event.xkey.subwindow = Tk_WindowId(tkwin2); + } else { + goto badopt; + } + break; } - if (flags & (CREATE|DESTROY|UNMAP|MAP|REPARENT|CONFIG - |GRAVITY|CIRC)) { - event.xcreatewindow.window = number; - } else { - goto badopt; + case EVENT_TIME: { + if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { + return TCL_ERROR; + } + if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { + event.xkey.time = (Time) number; + } else if (flags & PROP) { + event.xproperty.time = (Time) number; + } else { + goto badopt; + } + break; } - } else if (strcmp(field, "-x") == 0) { - int rootX, rootY; - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; + case EVENT_WIDTH: { + if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) + != TCL_OK) { + return TCL_ERROR; + } + if (flags & EXPOSE) { + event.xexpose.width = number; + } else if (flags & (CREATE|CONFIG)) { + event.xcreatewindow.width = number; + } else { + goto badopt; + } + break; } - Tk_GetRootCoords(tkwin, &rootX, &rootY); - rootX += number; - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.x = number; - event.xkey.x_root = rootX; - } else if (flags & EXPOSE) { - event.xexpose.x = number; - } else if (flags & (CREATE|CONFIG|GRAVITY)) { - event.xcreatewindow.x = number; - } else if (flags & REPARENT) { - event.xreparent.x = number; - } else { - goto badopt; + case EVENT_WINDOW: { + if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) { + return TCL_ERROR; + } + if (flags & (CREATE|DESTROY|UNMAP|MAP|REPARENT|CONFIG + |GRAVITY|CIRC)) { + event.xcreatewindow.window = Tk_WindowId(tkwin2); + } else { + goto badopt; + } + break; } - } else if (strcmp(field, "-y") == 0) { - int rootX, rootY; - if (Tk_GetPixels(interp, tkwin, value, &number) != TCL_OK) { - return TCL_ERROR; + case EVENT_X: { + int rootX, rootY; + + if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) + != TCL_OK) { + return TCL_ERROR; + } + Tk_GetRootCoords(tkwin, &rootX, &rootY); + rootX += number; + if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { + event.xkey.x = number; + event.xkey.x_root = rootX; + } else if (flags & EXPOSE) { + event.xexpose.x = number; + } else if (flags & (CREATE|CONFIG|GRAVITY)) { + event.xcreatewindow.x = number; + } else if (flags & REPARENT) { + event.xreparent.x = number; + } else { + goto badopt; + } + break; } - Tk_GetRootCoords(tkwin, &rootX, &rootY); - rootY += number; - if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { - event.xkey.y = number; - event.xkey.y_root = rootY; - } else if (flags & EXPOSE) { - event.xexpose.y = number; - } else if (flags & (CREATE|CONFIG|GRAVITY)) { - event.xcreatewindow.y = number; - } else if (flags & REPARENT) { - event.xreparent.y = number; - } else { - goto badopt; + case EVENT_Y: { + int rootX, rootY; + + if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) + != TCL_OK) { + return TCL_ERROR; + } + Tk_GetRootCoords(tkwin, &rootX, &rootY); + rootY += number; + if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { + event.xkey.y = number; + event.xkey.y_root = rootY; + } else if (flags & EXPOSE) { + event.xexpose.y = number; + } else if (flags & (CREATE|CONFIG|GRAVITY)) { + event.xcreatewindow.y = number; + } else if (flags & REPARENT) { + event.xreparent.y = number; + } else { + goto badopt; + } + break; } - } else { - badopt: - Tcl_AppendResult(interp, "bad option to ", argv[1], - " event: \"", field, "\"", (char *) NULL); - return TCL_ERROR; } + continue; + + badopt: + Tcl_AppendResult(interp, name, " event doesn't accept \"", + Tcl_GetStringFromObj(optionPtr, NULL), "\" option", NULL); + return TCL_ERROR; } - if (synch != 0) { Tk_HandleEvent(&event); } else { Tk_QueueWindowEvent(&event, pos); } + /* + * We only allow warping if the window is mapped + */ + if ((warp != 0) && Tk_IsMapped(tkwin)) { + TkDisplay *dispPtr; + dispPtr = TkGetDisplay(event.xmotion.display); + if (!dispPtr->warpInProgress) { + Tcl_DoWhenIdle(DoWarp, (ClientData) dispPtr); + dispPtr->warpInProgress = 1; + } + dispPtr->warpWindow = event.xany.window; + dispPtr->warpX = event.xkey.x; + dispPtr->warpY = event.xkey.y; + } Tcl_ResetResult(interp); return TCL_OK; + +} +static int +NameToWindow(interp, mainWin, objPtr, tkwinPtr) + Tcl_Interp *interp; /* Interp for error return and name lookup. */ + Tk_Window mainWin; /* Main window of application. */ + Tcl_Obj *objPtr; /* Contains name or id string of window. */ + Tk_Window *tkwinPtr; /* Filled with token for window. */ +{ + char *name; + Tk_Window tkwin; + int id; + + name = Tcl_GetStringFromObj(objPtr, NULL); + if (name[0] == '.') { + tkwin = Tk_NameToWindow(interp, name, mainWin); + if (tkwin == NULL) { + return TCL_ERROR; + } + *tkwinPtr = tkwin; + } else { + if (TkpScanWindowId(NULL, name, &id) != TCL_OK) { + Tcl_AppendResult(interp, "bad window name/identifier \"", + name, "\"", (char *) NULL); + return TCL_ERROR; + } + *tkwinPtr = Tk_IdToWindow(Tk_Display(mainWin), (Window) id); + } + return TCL_OK; +} + +/* + *------------------------------------------------------------------------- + * + * DoWarp -- + * + * Perform Warping of X pointer. Executed as an idle handler only. + * + * Results: + * None + * + * Side effects: + * X Pointer will move to a new location. + * + *------------------------------------------------------------------------- + */ +static void +DoWarp(clientData) + ClientData clientData; +{ + TkDisplay *dispPtr = (TkDisplay *) clientData; + + XWarpPointer(dispPtr->display, (Window) None, (Window) dispPtr->warpWindow, + 0, 0, 0, 0, (int) dispPtr->warpX, (int) dispPtr->warpY); + XForceScreenSaver(dispPtr->display, ScreenSaverReset); + dispPtr->warpInProgress = 0; } /* @@ -3609,7 +3770,7 @@ HandleEventGenerate(interp, mainwin, argc, argv) * Results: * The return value is NULL if the virtual event string was * not in the proper format. In this case, an error message - * will be left in interp->result. Otherwise the return + * will be left in the interp's result. Otherwise the return * value is a Tk_Uid that represents the virtual event. * * Side effects: @@ -3655,7 +3816,7 @@ GetVirtualEventUid(interp, virtString) * in patternTable that corresponds to eventString. If an error * was found while parsing eventString, or if "create" is 0 and * no pattern sequence previously existed, then NULL is returned - * and interp->result contains a message describing the problem. + * and the interp's result contains a message describing the problem. * If no pattern sequence previously existed for eventString, then * a new one is created with a NULL command field. In a successful * return, *maskPtr is filled in with a mask of the event types @@ -3731,27 +3892,23 @@ FindSequence(interp, patternTablePtr, object, eventString, create, if (eventMask & VirtualEventMask) { if (allowVirtual == 0) { - interp->result = - "virtual event not allowed in definition of another virtual event"; + Tcl_SetResult(interp, + "virtual event not allowed in definition of another virtual event", + TCL_STATIC); return NULL; } virtualFound = 1; } /* - * Replicate events for DOUBLE and TRIPLE. + * Replicate events for DOUBLE, TRIPLE, QUADRUPLE. */ - if ((count > 1) && (numPats < EVENT_BUFFER_SIZE-1)) { + while ((count-- > 1) && (numPats < EVENT_BUFFER_SIZE-1)) { flags |= PAT_NEARBY; patPtr[-1] = patPtr[0]; patPtr--; numPats++; - if ((count == 3) && (numPats < EVENT_BUFFER_SIZE-1)) { - patPtr[-1] = patPtr[0]; - patPtr--; - numPats++; - } } } @@ -3763,11 +3920,12 @@ FindSequence(interp, patternTablePtr, object, eventString, create, */ if (numPats == 0) { - interp->result = "no events specified in binding"; + Tcl_SetResult(interp, "no events specified in binding", TCL_STATIC); return NULL; } if ((numPats > 1) && (virtualFound != 0)) { - interp->result = "virtual events may not be composed"; + Tcl_SetResult(interp, "virtual events may not be composed", + TCL_STATIC); return NULL; } @@ -3793,6 +3951,14 @@ FindSequence(interp, patternTablePtr, object, eventString, create, if (new) { Tcl_DeleteHashEntry(hPtr); } + /* + * No binding exists for the sequence, so return an empty error. + * This is a special error that the caller will check for in order + * to silently ignore this case. This is a hack that maintains + * backward compatibility for Tk_GetBinding but the various "bind" + * commands silently ignore missing bindings. + */ + return NULL; } psPtr = (PatSeq *) ckalloc((unsigned) (sizeof(PatSeq) @@ -3882,8 +4048,10 @@ ParseEventDescription(interp, eventStringPtr, patPtr, if (isprint(UCHAR(*p))) { patPtr->detail.keySym = *p; } else { - sprintf(interp->result, - "bad ASCII character 0x%x", (unsigned char) *p); + char buf[64]; + + sprintf(buf, "bad ASCII character 0x%x", (unsigned char) *p); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return 0; } } @@ -3923,11 +4091,13 @@ ParseEventDescription(interp, eventStringPtr, patPtr, char *field = p + 1; p = strchr(field, '>'); if (p == field) { - interp->result = "virtual event \"<<>>\" is badly formed"; + Tcl_SetResult(interp, "virtual event \"<<>>\" is badly formed", + TCL_STATIC); return 0; } if ((p == NULL) || (p[1] != '>')) { - interp->result = "missing \">\" in virtual binding"; + Tcl_SetResult(interp, "missing \">\" in virtual binding", + TCL_STATIC); return 0; } *p = '\0'; @@ -3957,12 +4127,10 @@ ParseEventDescription(interp, eventStringPtr, patPtr, } modPtr = (ModInfo *) Tcl_GetHashValue(hPtr); patPtr->needMods |= modPtr->mask; - if (modPtr->flags & (DOUBLE|TRIPLE)) { - if (modPtr->flags & DOUBLE) { - count = 2; - } else { - count = 3; - } + if (modPtr->flags & (MULT_CLICKS)) { + int i = modPtr->flags & MULT_CLICKS; + count = 2; + while (i >>= 1) count++; } while ((*p == '-') || isspace(UCHAR(*p))) { p++; @@ -4014,7 +4182,8 @@ ParseEventDescription(interp, eventStringPtr, patPtr, } } } else if (eventFlags == 0) { - interp->result = "no event type or button # or keysym"; + Tcl_SetResult(interp, "no event type or button # or keysym", + TCL_STATIC); return 0; } @@ -4025,11 +4194,13 @@ ParseEventDescription(interp, eventStringPtr, patPtr, while (*p != '\0') { p++; if (*p == '>') { - interp->result = "extra characters after detail in binding"; + Tcl_SetResult(interp, + "extra characters after detail in binding", + TCL_STATIC); return 0; } } - interp->result = "missing \">\" in binding"; + Tcl_SetResult(interp, "missing \">\" in binding", TCL_STATIC); return 0; } p++; @@ -4104,7 +4275,7 @@ GetPatternString(psPtr, dsPtr) Tcl_DString *dsPtr; { Pattern *patPtr; - char c, buffer[10]; + char c, buffer[TCL_INTEGER_SPACE]; int patsLeft, needMods; ModInfo *modPtr; EventInfo *eiPtr; @@ -4147,8 +4318,8 @@ GetPatternString(psPtr, dsPtr) /* * It's a more general event specification. First check - * for "Double" or "Triple", then modifiers, then event type, - * then keysym or button detail. + * for "Double", "Triple", "Quadruple", then modifiers, + * then event type, then keysym or button detail. */ Tcl_DStringAppend(dsPtr, "<", 1); @@ -4161,7 +4332,14 @@ GetPatternString(psPtr, dsPtr) (char *) (patPtr-1), sizeof(Pattern)) == 0)) { patsLeft--; patPtr--; - Tcl_DStringAppend(dsPtr, "Triple-", 7); + if ((patsLeft > 1) && (memcmp((char *) patPtr, + (char *) (patPtr-1), sizeof(Pattern)) == 0)) { + patsLeft--; + patPtr--; + Tcl_DStringAppend(dsPtr, "Quadruple-", 10); + } else { + Tcl_DStringAppend(dsPtr, "Triple-", 7); + } } else { Tcl_DStringAppend(dsPtr, "Double-", 7); } @@ -4203,220 +4381,6 @@ GetPatternString(psPtr, dsPtr) } /* - *---------------------------------------------------------------------- - * - * GetKeySym -- - * - * Given an X KeyPress or KeyRelease event, map the - * keycode in the event into a KeySym. - * - * Results: - * The return value is the KeySym corresponding to - * eventPtr, or NoSymbol if no matching Keysym could be - * found. - * - * Side effects: - * In the first call for a given display, keycode-to- - * KeySym maps get loaded. - * - *---------------------------------------------------------------------- - */ - -static KeySym -GetKeySym(dispPtr, eventPtr) - TkDisplay *dispPtr; /* Display in which to - * map keycode. */ - XEvent *eventPtr; /* Description of X event. */ -{ - KeySym sym; - int index; - - /* - * Refresh the mapping information if it's stale - */ - - if (dispPtr->bindInfoStale) { - InitKeymapInfo(dispPtr); - } - - /* - * Figure out which of the four slots in the keymap vector to - * use for this key. Refer to Xlib documentation for more info - * on how this computation works. - */ - - index = 0; - if (eventPtr->xkey.state & dispPtr->modeModMask) { - index = 2; - } - if ((eventPtr->xkey.state & ShiftMask) - || ((dispPtr->lockUsage != LU_IGNORE) - && (eventPtr->xkey.state & LockMask))) { - index += 1; - } - sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, index); - - /* - * Special handling: if the key was shifted because of Lock, but - * lock is only caps lock, not shift lock, and the shifted keysym - * isn't upper-case alphabetic, then switch back to the unshifted - * keysym. - */ - - if ((index & 1) && !(eventPtr->xkey.state & ShiftMask) - && (dispPtr->lockUsage == LU_CAPS)) { - if (!(((sym >= XK_A) && (sym <= XK_Z)) - || ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) - || ((sym >= XK_Ooblique) && (sym <= XK_Thorn)))) { - index &= ~1; - sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, - index); - } - } - - /* - * Another bit of special handling: if this is a shifted key and there - * is no keysym defined, then use the keysym for the unshifted key. - */ - - if ((index & 1) && (sym == NoSymbol)) { - sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, - index & ~1); - } - return sym; -} - -/* - *-------------------------------------------------------------- - * - * InitKeymapInfo -- - * - * This procedure is invoked to scan keymap information - * to recompute stuff that's important for binding, such - * as the modifier key (if any) that corresponds to "mode - * switch". - * - * Results: - * None. - * - * Side effects: - * Keymap-related information in dispPtr is updated. - * - *-------------------------------------------------------------- - */ - -static void -InitKeymapInfo(dispPtr) - TkDisplay *dispPtr; /* Display for which to recompute keymap - * information. */ -{ - XModifierKeymap *modMapPtr; - KeyCode *codePtr; - KeySym keysym; - int count, i, j, max, arraySize; -#define KEYCODE_ARRAY_SIZE 20 - - dispPtr->bindInfoStale = 0; - modMapPtr = XGetModifierMapping(dispPtr->display); - - /* - * Check the keycodes associated with the Lock modifier. If - * any of them is associated with the XK_Shift_Lock modifier, - * then Lock has to be interpreted as Shift Lock, not Caps Lock. - */ - - dispPtr->lockUsage = LU_IGNORE; - codePtr = modMapPtr->modifiermap + modMapPtr->max_keypermod*LockMapIndex; - for (count = modMapPtr->max_keypermod; count > 0; count--, codePtr++) { - if (*codePtr == 0) { - continue; - } - keysym = XKeycodeToKeysym(dispPtr->display, *codePtr, 0); - if (keysym == XK_Shift_Lock) { - dispPtr->lockUsage = LU_SHIFT; - break; - } - if (keysym == XK_Caps_Lock) { - dispPtr->lockUsage = LU_CAPS; - break; - } - } - - /* - * Look through the keycodes associated with modifiers to see if - * the the "mode switch", "meta", or "alt" keysyms are associated - * with any modifiers. If so, remember their modifier mask bits. - */ - - dispPtr->modeModMask = 0; - dispPtr->metaModMask = 0; - dispPtr->altModMask = 0; - codePtr = modMapPtr->modifiermap; - max = 8*modMapPtr->max_keypermod; - for (i = 0; i < max; i++, codePtr++) { - if (*codePtr == 0) { - continue; - } - keysym = XKeycodeToKeysym(dispPtr->display, *codePtr, 0); - if (keysym == XK_Mode_switch) { - dispPtr->modeModMask |= ShiftMask << (i/modMapPtr->max_keypermod); - } - if ((keysym == XK_Meta_L) || (keysym == XK_Meta_R)) { - dispPtr->metaModMask |= ShiftMask << (i/modMapPtr->max_keypermod); - } - if ((keysym == XK_Alt_L) || (keysym == XK_Alt_R)) { - dispPtr->altModMask |= ShiftMask << (i/modMapPtr->max_keypermod); - } - } - - /* - * Create an array of the keycodes for all modifier keys. - */ - - if (dispPtr->modKeyCodes != NULL) { - ckfree((char *) dispPtr->modKeyCodes); - } - dispPtr->numModKeyCodes = 0; - arraySize = KEYCODE_ARRAY_SIZE; - dispPtr->modKeyCodes = (KeyCode *) ckalloc((unsigned) - (KEYCODE_ARRAY_SIZE * sizeof(KeyCode))); - for (i = 0, codePtr = modMapPtr->modifiermap; i < max; i++, codePtr++) { - if (*codePtr == 0) { - continue; - } - - /* - * Make sure that the keycode isn't already in the array. - */ - - for (j = 0; j < dispPtr->numModKeyCodes; j++) { - if (dispPtr->modKeyCodes[j] == *codePtr) { - goto nextModCode; - } - } - if (dispPtr->numModKeyCodes >= arraySize) { - KeyCode *new; - - /* - * Ran out of space in the array; grow it. - */ - - arraySize *= 2; - new = (KeyCode *) ckalloc((unsigned) - (arraySize * sizeof(KeyCode))); - memcpy((VOID *) new, (VOID *) dispPtr->modKeyCodes, - (dispPtr->numModKeyCodes * sizeof(KeyCode))); - ckfree((char *) dispPtr->modKeyCodes); - dispPtr->modKeyCodes = new; - } - dispPtr->modKeyCodes[dispPtr->numModKeyCodes] = *codePtr; - dispPtr->numModKeyCodes++; - nextModCode: continue; - } - XFreeModifiermap(modMapPtr); -} - -/* *--------------------------------------------------------------------------- * * EvalTclBinding -- @@ -4525,7 +4489,7 @@ TkKeysymToString(keysym) * * Results: * Returns the result of evaluating script, including both a standard - * Tcl completion code and a string in interp->result. + * Tcl completion code and a string in the interp's result. * * Side effects: * None. @@ -4550,3 +4514,5 @@ TkCopyAndGlobalEval(interp, script) } + + diff --git a/tk/generic/tkBitmap.c b/tk/generic/tkBitmap.c index 431fa56db42..ff8e7e3e5a2 100644 --- a/tk/generic/tkBitmap.c +++ b/tk/generic/tkBitmap.c @@ -6,7 +6,7 @@ * also avoids interactions with the X server. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -51,69 +51,180 @@ * "nameTable". */ -typedef struct { +typedef struct TkBitmap { Pixmap bitmap; /* X identifier for bitmap. None means this * bitmap was created by Tk_DefineBitmap * and it isn't currently in use. */ int width, height; /* Dimensions of bitmap. */ Display *display; /* Display for which bitmap is valid. */ - int refCount; /* Number of active uses of bitmap. */ - Tcl_HashEntry *hashPtr; /* Entry in nameTable for this structure + int resourceRefCount; /* Number of active uses of this bitmap (each + * active use corresponds to a call to + * Tk_AllocBitmapFromObj or Tk_GetBitmap). + * If this count is 0, then this TkBitmap + * structure is no longer valid and it isn't + * present in nameTable: it is being kept + * around only because there are objects + * referring to it. The structure is freed + * when resourceRefCount and objRefCount + * are both 0. */ + int objRefCount; /* Number of Tcl_Obj's that reference + * this structure. */ + Tcl_HashEntry *nameHashPtr; /* Entry in nameTable for this structure + * (needed when deleting). */ + Tcl_HashEntry *idHashPtr; /* Entry in idTable for this structure * (needed when deleting). */ + struct TkBitmap *nextPtr; /* Points to the next TkBitmap structure with + * the same name. All bitmaps with the + * same name (but different displays) are + * chained together off a single entry in + * nameTable. */ } TkBitmap; -/* - * Hash table to map from a textual description of a bitmap to the - * TkBitmap record for the bitmap, and key structure used in that - * hash table: +/* + * Used in bitmapDataTable, stored in the TkDisplay structure, to map + * between in-core data about a bitmap to its TkBitmap structure. */ -static Tcl_HashTable nameTable; typedef struct { - Tk_Uid name; /* Textual name for desired bitmap. */ - Screen *screen; /* Screen on which bitmap will be used. */ -} NameKey; + char *source; /* Bitmap bits. */ + int width, height; /* Dimensions of bitmap. */ +} DataKey; + +typedef struct ThreadSpecificData { + int initialized; /* 0 means table below needs initializing. */ + Tcl_HashTable predefBitmapTable; + /* Hash table created by Tk_DefineBitmap + * to map from a name to a collection + * of in-core data about a bitmap. The + * table is indexed by the address of the + * data for the bitmap, and the entries + * contain pointers to TkPredefBitmap + * structures. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; /* - * Hash table that maps from <display + bitmap id> to the TkBitmap structure - * for the bitmap. This table is used by Tk_FreeBitmap. + * Forward declarations for procedures defined in this file: */ -static Tcl_HashTable idTable; -typedef struct { - Display *display; /* Display for which bitmap was allocated. */ - Pixmap pixmap; /* X identifier for pixmap. */ -} IdKey; +static void BitmapInit _ANSI_ARGS_((TkDisplay *dispPtr)); +static void DupBitmapObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr, + Tcl_Obj *dupObjPtr)); +static void FreeBitmap _ANSI_ARGS_((TkBitmap *bitmapPtr)); +static void FreeBitmapObjProc _ANSI_ARGS_((Tcl_Obj *objPtr)); +static TkBitmap * GetBitmap _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, CONST char *name)); +static TkBitmap * GetBitmapFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj *objPtr)); +static void InitBitmapObj _ANSI_ARGS_((Tcl_Obj *objPtr)); /* - * Hash table create by Tk_DefineBitmap to map from a name to a - * collection of in-core data about a bitmap. The table is - * indexed by the address of the data for the bitmap, and the entries - * contain pointers to TkPredefBitmap structures. + * The following structure defines the implementation of the "bitmap" Tcl + * object, which maps a string bitmap name to a TkBitmap object. The + * ptr1 field of the Tcl_Obj points to a TkBitmap object. */ -Tcl_HashTable tkPredefBitmapTable; - +static Tcl_ObjType bitmapObjType = { + "bitmap", /* name */ + FreeBitmapObjProc, /* freeIntRepProc */ + DupBitmapObjProc, /* dupIntRepProc */ + NULL, /* updateStringProc */ + NULL /* setFromAnyProc */ +}; + /* - * Hash table used by Tk_GetBitmapFromData to map from a collection - * of in-core data about a bitmap to a Tk_Uid giving an automatically- - * generated name for the bitmap: + *---------------------------------------------------------------------- + * + * Tk_AllocBitmapFromObj -- + * + * Given a Tcl_Obj *, map the value to a corresponding + * Pixmap structure based on the tkwin given. + * + * Results: + * The return value is the X identifer for the desired bitmap + * (i.e. a Pixmap with a single plane), unless string couldn't be + * parsed correctly. In this case, None is returned and an error + * message is left in the interp's result. The caller should never + * modify the bitmap that is returned, and should eventually call + * Tk_FreeBitmapFromObj when the bitmap is no longer needed. + * + * Side effects: + * The bitmap is added to an internal database with a reference count. + * For each call to this procedure, there should eventually be a call + * to Tk_FreeBitmapFromObj, so that the database can be cleaned up + * when bitmaps aren't needed anymore. + * + *---------------------------------------------------------------------- */ -static Tcl_HashTable dataTable; -typedef struct { - char *source; /* Bitmap bits. */ - int width, height; /* Dimensions of bitmap. */ -} DataKey; +Pixmap +Tk_AllocBitmapFromObj(interp, tkwin, objPtr) + Tcl_Interp *interp; /* Interp for error results. This may + * be NULL. */ + Tk_Window tkwin; /* Need the screen the bitmap is used on.*/ + Tcl_Obj *objPtr; /* Object describing bitmap; see manual + * entry for legal syntax of string value. */ +{ + TkBitmap *bitmapPtr; -static int initialized = 0; /* 0 means static structures haven't been - * initialized yet. */ + if (objPtr->typePtr != &bitmapObjType) { + InitBitmapObj(objPtr); + } + bitmapPtr = (TkBitmap *) objPtr->internalRep.twoPtrValue.ptr1; -/* - * Forward declarations for procedures defined in this file: - */ + /* + * If the object currently points to a TkBitmap, see if it's the + * one we want. If so, increment its reference count and return. + */ + + if (bitmapPtr != NULL) { + if (bitmapPtr->resourceRefCount == 0) { + /* + * This is a stale reference: it refers to a TkBitmap that's + * no longer in use. Clear the reference. + */ + + FreeBitmapObjProc(objPtr); + bitmapPtr = NULL; + } else if (Tk_Display(tkwin) == bitmapPtr->display) { + bitmapPtr->resourceRefCount++; + return bitmapPtr->bitmap; + } + } + + /* + * The object didn't point to the TkBitmap that we wanted. Search + * the list of TkBitmaps with the same name to see if one of the + * others is the right one. + */ + + if (bitmapPtr != NULL) { + TkBitmap *firstBitmapPtr = + (TkBitmap *) Tcl_GetHashValue(bitmapPtr->nameHashPtr); + FreeBitmapObjProc(objPtr); + for (bitmapPtr = firstBitmapPtr; bitmapPtr != NULL; + bitmapPtr = bitmapPtr->nextPtr) { + if (Tk_Display(tkwin) == bitmapPtr->display) { + bitmapPtr->resourceRefCount++; + bitmapPtr->objRefCount++; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr; + return bitmapPtr->bitmap; + } + } + } + + /* + * Still no luck. Call GetBitmap to allocate a new TkBitmap object. + */ -static void BitmapInit _ANSI_ARGS_((void)); + bitmapPtr = GetBitmap(interp, tkwin, Tcl_GetString(objPtr)); + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr; + if (bitmapPtr == NULL) { + return None; + } + bitmapPtr->objRefCount++; + return bitmapPtr->bitmap; +} /* *---------------------------------------------------------------------- @@ -127,7 +238,7 @@ static void BitmapInit _ANSI_ARGS_((void)); * The return value is the X identifer for the desired bitmap * (i.e. a Pixmap with a single plane), 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 + * message is left in the interp's result. The caller should never * modify the bitmap that is returned, and should eventually call * Tk_FreeBitmap when the bitmap is no longer needed. * @@ -145,30 +256,78 @@ Tk_GetBitmap(interp, tkwin, string) Tcl_Interp *interp; /* Interpreter to use for error reporting, * this may be NULL. */ Tk_Window tkwin; /* Window in which bitmap will be used. */ - Tk_Uid string; /* Description of bitmap. See manual entry + CONST char *string; /* Description of bitmap. See manual entry + * for details on legal syntax. */ +{ + TkBitmap *bitmapPtr = GetBitmap(interp, tkwin, string); + if (bitmapPtr == NULL) { + return None; + } + return bitmapPtr->bitmap; +} + +/* + *---------------------------------------------------------------------- + * + * GetBitmap -- + * + * Given a string describing a bitmap, locate (or create if necessary) + * a bitmap that fits the description. This routine returns the + * internal data structure for the bitmap. This avoids extra + * hash table lookups in Tk_AllocBitmapFromObj. + * + * Results: + * The return value is the X identifer for the desired bitmap + * (i.e. a Pixmap with a single plane), unless string couldn't be + * parsed correctly. In this case, None is returned and an error + * message is left in the interp's result. The caller should never + * modify the bitmap that is returned, and should eventually call + * Tk_FreeBitmap when the bitmap is no longer needed. + * + * Side effects: + * The bitmap is added to an internal database with a reference count. + * For each call to this procedure, there should eventually be a call + * to Tk_FreeBitmap or Tk_FreeBitmapFromObj, so that the database can + * be cleaned up when bitmaps aren't needed anymore. + * + *---------------------------------------------------------------------- + */ + +static TkBitmap * +GetBitmap(interp, tkwin, string) + Tcl_Interp *interp; /* Interpreter to use for error reporting, + * this may be NULL. */ + Tk_Window tkwin; /* Window in which bitmap will be used. */ + CONST char *string; /* Description of bitmap. See manual entry * for details on legal syntax. */ { - NameKey nameKey; - IdKey idKey; - Tcl_HashEntry *nameHashPtr, *idHashPtr, *predefHashPtr; - register TkBitmap *bitmapPtr; + Tcl_HashEntry *nameHashPtr, *predefHashPtr; + TkBitmap *bitmapPtr, *existingBitmapPtr; TkPredefBitmap *predefPtr; int new; Pixmap bitmap; int width, height; int dummy2; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - if (!initialized) { - BitmapInit(); + if (!dispPtr->bitmapInit) { + BitmapInit(dispPtr); } - nameKey.name = string; - nameKey.screen = Tk_Screen(tkwin); - nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new); + nameHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapNameTable, string, &new); if (!new) { - bitmapPtr = (TkBitmap *) Tcl_GetHashValue(nameHashPtr); - bitmapPtr->refCount++; - return bitmapPtr->bitmap; + existingBitmapPtr = (TkBitmap *) Tcl_GetHashValue(nameHashPtr); + for (bitmapPtr = existingBitmapPtr; bitmapPtr != NULL; + bitmapPtr = bitmapPtr->nextPtr) { + if (Tk_Display(tkwin) == bitmapPtr->display) { + bitmapPtr->resourceRefCount++; + return bitmapPtr; + } + } + } else { + existingBitmapPtr = NULL; } /* @@ -179,7 +338,7 @@ Tk_GetBitmap(interp, tkwin, string) * defined by a call to Tk_DefineBitmap. */ - if (*string == '@') { + if (*string == '@') { /* INTL: ISO char */ Tcl_DString buffer; int result; @@ -188,13 +347,19 @@ Tk_GetBitmap(interp, tkwin, string) " safe interpreter", (char *) NULL); goto error; } - - string = Tcl_TranslateFileName(interp, string + 1, &buffer); + + /* + * Note that we need to cast away the CONST from the string because + * Tcl_TranslateFileName is non const, even though it doesn't modify + * the string. + */ + + string = Tcl_TranslateFileName(interp, (char *) string + 1, &buffer); if (string == NULL) { goto error; } result = TkReadBitmapFile(Tk_Display(tkwin), - RootWindowOfScreen(nameKey.screen), string, + RootWindowOfScreen(Tk_Screen(tkwin)), string, (unsigned int *) &width, (unsigned int *) &height, &bitmap, &dummy2, &dummy2); if (result != BitmapSuccess) { @@ -207,7 +372,8 @@ Tk_GetBitmap(interp, tkwin, string) } Tcl_DStringFree(&buffer); } else { - predefHashPtr = Tcl_FindHashEntry(&tkPredefBitmapTable, string); + predefHashPtr = Tcl_FindHashEntry(&tsdPtr->predefBitmapTable, + string); if (predefHashPtr == NULL) { /* * The following platform specific call allows the user to @@ -236,7 +402,8 @@ Tk_GetBitmap(interp, tkwin, string) } } else { bitmap = XCreateBitmapFromData(Tk_Display(tkwin), - RootWindowOfScreen(nameKey.screen), predefPtr->source, + RootWindowOfScreen(Tk_Screen(tkwin)), + predefPtr->source, (unsigned) width, (unsigned) height); } } @@ -251,22 +418,24 @@ Tk_GetBitmap(interp, tkwin, string) bitmapPtr->width = width; bitmapPtr->height = height; bitmapPtr->display = Tk_Display(tkwin); - bitmapPtr->refCount = 1; - bitmapPtr->hashPtr = nameHashPtr; - idKey.display = bitmapPtr->display; - idKey.pixmap = bitmap; - idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, - &new); + bitmapPtr->resourceRefCount = 1; + bitmapPtr->objRefCount = 0; + bitmapPtr->nameHashPtr = nameHashPtr; + bitmapPtr->idHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapIdTable, + (char *) bitmap, &new); if (!new) { panic("bitmap already registered in Tk_GetBitmap"); } + bitmapPtr->nextPtr = existingBitmapPtr; Tcl_SetHashValue(nameHashPtr, bitmapPtr); - Tcl_SetHashValue(idHashPtr, bitmapPtr); - return bitmapPtr->bitmap; + Tcl_SetHashValue(bitmapPtr->idHashPtr, bitmapPtr); + return bitmapPtr; error: - Tcl_DeleteHashEntry(nameHashPtr); - return None; + if (new) { + Tcl_DeleteHashEntry(nameHashPtr); + } + return NULL; } /* @@ -280,7 +449,7 @@ Tk_GetBitmap(interp, tkwin, string) * * Results: * A standard Tcl result. If an error occurs then TCL_ERROR is - * returned and a message is left in interp->result. + * returned and a message is left in the interp's result. * * Side effects: * "Name" is entered into the bitmap table and may be used from @@ -292,7 +461,7 @@ Tk_GetBitmap(interp, tkwin, string) int Tk_DefineBitmap(interp, name, source, width, height) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - Tk_Uid name; /* Name to use for bitmap. Must not already + CONST char *name; /* Name to use for bitmap. Must not already * be defined as a bitmap. */ char *source; /* Address of bits for bitmap. */ int width; /* Width of bitmap. */ @@ -301,12 +470,23 @@ Tk_DefineBitmap(interp, name, source, width, height) int new; Tcl_HashEntry *predefHashPtr; TkPredefBitmap *predefPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + /* + * Initialize the Bitmap module if not initialized already for this + * thread. Since the current TkDisplay structure cannot be + * introspected from here, pass a NULL pointer to BitmapInit, + * which will know to initialize only the data in the + * ThreadSpecificData structure for the current thread. + */ - if (!initialized) { - BitmapInit(); + if (!tsdPtr->initialized) { + BitmapInit((TkDisplay *) NULL); } - predefHashPtr = Tcl_CreateHashEntry(&tkPredefBitmapTable, name, &new); + predefHashPtr = Tcl_CreateHashEntry(&tsdPtr->predefBitmapTable, + name, &new); if (!new) { Tcl_AppendResult(interp, "bitmap \"", name, "\" is already defined", (char *) NULL); @@ -338,29 +518,27 @@ Tk_DefineBitmap(interp, name, source, width, height) *-------------------------------------------------------------- */ -Tk_Uid +char * Tk_NameOfBitmap(display, bitmap) Display *display; /* Display for which bitmap was * allocated. */ Pixmap bitmap; /* Bitmap whose name is wanted. */ { - IdKey idKey; Tcl_HashEntry *idHashPtr; TkBitmap *bitmapPtr; + TkDisplay *dispPtr = TkGetDisplay(display); - if (!initialized) { + if (dispPtr == NULL || !dispPtr->bitmapInit) { unknown: panic("Tk_NameOfBitmap received unknown bitmap argument"); } - idKey.display = display; - idKey.pixmap = bitmap; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); + idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap); if (idHashPtr == NULL) { goto unknown; } bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); - return ((NameKey *) bitmapPtr->hashPtr->key.words)->name; + return bitmapPtr->nameHashPtr->key.string; } /* @@ -390,18 +568,16 @@ Tk_SizeOfBitmap(display, bitmap, widthPtr, heightPtr) int *widthPtr; /* Store bitmap width here. */ int *heightPtr; /* Store bitmap height here. */ { - IdKey idKey; Tcl_HashEntry *idHashPtr; TkBitmap *bitmapPtr; + TkDisplay *dispPtr = TkGetDisplay(display); - if (!initialized) { + if (!dispPtr->bitmapInit) { unknownBitmap: panic("Tk_SizeOfBitmap received unknown bitmap argument"); } - idKey.display = display; - idKey.pixmap = bitmap; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); + idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap); if (idHashPtr == NULL) { goto unknownBitmap; } @@ -413,6 +589,56 @@ Tk_SizeOfBitmap(display, bitmap, widthPtr, heightPtr) /* *---------------------------------------------------------------------- * + * FreeBitmap -- + * + * This procedure does all the work of releasing a bitmap allocated by + * Tk_GetBitmap or TkGetBitmapFromData. It is invoked by both + * Tk_FreeBitmap and Tk_FreeBitmapFromObj + * + * Results: + * None. + * + * Side effects: + * The reference count associated with bitmap is decremented, and + * it is officially deallocated if no-one is using it anymore. + * + *---------------------------------------------------------------------- + */ + +static void +FreeBitmap(bitmapPtr) + TkBitmap *bitmapPtr; /* Bitmap to be released. */ +{ + TkBitmap *prevPtr; + + bitmapPtr->resourceRefCount--; + if (bitmapPtr->resourceRefCount > 0) { + return; + } + + Tk_FreePixmap(bitmapPtr->display, bitmapPtr->bitmap); + Tcl_DeleteHashEntry(bitmapPtr->idHashPtr); + prevPtr = (TkBitmap *) Tcl_GetHashValue(bitmapPtr->nameHashPtr); + if (prevPtr == bitmapPtr) { + if (bitmapPtr->nextPtr == NULL) { + Tcl_DeleteHashEntry(bitmapPtr->nameHashPtr); + } else { + Tcl_SetHashValue(bitmapPtr->nameHashPtr, bitmapPtr->nextPtr); + } + } else { + while (prevPtr->nextPtr != bitmapPtr) { + prevPtr = prevPtr->nextPtr; + } + prevPtr->nextPtr = bitmapPtr->nextPtr; + } + if (bitmapPtr->objRefCount == 0) { + ckfree((char *) bitmapPtr); + } +} + +/* + *---------------------------------------------------------------------- + * * Tk_FreeBitmap -- * * This procedure is called to release a bitmap allocated by @@ -435,26 +661,115 @@ Tk_FreeBitmap(display, bitmap) Pixmap bitmap; /* Bitmap to be released. */ { Tcl_HashEntry *idHashPtr; - register TkBitmap *bitmapPtr; - IdKey idKey; + TkDisplay *dispPtr = TkGetDisplay(display); - if (!initialized) { + if (!dispPtr->bitmapInit) { panic("Tk_FreeBitmap called before Tk_GetBitmap"); } - idKey.display = display; - idKey.pixmap = bitmap; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); + idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap); if (idHashPtr == NULL) { panic("Tk_FreeBitmap received unknown bitmap argument"); } - bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); - bitmapPtr->refCount--; - if (bitmapPtr->refCount == 0) { - Tk_FreePixmap(bitmapPtr->display, bitmapPtr->bitmap); - Tcl_DeleteHashEntry(idHashPtr); - Tcl_DeleteHashEntry(bitmapPtr->hashPtr); - ckfree((char *) bitmapPtr); + FreeBitmap((TkBitmap *) Tcl_GetHashValue(idHashPtr)); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_FreeBitmapFromObj -- + * + * This procedure is called to release a bitmap allocated by + * Tk_AllocBitmapFromObj. It does not throw away the Tcl_Obj *; + * it only gets rid of the hash table entry for this bitmap + * and clears the cached value that is normally stored in the object. + * + * Results: + * None. + * + * Side effects: + * The reference count associated with the bitmap represented by + * objPtr is decremented, and the bitmap is released to X if there are + * no remaining uses for it. + * + *---------------------------------------------------------------------- + */ + +void +Tk_FreeBitmapFromObj(tkwin, objPtr) + Tk_Window tkwin; /* The window this bitmap lives in. Needed + * for the display value. */ + Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */ +{ + FreeBitmap(GetBitmapFromObj(tkwin, objPtr)); +} + +/* + *--------------------------------------------------------------------------- + * + * FreeBitmapObjProc -- + * + * This proc is called to release an object reference to a bitmap. + * Called when the object's internal rep is released or when + * the cached bitmapPtr needs to be changed. + * + * Results: + * None. + * + * Side effects: + * The object reference count is decremented. When both it + * and the hash ref count go to zero, the color's resources + * are released. + * + *--------------------------------------------------------------------------- + */ + +static void +FreeBitmapObjProc(objPtr) + Tcl_Obj *objPtr; /* The object we are releasing. */ +{ + TkBitmap *bitmapPtr = (TkBitmap *) objPtr->internalRep.twoPtrValue.ptr1; + + if (bitmapPtr != NULL) { + bitmapPtr->objRefCount--; + if ((bitmapPtr->objRefCount == 0) + && (bitmapPtr->resourceRefCount == 0)) { + ckfree((char *) bitmapPtr); + } + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL; + } +} + +/* + *--------------------------------------------------------------------------- + * + * DupBitmapObjProc -- + * + * When a cached bitmap object is duplicated, this is called to + * update the internal reps. + * + * Results: + * None. + * + * Side effects: + * The color's objRefCount is incremented and the internal rep + * of the copy is set to point to it. + * + *--------------------------------------------------------------------------- + */ + +static void +DupBitmapObjProc(srcObjPtr, dupObjPtr) + Tcl_Obj *srcObjPtr; /* The object we are copying from. */ + Tcl_Obj *dupObjPtr; /* The object we are copying to. */ +{ + TkBitmap *bitmapPtr = (TkBitmap *) srcObjPtr->internalRep.twoPtrValue.ptr1; + + dupObjPtr->typePtr = srcObjPtr->typePtr; + dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr; + + if (bitmapPtr != NULL) { + bitmapPtr->objRefCount++; } } @@ -471,7 +786,7 @@ Tk_FreeBitmap(display, bitmap) * The return value is the X identifer for the desired bitmap * (a one-plane Pixmap), 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 bitmap that + * the interp's result. The caller should never modify the bitmap that * is returned, and should eventually call Tk_FreeBitmap when the * bitmap is no longer needed. * @@ -494,25 +809,24 @@ Tk_GetBitmapFromData(interp, tkwin, source, width, height) { DataKey nameKey; Tcl_HashEntry *dataHashPtr; - Tk_Uid name; int new; - char string[20]; - static int autoNumber = 0; + char string[16 + TCL_INTEGER_SPACE]; + char *name; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - if (!initialized) { - BitmapInit(); - } + BitmapInit(dispPtr); nameKey.source = source; nameKey.width = width; nameKey.height = height; - dataHashPtr = Tcl_CreateHashEntry(&dataTable, (char *) &nameKey, &new); + dataHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapDataTable, + (char *) &nameKey, &new); if (!new) { - name = (Tk_Uid) Tcl_GetHashValue(dataHashPtr); + name = (char *) Tcl_GetHashValue(dataHashPtr); } else { - autoNumber++; - sprintf(string, "_tk%d", autoNumber); - name = Tk_GetUid(string); + dispPtr->bitmapAutoNumber++; + sprintf(string, "_tk%d", dispPtr->bitmapAutoNumber); + name = string; Tcl_SetHashValue(dataHashPtr, name); if (Tk_DefineBitmap(interp, name, source, width, height) != TCL_OK) { Tcl_DeleteHashEntry(dataHashPtr); @@ -525,63 +839,226 @@ Tk_GetBitmapFromData(interp, tkwin, source, width, height) /* *---------------------------------------------------------------------- * - * BitmapInit -- + * Tk_GetBitmapFromObj -- + * + * Returns the bitmap referred to by a Tcl object. The bitmap must + * already have been allocated via a call to Tk_AllocBitmapFromObj + * or Tk_GetBitmap. + * + * Results: + * Returns the Pixmap that matches the tkwin and the string rep + * of objPtr. + * + * Side effects: + * If the object is not already a bitmap, the conversion will free + * any old internal representation. * - * Initialize the structures used for bitmap management. + *---------------------------------------------------------------------- + */ + +Pixmap +Tk_GetBitmapFromObj(tkwin, objPtr) + Tk_Window tkwin; + Tcl_Obj *objPtr; /* The object from which to get pixels. */ +{ + TkBitmap *bitmapPtr = GetBitmapFromObj(tkwin, objPtr); + return bitmapPtr->bitmap; +} + +/* + *---------------------------------------------------------------------- + * + * GetBitmapFromObj -- + * + * Returns the bitmap referred to by a Tcl object. The bitmap must + * already have been allocated via a call to Tk_AllocBitmapFromObj + * or Tk_GetBitmap. + * + * Results: + * Returns the TkBitmap * that matches the tkwin and the string rep + * of objPtr. + * + * Side effects: + * If the object is not already a bitmap, the conversion will free + * any old internal representation. + * + *---------------------------------------------------------------------- + */ + +static TkBitmap * +GetBitmapFromObj(tkwin, objPtr) + Tk_Window tkwin; /* Window in which the bitmap will be used. */ + Tcl_Obj *objPtr; /* The object that describes the desired + * bitmap. */ +{ + TkBitmap *bitmapPtr; + Tcl_HashEntry *hashPtr; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + + if (objPtr->typePtr != &bitmapObjType) { + InitBitmapObj(objPtr); + } + + bitmapPtr = (TkBitmap *) objPtr->internalRep.twoPtrValue.ptr1; + if (bitmapPtr != NULL) { + if ((bitmapPtr->resourceRefCount > 0) + && (Tk_Display(tkwin) == bitmapPtr->display)) { + return bitmapPtr; + } + hashPtr = bitmapPtr->nameHashPtr; + FreeBitmapObjProc(objPtr); + } else { + hashPtr = Tcl_FindHashEntry(&dispPtr->bitmapNameTable, + Tcl_GetString(objPtr)); + if (hashPtr == NULL) { + goto error; + } + } + + /* + * At this point we've got a hash table entry, off of which hang + * one or more TkBitmap structures. See if any of them will work. + */ + + for (bitmapPtr = (TkBitmap *) Tcl_GetHashValue(hashPtr); + bitmapPtr != NULL; bitmapPtr = bitmapPtr->nextPtr) { + if (Tk_Display(tkwin) == bitmapPtr->display) { + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr; + bitmapPtr->objRefCount++; + return bitmapPtr; + } + } + + error: + panic("GetBitmapFromObj called with non-existent bitmap!"); + /* + * The following code isn't reached; it's just there to please compilers. + */ + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * InitBitmapObj -- + * + * Bookeeping procedure to change an objPtr to a bitmap type. * * Results: * None. * * Side effects: + * The old internal rep of the object is freed. The internal + * rep is cleared. The final form of the object is set + * by either Tk_AllocBitmapFromObj or GetBitmapFromObj. + * + *---------------------------------------------------------------------- + */ + +static void +InitBitmapObj(objPtr) + Tcl_Obj *objPtr; /* The object to convert. */ +{ + Tcl_ObjType *typePtr; + + /* + * Free the old internalRep before setting the new one. + */ + + Tcl_GetString(objPtr); + typePtr = objPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(objPtr); + } + objPtr->typePtr = &bitmapObjType; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL; +} + +/* + *---------------------------------------------------------------------- + * + * BitmapInit -- + * Initializes hash tables used by this module. Initializes + * tables stored in TkDisplay structure if a TkDisplay pointer + * is passed in. Iinitializes the thread-local data + * in the current thread's ThreadSpecificData structure. + * + * Results: + * None. + * + * Side effects: * Read the code. * *---------------------------------------------------------------------- */ static void -BitmapInit() +BitmapInit(dispPtr) + TkDisplay *dispPtr; /* TkDisplay structure encapsulating + * thread-specific data used by this + * module, or NULL if unavailable. */ { Tcl_Interp *dummy; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - dummy = Tcl_CreateInterp(); - initialized = 1; - Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int)); - Tcl_InitHashTable(&dataTable, sizeof(DataKey)/sizeof(int)); - Tcl_InitHashTable(&tkPredefBitmapTable, TCL_ONE_WORD_KEYS); + /* + * First initialize the data in the ThreadSpecificData strucuture, + * if needed. + */ + + if (!tsdPtr->initialized) { + tsdPtr->initialized = 1; + dummy = Tcl_CreateInterp(); + Tcl_InitHashTable(&tsdPtr->predefBitmapTable, TCL_STRING_KEYS); + + Tk_DefineBitmap(dummy, "error", (char *) error_bits, + error_width, error_height); + Tk_DefineBitmap(dummy, "gray75", (char *) gray75_bits, + gray75_width, gray75_height); + Tk_DefineBitmap(dummy, "gray50", (char *) gray50_bits, + gray50_width, gray50_height); + Tk_DefineBitmap(dummy, "gray25", (char *) gray25_bits, + gray25_width, gray25_height); + Tk_DefineBitmap(dummy, "gray12", (char *) gray12_bits, + gray12_width, gray12_height); + Tk_DefineBitmap(dummy, "hourglass", (char *) hourglass_bits, + hourglass_width, hourglass_height); + Tk_DefineBitmap(dummy, "info", (char *) info_bits, + info_width, info_height); + Tk_DefineBitmap(dummy, "questhead", (char *) questhead_bits, + questhead_width, questhead_height); + Tk_DefineBitmap(dummy, "question", (char *) question_bits, + question_width, question_height); + Tk_DefineBitmap(dummy, "warning", (char *) warning_bits, + warning_width, warning_height); + + TkpDefineNativeBitmaps(); + Tcl_DeleteInterp(dummy); + } /* - * The call below is tricky: can't use sizeof(IdKey) because it - * gets padded with extra unpredictable bytes on some 64-bit - * machines. + * Was a valid TkDisplay pointer passed? If so, initialize the + * Bitmap module tables in that structure. */ - Tcl_InitHashTable(&idTable, (sizeof(Display *) + sizeof(Pixmap)) - /sizeof(int)); - - Tk_DefineBitmap(dummy, Tk_GetUid("error"), (char *) error_bits, - error_width, error_height); - Tk_DefineBitmap(dummy, Tk_GetUid("gray75"), (char *) gray75_bits, - gray75_width, gray75_height); - Tk_DefineBitmap(dummy, Tk_GetUid("gray50"), (char *) gray50_bits, - gray50_width, gray50_height); - Tk_DefineBitmap(dummy, Tk_GetUid("gray25"), (char *) gray25_bits, - gray25_width, gray25_height); - Tk_DefineBitmap(dummy, Tk_GetUid("gray12"), (char *) gray12_bits, - gray12_width, gray12_height); - Tk_DefineBitmap(dummy, Tk_GetUid("hourglass"), (char *) hourglass_bits, - hourglass_width, hourglass_height); - Tk_DefineBitmap(dummy, Tk_GetUid("info"), (char *) info_bits, - info_width, info_height); - Tk_DefineBitmap(dummy, Tk_GetUid("questhead"), (char *) questhead_bits, - questhead_width, questhead_height); - Tk_DefineBitmap(dummy, Tk_GetUid("question"), (char *) question_bits, - question_width, question_height); - Tk_DefineBitmap(dummy, Tk_GetUid("warning"), (char *) warning_bits, - warning_width, warning_height); - - TkpDefineNativeBitmaps(); - - Tcl_DeleteInterp(dummy); + if (dispPtr != NULL) { + dispPtr->bitmapInit = 1; + Tcl_InitHashTable(&dispPtr->bitmapNameTable, TCL_STRING_KEYS); + Tcl_InitHashTable(&dispPtr->bitmapDataTable, 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. + */ + + /* + * The comment above doesn't make sense... + */ + Tcl_InitHashTable(&dispPtr->bitmapIdTable, TCL_ONE_WORD_KEYS); + } } /* @@ -627,4 +1104,83 @@ TkReadBitmapFile(display, d, filename, width_return, height_return, ckfree(data); return BitmapSuccess; + } + +/* + *---------------------------------------------------------------------- + * + * TkDebugBitmap -- + * + * This procedure returns debugging information about a bitmap. + * + * Results: + * The return value is a list with one sublist for each TkBitmap + * corresponding to "name". Each sublist has two elements that + * contain the resourceRefCount and objRefCount fields from the + * TkBitmap structure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_Obj * +TkDebugBitmap(tkwin, name) + Tk_Window tkwin; /* The window in which the bitmap will be + * used (not currently used). */ + char *name; /* Name of the desired color. */ +{ + TkBitmap *bitmapPtr; + Tcl_HashEntry *hashPtr; + Tcl_Obj *resultPtr, *objPtr; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + + resultPtr = Tcl_NewObj(); + hashPtr = Tcl_FindHashEntry(&dispPtr->bitmapNameTable, name); + if (hashPtr != NULL) { + bitmapPtr = (TkBitmap *) Tcl_GetHashValue(hashPtr); + if (bitmapPtr == NULL) { + panic("TkDebugBitmap found empty hash table entry"); + } + for ( ; (bitmapPtr != NULL); bitmapPtr = bitmapPtr->nextPtr) { + objPtr = Tcl_NewObj(); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewIntObj(bitmapPtr->resourceRefCount)); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewIntObj(bitmapPtr->objRefCount)); + Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); + } + } + return resultPtr; +} + + +/* + *---------------------------------------------------------------------- + * + * TkGetBitmapPredefTable -- + * This procedure is used by tkMacBitmap.c to access the thread- + * specific predefBitmap table that maps from the names of + * the predefined bitmaps to data associated with those + * bitmaps. It is required because the table is allocated in + * thread-local storage and is not visible outside this file. + + * Results: + * Returns a pointer to the predefined bitmap hash table for + * the current thread. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +Tcl_HashTable * +TkGetBitmapPredefTable() +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + return &tsdPtr->predefBitmapTable; } + diff --git a/tk/generic/tkButton.c b/tk/generic/tkButton.c index b493be03a0c..8a52f91217c 100644 --- a/tk/generic/tkButton.c +++ b/tk/generic/tkButton.c @@ -3,11 +3,10 @@ * * This module implements a collection of button-like * widgets for the Tk toolkit. The widgets implemented - * include labels, buttons, check buttons, and radio - * buttons. + * include labels, buttons, checkbuttons, and radiobuttons. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -19,183 +18,446 @@ #include "default.h" /* - * Class names for buttons, indexed by one of the type values above. + * Class names for buttons, indexed by one of the type values defined + * in tkButton.h. */ static char *classNames[] = {"Label", "Button", "Checkbutton", "Radiobutton"}; /* - * The class procedure table for the button widget. + * The following table defines the legal values for the -default option. + * It is used together with the "enum defaultValue" declaration in tkButton.h. */ -static int configFlags[] = {LABEL_MASK, BUTTON_MASK, - CHECK_BUTTON_MASK, RADIO_BUTTON_MASK}; +static char *defaultStrings[] = { + "active", "disabled", "normal", (char *) NULL +}; + +/* + * The following table defines the legal values for the -state option. + * It is used together with the "enum state" declaration in tkButton.h. + */ + +static char *stateStrings[] = { + "active", "disabled", "normal", (char *) NULL +}; /* - * Information used for parsing configuration specs: + * Information used for parsing configuration options. There is a + * separate table for each of the four widget classes. */ -Tk_ConfigSpec tkpButtonConfigSpecs[] = { - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_BUTTON_ACTIVE_BG_COLOR, Tk_Offset(TkButton, activeBorder), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK - |TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_BUTTON_ACTIVE_BG_MONO, Tk_Offset(TkButton, activeBorder), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK - |TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_BUTTON_ACTIVE_FG_COLOR, Tk_Offset(TkButton, activeFg), - BUTTON_MASK|TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_CHKRAD_ACTIVE_FG_COLOR, Tk_Offset(TkButton, activeFg), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_BUTTON_ACTIVE_FG_MONO, Tk_Offset(TkButton, activeFg), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK - |TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", - DEF_BUTTON_ANCHOR, Tk_Offset(TkButton, anchor), ALL_MASK}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_BUTTON_BG_COLOR, Tk_Offset(TkButton, normalBorder), - ALL_MASK | TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_BUTTON_BG_MONO, Tk_Offset(TkButton, normalBorder), - ALL_MASK | TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, ALL_MASK}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, ALL_MASK}, - {TK_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap", - DEF_BUTTON_BITMAP, Tk_Offset(TkButton, bitmap), - ALL_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_BUTTON_BORDER_WIDTH, Tk_Offset(TkButton, borderWidth), ALL_MASK}, - {TK_CONFIG_STRING, "-command", "command", "Command", - DEF_BUTTON_COMMAND, Tk_Offset(TkButton, command), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_BUTTON_CURSOR, Tk_Offset(TkButton, cursor), - ALL_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-default", "default", "Default", - DEF_BUTTON_DEFAULT, Tk_Offset(TkButton, defaultState), BUTTON_MASK}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", +static Tk_OptionSpec labelOptionSpecs[] = { + {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground", + DEF_BUTTON_ACTIVE_BG_COLOR, -1, Tk_Offset(TkButton, activeBorder), + 0, (ClientData) DEF_BUTTON_ACTIVE_BG_MONO, 0}, + {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "Background", + DEF_BUTTON_ACTIVE_FG_COLOR, -1, Tk_Offset(TkButton, activeFg), + TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_ACTIVE_FG_MONO, 0}, + {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", + DEF_BUTTON_ANCHOR, -1, Tk_Offset(TkButton, anchor), 0, 0, 0}, + {TK_OPTION_BORDER, "-background", "background", "Background", + DEF_BUTTON_BG_COLOR, -1, Tk_Offset(TkButton, normalBorder), + 0, (ClientData) DEF_BUTTON_BG_MONO, 0}, + {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, + {TK_OPTION_BITMAP, "-bitmap", "bitmap", "Bitmap", + DEF_BUTTON_BITMAP, -1, Tk_Offset(TkButton, bitmap), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + DEF_BUTTON_BORDER_WIDTH, Tk_Offset(TkButton, borderWidthPtr), + Tk_Offset(TkButton, borderWidth), 0, 0, 0}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + DEF_BUTTON_CURSOR, -1, Tk_Offset(TkButton, cursor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground", + "DisabledForeground", DEF_BUTTON_DISABLED_FG_COLOR, + -1, Tk_Offset(TkButton, disabledFg), TK_OPTION_NULL_OK, + (ClientData) DEF_BUTTON_DISABLED_FG_MONO, 0}, + {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + DEF_BUTTON_FONT, -1, Tk_Offset(TkButton, tkfont), 0, 0, 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + DEF_BUTTON_FG, -1, Tk_Offset(TkButton, normalFg), 0, 0, 0}, + {TK_OPTION_STRING, "-height", "height", "Height", + DEF_BUTTON_HEIGHT, Tk_Offset(TkButton, heightPtr), -1, 0, 0, 0}, + {TK_OPTION_BORDER, "-highlightbackground", "highlightBackground", + "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG_COLOR, + -1, Tk_Offset(TkButton, highlightBorder), 0, + (ClientData) DEF_BUTTON_HIGHLIGHT_BG_MONO, 0}, + {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", + DEF_BUTTON_HIGHLIGHT, -1, Tk_Offset(TkButton, highlightColorPtr), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", + "HighlightThickness", DEF_LABEL_HIGHLIGHT_WIDTH, + Tk_Offset(TkButton, highlightWidthPtr), + Tk_Offset(TkButton, highlightWidth), 0, 0, 0}, + {TK_OPTION_STRING, "-image", "image", "Image", + DEF_BUTTON_IMAGE, Tk_Offset(TkButton, imagePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", + DEF_BUTTON_JUSTIFY, -1, Tk_Offset(TkButton, justify), 0, 0, 0}, + {TK_OPTION_PIXELS, "-padx", "padX", "Pad", + DEF_LABCHKRAD_PADX, Tk_Offset(TkButton, padXPtr), + Tk_Offset(TkButton, padX), 0, 0, 0}, + {TK_OPTION_PIXELS, "-pady", "padY", "Pad", + DEF_LABCHKRAD_PADY, Tk_Offset(TkButton, padYPtr), + Tk_Offset(TkButton, padY), 0, 0, 0}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + DEF_LABCHKRAD_RELIEF, -1, Tk_Offset(TkButton, relief), 0, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", "state", "State", + DEF_BUTTON_STATE, -1, Tk_Offset(TkButton, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + DEF_LABEL_TAKE_FOCUS, Tk_Offset(TkButton, takeFocusPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-text", "text", "Text", + DEF_BUTTON_TEXT, Tk_Offset(TkButton, textPtr), -1, 0, 0, 0}, + {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", + DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarNamePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_INT, "-underline", "underline", "Underline", + DEF_BUTTON_UNDERLINE, -1, Tk_Offset(TkButton, underline), 0, 0, 0}, + {TK_OPTION_STRING, "-width", "width", "Width", + DEF_BUTTON_WIDTH, Tk_Offset(TkButton, widthPtr), -1, 0, 0, 0}, + {TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength", + DEF_BUTTON_WRAP_LENGTH, Tk_Offset(TkButton, wrapLengthPtr), + Tk_Offset(TkButton, wrapLength), 0, 0, 0}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0, 0, 0} +}; + +static Tk_OptionSpec buttonOptionSpecs[] = { + {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground", + DEF_BUTTON_ACTIVE_BG_COLOR, -1, Tk_Offset(TkButton, activeBorder), + 0, (ClientData) DEF_BUTTON_ACTIVE_BG_MONO, 0}, + {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "Background", + DEF_BUTTON_ACTIVE_FG_COLOR, -1, Tk_Offset(TkButton, activeFg), + TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_ACTIVE_FG_MONO, 0}, + {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", + DEF_BUTTON_ANCHOR, -1, Tk_Offset(TkButton, anchor), 0, 0, 0}, + {TK_OPTION_BORDER, "-background", "background", "Background", + DEF_BUTTON_BG_COLOR, -1, Tk_Offset(TkButton, normalBorder), + 0, (ClientData) DEF_BUTTON_BG_MONO, 0}, + {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, + {TK_OPTION_BITMAP, "-bitmap", "bitmap", "Bitmap", + DEF_BUTTON_BITMAP, -1, Tk_Offset(TkButton, bitmap), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + DEF_BUTTON_BORDER_WIDTH, Tk_Offset(TkButton, borderWidthPtr), + Tk_Offset(TkButton, borderWidth), 0, 0, 0}, + {TK_OPTION_STRING, "-command", "command", "Command", + DEF_BUTTON_COMMAND, Tk_Offset(TkButton, commandPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + DEF_BUTTON_CURSOR, -1, Tk_Offset(TkButton, cursor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-default", "default", "Default", + DEF_BUTTON_DEFAULT, -1, Tk_Offset(TkButton, defaultState), + 0, (ClientData) defaultStrings, 0}, + {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground", + "DisabledForeground", DEF_BUTTON_DISABLED_FG_COLOR, + -1, Tk_Offset(TkButton, disabledFg), TK_OPTION_NULL_OK, + (ClientData) DEF_BUTTON_DISABLED_FG_MONO, 0}, + {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + DEF_BUTTON_FONT, -1, Tk_Offset(TkButton, tkfont), 0, 0, 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + DEF_BUTTON_FG, -1, Tk_Offset(TkButton, normalFg), 0, 0, 0}, + {TK_OPTION_STRING, "-height", "height", "Height", + DEF_BUTTON_HEIGHT, Tk_Offset(TkButton, heightPtr), -1, 0, 0, 0}, + {TK_OPTION_BORDER, "-highlightbackground", "highlightBackground", + "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG_COLOR, + -1, Tk_Offset(TkButton, highlightBorder), 0, + (ClientData) DEF_BUTTON_HIGHLIGHT_BG_MONO, 0}, + {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", + DEF_BUTTON_HIGHLIGHT, -1, Tk_Offset(TkButton, highlightColorPtr), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", + "HighlightThickness", DEF_BUTTON_HIGHLIGHT_WIDTH, + Tk_Offset(TkButton, highlightWidthPtr), + Tk_Offset(TkButton, highlightWidth), 0, 0, 0}, + {TK_OPTION_STRING, "-image", "image", "Image", + DEF_BUTTON_IMAGE, Tk_Offset(TkButton, imagePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", + DEF_BUTTON_JUSTIFY, -1, Tk_Offset(TkButton, justify), 0, 0, 0}, + {TK_OPTION_PIXELS, "-padx", "padX", "Pad", + DEF_BUTTON_PADX, Tk_Offset(TkButton, padXPtr), + Tk_Offset(TkButton, padX), 0, 0, 0}, + {TK_OPTION_PIXELS, "-pady", "padY", "Pad", + DEF_BUTTON_PADY, Tk_Offset(TkButton, padYPtr), + Tk_Offset(TkButton, padY), 0, 0, 0}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + DEF_BUTTON_RELIEF, -1, Tk_Offset(TkButton, relief), 0, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", "state", "State", + DEF_BUTTON_STATE, -1, Tk_Offset(TkButton, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + DEF_BUTTON_TAKE_FOCUS, Tk_Offset(TkButton, takeFocusPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-text", "text", "Text", + DEF_BUTTON_TEXT, Tk_Offset(TkButton, textPtr), -1, 0, 0, 0}, + {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", + DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarNamePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_INT, "-underline", "underline", "Underline", + DEF_BUTTON_UNDERLINE, -1, Tk_Offset(TkButton, underline), 0, 0, 0}, + {TK_OPTION_STRING, "-width", "width", "Width", + DEF_BUTTON_WIDTH, Tk_Offset(TkButton, widthPtr), -1, 0, 0, 0}, + {TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength", + DEF_BUTTON_WRAP_LENGTH, Tk_Offset(TkButton, wrapLengthPtr), + Tk_Offset(TkButton, wrapLength), 0, 0, 0}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, 0, 0} +}; + +static Tk_OptionSpec checkbuttonOptionSpecs[] = { + {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground", + DEF_BUTTON_ACTIVE_BG_COLOR, -1, Tk_Offset(TkButton, activeBorder), + 0, (ClientData) DEF_BUTTON_ACTIVE_BG_MONO, 0}, + {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "Background", + DEF_CHKRAD_ACTIVE_FG_COLOR, -1, Tk_Offset(TkButton, activeFg), + TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_ACTIVE_FG_MONO, 0}, + {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", + DEF_BUTTON_ANCHOR, -1, Tk_Offset(TkButton, anchor), 0, 0, 0}, + {TK_OPTION_BORDER, "-background", "background", "Background", + DEF_BUTTON_BG_COLOR, -1, Tk_Offset(TkButton, normalBorder), + 0, (ClientData) DEF_BUTTON_BG_MONO, 0}, + {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, + {TK_OPTION_BITMAP, "-bitmap", "bitmap", "Bitmap", + DEF_BUTTON_BITMAP, -1, Tk_Offset(TkButton, bitmap), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + DEF_BUTTON_BORDER_WIDTH, Tk_Offset(TkButton, borderWidthPtr), + Tk_Offset(TkButton, borderWidth), 0, 0, 0}, + {TK_OPTION_STRING, "-command", "command", "Command", + DEF_BUTTON_COMMAND, Tk_Offset(TkButton, commandPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + DEF_BUTTON_CURSOR, -1, Tk_Offset(TkButton, cursor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground", "DisabledForeground", DEF_BUTTON_DISABLED_FG_COLOR, - Tk_Offset(TkButton, disabledFg), BUTTON_MASK|CHECK_BUTTON_MASK - |RADIO_BUTTON_MASK|TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", - "DisabledForeground", DEF_BUTTON_DISABLED_FG_MONO, - Tk_Offset(TkButton, disabledFg), BUTTON_MASK|CHECK_BUTTON_MASK - |RADIO_BUTTON_MASK|TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, ALL_MASK}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_BUTTON_FONT, Tk_Offset(TkButton, tkfont), - ALL_MASK}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_BUTTON_FG, Tk_Offset(TkButton, normalFg), LABEL_MASK|BUTTON_MASK}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_CHKRAD_FG, Tk_Offset(TkButton, normalFg), CHECK_BUTTON_MASK - |RADIO_BUTTON_MASK}, - {TK_CONFIG_STRING, "-height", "height", "Height", - DEF_BUTTON_HEIGHT, Tk_Offset(TkButton, heightString), ALL_MASK}, - {TK_CONFIG_BORDER, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG, - Tk_Offset(TkButton, highlightBorder), ALL_MASK}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_BUTTON_HIGHLIGHT, Tk_Offset(TkButton, highlightColorPtr), - ALL_MASK}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_LABEL_HIGHLIGHT_WIDTH, Tk_Offset(TkButton, highlightWidth), - LABEL_MASK}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_BUTTON_HIGHLIGHT_WIDTH, Tk_Offset(TkButton, highlightWidth), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_STRING, "-image", "image", "Image", - DEF_BUTTON_IMAGE, Tk_Offset(TkButton, imageString), - ALL_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn", - DEF_BUTTON_INDICATOR, Tk_Offset(TkButton, indicatorOn), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", - DEF_BUTTON_JUSTIFY, Tk_Offset(TkButton, justify), ALL_MASK}, - {TK_CONFIG_STRING, "-offvalue", "offValue", "Value", - DEF_BUTTON_OFF_VALUE, Tk_Offset(TkButton, offValue), - CHECK_BUTTON_MASK}, - {TK_CONFIG_STRING, "-onvalue", "onValue", "Value", - DEF_BUTTON_ON_VALUE, Tk_Offset(TkButton, onValue), - CHECK_BUTTON_MASK}, - {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", - DEF_BUTTON_PADX, Tk_Offset(TkButton, padX), BUTTON_MASK}, - {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", - DEF_LABCHKRAD_PADX, Tk_Offset(TkButton, padX), - LABEL_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", - DEF_BUTTON_PADY, Tk_Offset(TkButton, padY), BUTTON_MASK}, - {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", - DEF_LABCHKRAD_PADY, Tk_Offset(TkButton, padY), - LABEL_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_BUTTON_RELIEF, Tk_Offset(TkButton, relief), BUTTON_MASK}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_LABCHKRAD_RELIEF, Tk_Offset(TkButton, relief), - LABEL_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_BORDER, "-selectcolor", "selectColor", "Background", - DEF_BUTTON_SELECT_COLOR, Tk_Offset(TkButton, selectBorder), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_COLOR_ONLY - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_BORDER, "-selectcolor", "selectColor", "Background", - DEF_BUTTON_SELECT_MONO, Tk_Offset(TkButton, selectBorder), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_MONO_ONLY - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-selectimage", "selectImage", "SelectImage", - DEF_BUTTON_SELECT_IMAGE, Tk_Offset(TkButton, selectImageString), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-state", "state", "State", - DEF_BUTTON_STATE, Tk_Offset(TkButton, state), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_LABEL_TAKE_FOCUS, Tk_Offset(TkButton, takeFocus), - LABEL_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_BUTTON_TAKE_FOCUS, Tk_Offset(TkButton, takeFocus), - BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-text", "text", "Text", - DEF_BUTTON_TEXT, Tk_Offset(TkButton, text), ALL_MASK}, - {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable", - DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarName), - ALL_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-underline", "underline", "Underline", - DEF_BUTTON_UNDERLINE, Tk_Offset(TkButton, underline), ALL_MASK}, - {TK_CONFIG_STRING, "-value", "value", "Value", - DEF_BUTTON_VALUE, Tk_Offset(TkButton, onValue), - RADIO_BUTTON_MASK}, - {TK_CONFIG_STRING, "-variable", "variable", "Variable", - DEF_RADIOBUTTON_VARIABLE, Tk_Offset(TkButton, selVarName), - RADIO_BUTTON_MASK}, - {TK_CONFIG_STRING, "-variable", "variable", "Variable", - DEF_CHECKBUTTON_VARIABLE, Tk_Offset(TkButton, selVarName), - CHECK_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-width", "width", "Width", - DEF_BUTTON_WIDTH, Tk_Offset(TkButton, widthString), ALL_MASK}, - {TK_CONFIG_PIXELS, "-wraplength", "wrapLength", "WrapLength", - DEF_BUTTON_WRAP_LENGTH, Tk_Offset(TkButton, wrapLength), ALL_MASK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} + -1, Tk_Offset(TkButton, disabledFg), TK_OPTION_NULL_OK, + (ClientData) DEF_BUTTON_DISABLED_FG_MONO, 0}, + {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + DEF_BUTTON_FONT, -1, Tk_Offset(TkButton, tkfont), 0, 0, 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + DEF_CHKRAD_FG, -1, Tk_Offset(TkButton, normalFg), 0, 0, 0}, + {TK_OPTION_STRING, "-height", "height", "Height", + DEF_BUTTON_HEIGHT, Tk_Offset(TkButton, heightPtr), -1, 0, 0, 0}, + {TK_OPTION_BORDER, "-highlightbackground", "highlightBackground", + "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG_COLOR, + -1, Tk_Offset(TkButton, highlightBorder), 0, + (ClientData) DEF_BUTTON_HIGHLIGHT_BG_MONO, 0}, + {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", + DEF_BUTTON_HIGHLIGHT, -1, Tk_Offset(TkButton, highlightColorPtr), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", + "HighlightThickness", DEF_BUTTON_HIGHLIGHT_WIDTH, + Tk_Offset(TkButton, highlightWidthPtr), + Tk_Offset(TkButton, highlightWidth), 0, 0, 0}, + {TK_OPTION_STRING, "-image", "image", "Image", + DEF_BUTTON_IMAGE, Tk_Offset(TkButton, imagePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn", + DEF_BUTTON_INDICATOR, -1, Tk_Offset(TkButton, indicatorOn), 0, 0, 0}, + {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", + DEF_BUTTON_JUSTIFY, -1, Tk_Offset(TkButton, justify), 0, 0, 0}, + {TK_OPTION_STRING, "-offvalue", "offValue", "Value", + DEF_BUTTON_OFF_VALUE, Tk_Offset(TkButton, offValuePtr), -1, 0, 0, 0}, + {TK_OPTION_STRING, "-onvalue", "onValue", "Value", + DEF_BUTTON_ON_VALUE, Tk_Offset(TkButton, onValuePtr), -1, 0, 0, 0}, + {TK_OPTION_PIXELS, "-padx", "padX", "Pad", + DEF_LABCHKRAD_PADX, Tk_Offset(TkButton, padXPtr), + Tk_Offset(TkButton, padX), 0, 0, 0}, + {TK_OPTION_PIXELS, "-pady", "padY", "Pad", + DEF_LABCHKRAD_PADY, Tk_Offset(TkButton, padYPtr), + Tk_Offset(TkButton, padY), 0, 0, 0}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + DEF_LABCHKRAD_RELIEF, -1, Tk_Offset(TkButton, relief), 0, 0, 0}, + {TK_OPTION_BORDER, "-selectcolor", "selectColor", "Background", + DEF_BUTTON_SELECT_COLOR, -1, Tk_Offset(TkButton, selectBorder), + TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_SELECT_MONO, 0}, + {TK_OPTION_STRING, "-selectimage", "selectImage", "SelectImage", + DEF_BUTTON_SELECT_IMAGE, Tk_Offset(TkButton, selectImagePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", "state", "State", + DEF_BUTTON_STATE, -1, Tk_Offset(TkButton, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + DEF_BUTTON_TAKE_FOCUS, Tk_Offset(TkButton, takeFocusPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-text", "text", "Text", + DEF_BUTTON_TEXT, Tk_Offset(TkButton, textPtr), -1, 0, 0, 0}, + {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", + DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarNamePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_INT, "-underline", "underline", "Underline", + DEF_BUTTON_UNDERLINE, -1, Tk_Offset(TkButton, underline), 0, 0, 0}, + {TK_OPTION_STRING, "-variable", "variable", "Variable", + DEF_CHECKBUTTON_VARIABLE, Tk_Offset(TkButton, selVarNamePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-width", "width", "Width", + DEF_BUTTON_WIDTH, Tk_Offset(TkButton, widthPtr), -1, 0, 0, 0}, + {TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength", + DEF_BUTTON_WRAP_LENGTH, Tk_Offset(TkButton, wrapLengthPtr), + Tk_Offset(TkButton, wrapLength), 0, 0, 0}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, 0, 0} +}; + +static Tk_OptionSpec radiobuttonOptionSpecs[] = { + {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground", + DEF_BUTTON_ACTIVE_BG_COLOR, -1, Tk_Offset(TkButton, activeBorder), + 0, (ClientData) DEF_BUTTON_ACTIVE_BG_MONO, 0}, + {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "Background", + DEF_CHKRAD_ACTIVE_FG_COLOR, -1, Tk_Offset(TkButton, activeFg), + TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_ACTIVE_FG_MONO, 0}, + {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", + DEF_BUTTON_ANCHOR, -1, Tk_Offset(TkButton, anchor), 0, 0, 0}, + {TK_OPTION_BORDER, "-background", "background", "Background", + DEF_BUTTON_BG_COLOR, -1, Tk_Offset(TkButton, normalBorder), + 0, (ClientData) DEF_BUTTON_BG_MONO, 0}, + {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, + {TK_OPTION_BITMAP, "-bitmap", "bitmap", "Bitmap", + DEF_BUTTON_BITMAP, -1, Tk_Offset(TkButton, bitmap), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + DEF_BUTTON_BORDER_WIDTH, Tk_Offset(TkButton, borderWidthPtr), + Tk_Offset(TkButton, borderWidth), 0, 0, 0}, + {TK_OPTION_STRING, "-command", "command", "Command", + DEF_BUTTON_COMMAND, Tk_Offset(TkButton, commandPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + DEF_BUTTON_CURSOR, -1, Tk_Offset(TkButton, cursor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground", + "DisabledForeground", DEF_BUTTON_DISABLED_FG_COLOR, + -1, Tk_Offset(TkButton, disabledFg), TK_OPTION_NULL_OK, + (ClientData) DEF_BUTTON_DISABLED_FG_MONO, 0}, + {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + DEF_BUTTON_FONT, -1, Tk_Offset(TkButton, tkfont), 0, 0, 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + DEF_CHKRAD_FG, -1, Tk_Offset(TkButton, normalFg), 0, 0, 0}, + {TK_OPTION_STRING, "-height", "height", "Height", + DEF_BUTTON_HEIGHT, Tk_Offset(TkButton, heightPtr), -1, 0, 0, 0}, + {TK_OPTION_BORDER, "-highlightbackground", "highlightBackground", + "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG_COLOR, + -1, Tk_Offset(TkButton, highlightBorder), 0, + (ClientData) DEF_BUTTON_HIGHLIGHT_BG_MONO, 0}, + {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", + DEF_BUTTON_HIGHLIGHT, -1, Tk_Offset(TkButton, highlightColorPtr), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", + "HighlightThickness", DEF_BUTTON_HIGHLIGHT_WIDTH, + Tk_Offset(TkButton, highlightWidthPtr), + Tk_Offset(TkButton, highlightWidth), 0, 0, 0}, + {TK_OPTION_STRING, "-image", "image", "Image", + DEF_BUTTON_IMAGE, Tk_Offset(TkButton, imagePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn", + DEF_BUTTON_INDICATOR, -1, Tk_Offset(TkButton, indicatorOn), + 0, 0, 0}, + {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", + DEF_BUTTON_JUSTIFY, -1, Tk_Offset(TkButton, justify), 0, 0, 0}, + {TK_OPTION_PIXELS, "-padx", "padX", "Pad", + DEF_LABCHKRAD_PADX, Tk_Offset(TkButton, padXPtr), + Tk_Offset(TkButton, padX), 0, 0, 0}, + {TK_OPTION_PIXELS, "-pady", "padY", "Pad", + DEF_LABCHKRAD_PADY, Tk_Offset(TkButton, padYPtr), + Tk_Offset(TkButton, padY), 0, 0, 0}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + DEF_LABCHKRAD_RELIEF, -1, Tk_Offset(TkButton, relief), 0, 0, 0}, + {TK_OPTION_BORDER, "-selectcolor", "selectColor", "Background", + DEF_BUTTON_SELECT_COLOR, -1, Tk_Offset(TkButton, selectBorder), + TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_SELECT_MONO, 0}, + {TK_OPTION_STRING, "-selectimage", "selectImage", "SelectImage", + DEF_BUTTON_SELECT_IMAGE, Tk_Offset(TkButton, selectImagePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", "state", "State", + DEF_BUTTON_STATE, -1, Tk_Offset(TkButton, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + DEF_BUTTON_TAKE_FOCUS, Tk_Offset(TkButton, takeFocusPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-text", "text", "Text", + DEF_BUTTON_TEXT, Tk_Offset(TkButton, textPtr), -1, 0, 0, 0}, + {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", + DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarNamePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_INT, "-underline", "underline", "Underline", + DEF_BUTTON_UNDERLINE, -1, Tk_Offset(TkButton, underline), 0, 0, 0}, + {TK_OPTION_STRING, "-value", "value", "Value", + DEF_BUTTON_VALUE, Tk_Offset(TkButton, onValuePtr), -1, 0, 0, 0}, + {TK_OPTION_STRING, "-variable", "variable", "Variable", + DEF_RADIOBUTTON_VARIABLE, Tk_Offset(TkButton, selVarNamePtr), -1, + 0, 0, 0}, + {TK_OPTION_STRING, "-width", "width", "Width", + DEF_BUTTON_WIDTH, Tk_Offset(TkButton, widthPtr), -1, 0, 0, 0}, + {TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength", + DEF_BUTTON_WRAP_LENGTH, Tk_Offset(TkButton, wrapLengthPtr), + Tk_Offset(TkButton, wrapLength), 0, 0, 0}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, 0, 0} +}; + +/* + * The following table maps from one of the type values defined in + * tkButton.h, such as TYPE_LABEL, to the option template for that + * class of widgets. + */ + +static Tk_OptionSpec *optionSpecs[] = { + labelOptionSpecs, + buttonOptionSpecs, + checkbuttonOptionSpecs, + radiobuttonOptionSpecs }; /* - * String to print out in error messages, identifying options for - * widget commands for different types of labels or buttons: + * The following tables define the widget commands supported by + * each of the classes, and map the indexes into the string tables + * into a single enumerated type used to dispatch the widget command. */ -static char *optionStrings[] = { - "cget or configure", - "cget, configure, flash, or invoke", - "cget, configure, deselect, flash, invoke, select, or toggle", - "cget, configure, deselect, flash, invoke, or select" +static char *commandNames[][8] = { + {"cget", "configure", (char *) NULL}, + {"cget", "configure", "flash", "invoke", (char *) NULL}, + {"cget", "configure", "deselect", "flash", "invoke", "select", + "toggle", (char *) NULL}, + {"cget", "configure", "deselect", "flash", "invoke", "select", + (char *) NULL} +}; +enum command { + COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DESELECT, COMMAND_FLASH, + COMMAND_INVOKE, COMMAND_SELECT, COMMAND_TOGGLE +}; +static enum command map[][8] = { + {COMMAND_CGET, COMMAND_CONFIGURE}, + {COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_FLASH, COMMAND_INVOKE}, + {COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DESELECT, COMMAND_FLASH, + COMMAND_INVOKE, COMMAND_SELECT, COMMAND_TOGGLE}, + {COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DESELECT, COMMAND_FLASH, + COMMAND_INVOKE, COMMAND_SELECT} }; /* @@ -205,8 +467,8 @@ static char *optionStrings[] = { static void ButtonCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static int ButtonCreate _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv, - int type)); + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[], int type)); static void ButtonEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static void ButtonImageProc _ANSI_ARGS_((ClientData clientData, @@ -221,13 +483,13 @@ static char * ButtonTextVarProc _ANSI_ARGS_((ClientData clientData, static char * ButtonVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)); -static int ButtonWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); +static int ButtonWidgetObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); static int ConfigureButton _ANSI_ARGS_((Tcl_Interp *interp, - TkButton *butPtr, int argc, char **argv, - int flags)); + TkButton *butPtr, int objc, + Tcl_Obj *CONST objv[])); static void DestroyButton _ANSI_ARGS_((TkButton *butPtr)); - /* *-------------------------------------------------------------- @@ -249,47 +511,43 @@ static void DestroyButton _ANSI_ARGS_((TkButton *butPtr)); */ int -Tk_ButtonCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ +Tk_ButtonObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Either NULL or pointer to option table. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument values. */ { - return ButtonCreate(clientData, interp, argc, argv, TYPE_BUTTON); + return ButtonCreate(clientData, interp, objc, objv, TYPE_BUTTON); } int -Tk_CheckbuttonCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ +Tk_CheckbuttonObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Either NULL or pointer to option table. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument values. */ { - return ButtonCreate(clientData, interp, argc, argv, TYPE_CHECK_BUTTON); + return ButtonCreate(clientData, interp, objc, objv, TYPE_CHECK_BUTTON); } int -Tk_LabelCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ +Tk_LabelObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Either NULL or pointer to option table. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument values. */ { - return ButtonCreate(clientData, interp, argc, argv, TYPE_LABEL); + return ButtonCreate(clientData, interp, objc, objv, TYPE_LABEL); } int -Tk_RadiobuttonCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ +Tk_RadiobuttonObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Either NULL or pointer to option table. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument values. */ { - return ButtonCreate(clientData, interp, argc, argv, TYPE_RADIO_BUTTON); + return ButtonCreate(clientData, interp, objc, objv, TYPE_RADIO_BUTTON); } /* @@ -311,23 +569,42 @@ Tk_RadiobuttonCmd(clientData, interp, argc, argv) */ static int -ButtonCreate(clientData, interp, argc, argv, type) - ClientData clientData; /* Main window associated with - * interpreter. */ +ButtonCreate(clientData, interp, objc, objv, type) + ClientData clientData; /* Option table for this widget class, or + * NULL if not created yet. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument values. */ int type; /* Type of button to create: TYPE_LABEL, * TYPE_BUTTON, TYPE_CHECK_BUTTON, or * TYPE_RADIO_BUTTON. */ { - register TkButton *butPtr; - Tk_Window tkwin = (Tk_Window) clientData; - Tk_Window new; + TkButton *butPtr; + Tk_OptionTable optionTable; + Tk_Window tkwin; + + optionTable = (Tk_OptionTable) clientData; + if (optionTable == NULL) { + Tcl_CmdInfo info; + char *name; + + /* + * We haven't created the option table for this widget class + * yet. Do it now and save the table as the clientData for + * the command, so we'll have access to it in future + * invocations of the command. + */ + + TkpButtonSetDefaults(optionSpecs[type]); + optionTable = Tk_CreateOptionTable(interp, optionSpecs[type]); + name = Tcl_GetString(objv[0]); + Tcl_GetCommandInfo(interp, name, &info); + info.objClientData = (ClientData) optionTable; + Tcl_SetCommandInfo(interp, name, &info); + } - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } @@ -335,39 +612,43 @@ ButtonCreate(clientData, interp, argc, argv, type) * Create the new window. */ - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { + tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), + Tcl_GetString(objv[1]), (char *) NULL); + if (tkwin == NULL) { return TCL_ERROR; } - Tk_SetClass(new, classNames[type]); - butPtr = TkpCreateButton(new); + Tk_SetClass(tkwin, classNames[type]); + butPtr = TkpCreateButton(tkwin); - TkSetClassProcs(new, &tkpButtonProcs, (ClientData) butPtr); + TkSetClassProcs(tkwin, &tkpButtonProcs, (ClientData) butPtr); /* * Initialize the data structure for the button. */ - butPtr->tkwin = new; - butPtr->display = Tk_Display(new); - butPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(butPtr->tkwin), - ButtonWidgetCmd, (ClientData) butPtr, ButtonCmdDeletedProc); + butPtr->tkwin = tkwin; + butPtr->display = Tk_Display(tkwin); butPtr->interp = interp; + butPtr->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(tkwin), + ButtonWidgetObjCmd, (ClientData) butPtr, ButtonCmdDeletedProc); butPtr->type = type; - butPtr->text = NULL; + butPtr->optionTable = optionTable; + butPtr->textPtr = NULL; butPtr->underline = -1; - butPtr->textVarName = NULL; + butPtr->textVarNamePtr = NULL; butPtr->bitmap = None; - butPtr->imageString = NULL; + butPtr->imagePtr = NULL; butPtr->image = NULL; - butPtr->selectImageString = NULL; + butPtr->selectImagePtr = NULL; butPtr->selectImage = NULL; - butPtr->state = tkNormalUid; + butPtr->state = STATE_NORMAL; butPtr->normalBorder = NULL; butPtr->activeBorder = NULL; + butPtr->borderWidthPtr = NULL; butPtr->borderWidth = 0; butPtr->relief = TK_RELIEF_FLAT; + butPtr->highlightWidthPtr = NULL; butPtr->highlightWidth = 0; butPtr->highlightBorder = NULL; butPtr->highlightColorPtr = NULL; @@ -378,43 +659,53 @@ ButtonCreate(clientData, interp, argc, argv, type) butPtr->disabledFg = NULL; butPtr->normalTextGC = None; butPtr->activeTextGC = None; - butPtr->gray = None; butPtr->disabledGC = None; + butPtr->gray = None; butPtr->copyGC = None; - butPtr->widthString = NULL; - butPtr->heightString = NULL; + butPtr->widthPtr = NULL; butPtr->width = 0; + butPtr->heightPtr = NULL; butPtr->height = 0; + butPtr->wrapLengthPtr = NULL; butPtr->wrapLength = 0; + butPtr->padXPtr = NULL; butPtr->padX = 0; + butPtr->padYPtr = NULL; butPtr->padY = 0; butPtr->anchor = TK_ANCHOR_CENTER; butPtr->justify = TK_JUSTIFY_CENTER; - butPtr->textLayout = NULL; butPtr->indicatorOn = 0; butPtr->selectBorder = NULL; + butPtr->textWidth = 0; + butPtr->textHeight = 0; + butPtr->textLayout = NULL; butPtr->indicatorSpace = 0; butPtr->indicatorDiameter = 0; - butPtr->defaultState = tkDisabledUid; - butPtr->selVarName = NULL; - butPtr->onValue = NULL; - butPtr->offValue = NULL; + butPtr->defaultState = DEFAULT_DISABLED; + butPtr->selVarNamePtr = NULL; + butPtr->onValuePtr = NULL; + butPtr->offValuePtr = NULL; butPtr->cursor = None; - butPtr->command = NULL; - butPtr->takeFocus = NULL; + butPtr->takeFocusPtr = NULL; + butPtr->commandPtr = NULL; butPtr->flags = 0; Tk_CreateEventHandler(butPtr->tkwin, ExposureMask|StructureNotifyMask|FocusChangeMask, ButtonEventProc, (ClientData) butPtr); - if (ConfigureButton(interp, butPtr, argc - 2, argv + 2, - configFlags[type]) != TCL_OK) { + if (Tk_InitOptions(interp, (char *) butPtr, optionTable, tkwin) + != TCL_OK) { + Tk_DestroyWindow(butPtr->tkwin); + return TCL_ERROR; + } + if (ConfigureButton(interp, butPtr, objc - 2, objv + 2) != TCL_OK) { Tk_DestroyWindow(butPtr->tkwin); return TCL_ERROR; } - interp->result = Tk_PathName(butPtr->tkwin); + Tcl_SetStringObj(Tcl_GetObjResult(interp), Tk_PathName(butPtr->tkwin), + -1); return TCL_OK; } @@ -437,147 +728,155 @@ ButtonCreate(clientData, interp, argc, argv, type) */ static int -ButtonWidgetCmd(clientData, interp, argc, argv) +ButtonWidgetObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about button widget. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument values. */ { - register TkButton *butPtr = (TkButton *) clientData; - int result = TCL_OK; - size_t length; - int c; - - if (argc < 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s option ?arg arg ...?\"", - argv[0]); + TkButton *butPtr = (TkButton *) clientData; + int index; + int result; + Tcl_Obj *objPtr; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } + result = Tcl_GetIndexFromObj(interp, objv[1], commandNames[butPtr->type], + "option", 0, &index); + if (result != TCL_OK) { + return result; + } Tcl_Preserve((ClientData) butPtr); - c = argv[1][0]; - length = strlen(argv[1]); - - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, butPtr->tkwin, tkpButtonConfigSpecs, - (char *) butPtr, argv[2], configFlags[butPtr->type]); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, butPtr->tkwin, - tkpButtonConfigSpecs, (char *) butPtr, (char *) NULL, - configFlags[butPtr->type]); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, butPtr->tkwin, - tkpButtonConfigSpecs, (char *) butPtr, argv[2], - configFlags[butPtr->type]); - } else { - result = ConfigureButton(interp, butPtr, argc-2, argv+2, - configFlags[butPtr->type] | TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'd') && (strncmp(argv[1], "deselect", length) == 0) - && (butPtr->type >= TYPE_CHECK_BUTTON)) { - if (argc > 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s deselect\"", - argv[0]); - goto error; - } - if (butPtr->type == TYPE_CHECK_BUTTON) { - if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->offValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; + + switch (map[butPtr->type][index]) { + case COMMAND_CGET: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "cget option"); + goto error; } - } else if (butPtr->flags & SELECTED) { - if (Tcl_SetVar(interp, butPtr->selVarName, "", - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - }; - } - } else if ((c == 'f') && (strncmp(argv[1], "flash", length) == 0) - && (butPtr->type != TYPE_LABEL)) { - int i; - - if (argc > 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s flash\"", - argv[0]); - goto error; - } - if (butPtr->state != tkDisabledUid) { - for (i = 0; i < 4; i++) { - butPtr->state = (butPtr->state == tkNormalUid) - ? tkActiveUid : tkNormalUid; - Tk_SetBackgroundFromBorder(butPtr->tkwin, - (butPtr->state == tkActiveUid) ? butPtr->activeBorder - : butPtr->normalBorder); - TkpDisplayButton((ClientData) butPtr); - - /* - * Special note: must cancel any existing idle handler - * for TkpDisplayButton; it's no longer needed, and TkpDisplayButton - * cleared the REDRAW_PENDING flag. - */ - - Tcl_CancelIdleCall(TkpDisplayButton, (ClientData) butPtr); - XFlush(butPtr->display); - Tcl_Sleep(50); + objPtr = Tk_GetOptionValue(interp, (char *) butPtr, + butPtr->optionTable, objv[2], butPtr->tkwin); + if (objPtr == NULL) { + goto error; + } else { + Tcl_SetObjResult(interp, objPtr); } + break; } - } else if ((c == 'i') && (strncmp(argv[1], "invoke", length) == 0) - && (butPtr->type > TYPE_LABEL)) { - if (argc > 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s invoke\"", - argv[0]); - goto error; + + case COMMAND_CONFIGURE: { + if (objc <= 3) { + objPtr = Tk_GetOptionInfo(interp, (char *) butPtr, + butPtr->optionTable, + (objc == 3) ? objv[2] : (Tcl_Obj *) NULL, + butPtr->tkwin); + if (objPtr == NULL) { + goto error; + } else { + Tcl_SetObjResult(interp, objPtr); + } + } else { + result = ConfigureButton(interp, butPtr, objc-2, objv+2); + } + break; } - if (butPtr->state != tkDisabledUid) { - result = TkInvokeButton(butPtr); + + case COMMAND_DESELECT: { + if (objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, "deselect"); + goto error; + } + if (butPtr->type == TYPE_CHECK_BUTTON) { + if (Tcl_ObjSetVar2(interp, butPtr->selVarNamePtr, NULL, + butPtr->offValuePtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) + == NULL) { + goto error; + } + } else if (butPtr->flags & SELECTED) { + if (Tcl_ObjSetVar2(interp, + butPtr->selVarNamePtr, NULL, Tcl_NewObj(), + TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) + == NULL) { + goto error; + } + } + break; } - } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0) - && (butPtr->type >= TYPE_CHECK_BUTTON)) { - if (argc > 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s select\"", - argv[0]); - goto error; + + case COMMAND_FLASH: { + int i; + + if (objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, "flash"); + goto error; + } + if (butPtr->state != STATE_DISABLED) { + for (i = 0; i < 4; i++) { + if (butPtr->state == STATE_NORMAL) { + butPtr->state = STATE_ACTIVE; + Tk_SetBackgroundFromBorder(butPtr->tkwin, + butPtr->activeBorder); + } else { + butPtr->state = STATE_NORMAL; + Tk_SetBackgroundFromBorder(butPtr->tkwin, + butPtr->normalBorder); + } + TkpDisplayButton((ClientData) butPtr); + + /* + * Special note: must cancel any existing idle handler + * for TkpDisplayButton; it's no longer needed, and + * TkpDisplayButton cleared the REDRAW_PENDING flag. + */ + + Tcl_CancelIdleCall(TkpDisplayButton, (ClientData) butPtr); + XFlush(butPtr->display); + Tcl_Sleep(50); + } + } + break; } - if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->onValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; + + case COMMAND_INVOKE: { + if (objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, "invoke"); + goto error; + } + if (butPtr->state != STATE_DISABLED) { + result = TkInvokeButton(butPtr); + } + break; } - } else if ((c == 't') && (strncmp(argv[1], "toggle", length) == 0) - && (length >= 2) && (butPtr->type == TYPE_CHECK_BUTTON)) { - if (argc > 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s toggle\"", - argv[0]); - goto error; + + case COMMAND_SELECT: { + if (objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, "select"); + goto error; + } + if (Tcl_ObjSetVar2(interp, butPtr->selVarNamePtr, NULL, + butPtr->onValuePtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) + == NULL) { + goto error; + } + break; } - if (butPtr->flags & SELECTED) { - if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->offValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; + + case COMMAND_TOGGLE: { + if (objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, "toggle"); + goto error; } - } else { - if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->onValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; + if (Tcl_ObjSetVar2(interp, butPtr->selVarNamePtr, NULL, + (butPtr->flags & SELECTED) ? butPtr->offValuePtr + : butPtr->onValuePtr, + TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) + == NULL) { + goto error; } + break; } - } else { - sprintf(interp->result, - "bad option \"%.50s\": must be %s", argv[1], - optionStrings[butPtr->type]); - goto error; } Tcl_Release((ClientData) butPtr); return result; @@ -592,15 +891,14 @@ ButtonWidgetCmd(clientData, interp, argc, argv) * * DestroyButton -- * - * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release - * to clean up the internal structure of a button at a safe time - * (when no-one is using it anymore). + * This procedure is invoked by ButtonEventProc to free all the + * resources of a button and clean up its state. * * Results: * None. * * Side effects: - * Everything associated with the widget is freed up. + * Everything associated with the widget is freed. * *---------------------------------------------------------------------- */ @@ -609,14 +907,22 @@ static void DestroyButton(butPtr) TkButton *butPtr; /* Info about button widget. */ { + TkpDestroyButton(butPtr); + + butPtr->flags |= BUTTON_DELETED; + if (butPtr->flags & REDRAW_PENDING) { + Tcl_CancelIdleCall(TkpDisplayButton, (ClientData) butPtr); + } + /* * Free up all the stuff that requires special handling, then * let Tk_FreeOptions handle all the standard option-related * stuff. */ - if (butPtr->textVarName != NULL) { - Tcl_UntraceVar(butPtr->interp, butPtr->textVarName, + Tcl_DeleteCommandFromToken(butPtr->interp, butPtr->widgetCmd); + if (butPtr->textVarNamePtr != NULL) { + Tcl_UntraceVar(butPtr->interp, Tcl_GetString(butPtr->textVarNamePtr), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ButtonTextVarProc, (ClientData) butPtr); } @@ -632,24 +938,27 @@ DestroyButton(butPtr) if (butPtr->activeTextGC != None) { Tk_FreeGC(butPtr->display, butPtr->activeTextGC); } - if (butPtr->gray != None) { - Tk_FreeBitmap(butPtr->display, butPtr->gray); - } if (butPtr->disabledGC != None) { Tk_FreeGC(butPtr->display, butPtr->disabledGC); } + if (butPtr->gray != None) { + Tk_FreeBitmap(butPtr->display, butPtr->gray); + } if (butPtr->copyGC != None) { Tk_FreeGC(butPtr->display, butPtr->copyGC); } - if (butPtr->selVarName != NULL) { - Tcl_UntraceVar(butPtr->interp, butPtr->selVarName, + if (butPtr->textLayout != NULL) { + Tk_FreeTextLayout(butPtr->textLayout); + } + if (butPtr->selVarNamePtr != NULL) { + Tcl_UntraceVar(butPtr->interp, Tcl_GetString(butPtr->selVarNamePtr), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ButtonVarProc, (ClientData) butPtr); } - Tk_FreeTextLayout(butPtr->textLayout); - Tk_FreeOptions(tkpButtonConfigSpecs, (char *) butPtr, butPtr->display, - configFlags[butPtr->type]); - Tcl_EventuallyFree((ClientData)butPtr, TCL_DYNAMIC); + Tk_FreeConfigOptions((char *) butPtr, butPtr->optionTable, + butPtr->tkwin); + butPtr->tkwin = NULL; + Tcl_EventuallyFree((ClientData) butPtr, TCL_DYNAMIC); } /* @@ -657,13 +966,12 @@ DestroyButton(butPtr) * * ConfigureButton -- * - * This procedure is called to process an argv/argc list, plus - * the Tk option database, in order to configure (or - * reconfigure) a button widget. + * This procedure is called to process an objc/objv list to set + * configuration options for a button widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then an error message is left in interp's result. * * Side effects: * Configuration information, such as text string, colors, font, @@ -674,199 +982,244 @@ DestroyButton(butPtr) */ static int -ConfigureButton(interp, butPtr, argc, argv, flags) +ConfigureButton(interp, butPtr, objc, objv) Tcl_Interp *interp; /* Used for error reporting. */ register TkButton *butPtr; /* Information about widget; may or may * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument values. */ { + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int error; Tk_Image image; /* * Eliminate any existing trace on variables monitored by the button. */ - if (butPtr->textVarName != NULL) { - Tcl_UntraceVar(interp, butPtr->textVarName, + if (butPtr->textVarNamePtr != NULL) { + Tcl_UntraceVar(interp, Tcl_GetString(butPtr->textVarNamePtr), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ButtonTextVarProc, (ClientData) butPtr); } - if (butPtr->selVarName != NULL) { - Tcl_UntraceVar(interp, butPtr->selVarName, + if (butPtr->selVarNamePtr != NULL) { + Tcl_UntraceVar(interp, Tcl_GetString(butPtr->selVarNamePtr), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ButtonVarProc, (ClientData) butPtr); } - - - if (Tk_ConfigureWidget(interp, butPtr->tkwin, tkpButtonConfigSpecs, - argc, argv, (char *) butPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - /* - * A few options need special processing, such as setting the - * background from a 3-D border, or filling in complicated - * defaults that couldn't be specified to Tk_ConfigureWidget. + * The following loop is potentially executed twice. During the + * first pass configuration options get set to their new values. + * If there is an error in this pass, we execute a second pass + * to restore all the options to their previous values. */ - if ((butPtr->state == tkActiveUid) && !Tk_StrictMotif(butPtr->tkwin)) { - Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->activeBorder); - } else { - Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->normalBorder); - if ((butPtr->state != tkNormalUid) && (butPtr->state != tkActiveUid) - && (butPtr->state != tkDisabledUid)) { - Tcl_AppendResult(interp, "bad state value \"", butPtr->state, - "\": must be normal, active, or disabled", (char *) NULL); - butPtr->state = tkNormalUid; - return TCL_ERROR; - } - } + for (error = 0; error <= 1; error++) { + if (!error) { + /* + * First pass: set options to new values. + */ - if ((butPtr->defaultState != tkActiveUid) - && (butPtr->defaultState != tkDisabledUid) - && (butPtr->defaultState != tkNormalUid)) { - Tcl_AppendResult(interp, "bad -default value \"", butPtr->defaultState, - "\": must be normal, active, or disabled", (char *) NULL); - butPtr->defaultState = tkDisabledUid; - return TCL_ERROR; - } + if (Tk_SetOptions(interp, (char *) butPtr, + butPtr->optionTable, objc, objv, + butPtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) { + continue; + } + } else { + /* + * Second pass: restore options to old values. + */ - if (butPtr->highlightWidth < 0) { - butPtr->highlightWidth = 0; - } + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } - if (butPtr->padX < 0) { - butPtr->padX = 0; - } - if (butPtr->padY < 0) { - butPtr->padY = 0; - } + /* + * A few options need special processing, such as setting the + * background from a 3-D border, or filling in complicated + * defaults that couldn't be specified to Tk_SetOptions. + */ - if (butPtr->type >= TYPE_CHECK_BUTTON) { - char *value; + if ((butPtr->state == STATE_ACTIVE) + && !Tk_StrictMotif(butPtr->tkwin)) { + Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->activeBorder); + } else { + Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->normalBorder); + } + if (butPtr->borderWidth < 0) { + butPtr->borderWidth = 0; + } + if (butPtr->highlightWidth < 0) { + butPtr->highlightWidth = 0; + } + if (butPtr->padX < 0) { + butPtr->padX = 0; + } + if (butPtr->padY < 0) { + butPtr->padY = 0; + } - if (butPtr->selVarName == NULL) { - butPtr->selVarName = (char *) ckalloc((unsigned) - (strlen(Tk_Name(butPtr->tkwin)) + 1)); - strcpy(butPtr->selVarName, Tk_Name(butPtr->tkwin)); + if (butPtr->type >= TYPE_CHECK_BUTTON) { + Tcl_Obj *valuePtr, *namePtr; + + if (butPtr->selVarNamePtr == NULL) { + butPtr->selVarNamePtr = Tcl_NewStringObj( + Tk_Name(butPtr->tkwin), -1); + Tcl_IncrRefCount(butPtr->selVarNamePtr); + } + namePtr = butPtr->selVarNamePtr; + + /* + * Select the button if the associated variable has the + * appropriate value, initialize the variable if it doesn't + * exist, then set a trace on the variable to monitor future + * changes to its value. + */ + + valuePtr = Tcl_ObjGetVar2(interp, namePtr, NULL, TCL_GLOBAL_ONLY); + butPtr->flags &= ~SELECTED; + if (valuePtr != NULL) { + if (strcmp(Tcl_GetString(valuePtr), + Tcl_GetString(butPtr->onValuePtr)) == 0) { + butPtr->flags |= SELECTED; + } + } else { + if (Tcl_ObjSetVar2(interp, namePtr, NULL, + (butPtr->type == TYPE_CHECK_BUTTON) + ? butPtr->offValuePtr : Tcl_NewObj(), + TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) + == NULL) { + continue; + } + } } /* - * Select the button if the associated variable has the - * appropriate value, initialize the variable if it doesn't - * exist, then set a trace on the variable to monitor future - * changes to its value. + * Get the images for the widget, if there are any. Allocate the + * new images before freeing the old ones, so that the reference + * counts don't go to zero and cause image data to be discarded. */ - - value = Tcl_GetVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY); - butPtr->flags &= ~SELECTED; - if (value != NULL) { - if (strcmp(value, butPtr->onValue) == 0) { - butPtr->flags |= SELECTED; + + if (butPtr->imagePtr != NULL) { + image = Tk_GetImage(butPtr->interp, butPtr->tkwin, + Tcl_GetString(butPtr->imagePtr), ButtonImageProc, + (ClientData) butPtr); + if (image == NULL) { + continue; } } else { - if (Tcl_SetVar(interp, butPtr->selVarName, - (butPtr->type == TYPE_CHECK_BUTTON) ? butPtr->offValue : "", - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - return TCL_ERROR; + image = NULL; + } + if (butPtr->image != NULL) { + Tk_FreeImage(butPtr->image); + } + butPtr->image = image; + if (butPtr->selectImagePtr != NULL) { + image = Tk_GetImage(butPtr->interp, butPtr->tkwin, + Tcl_GetString(butPtr->selectImagePtr), + ButtonSelectImageProc, (ClientData) butPtr); + if (image == NULL) { + continue; } + } else { + image = NULL; } - Tcl_TraceVar(interp, butPtr->selVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ButtonVarProc, (ClientData) butPtr); - } - - /* - * Get the images for the widget, if there are any. Allocate the - * new images before freeing the old ones, so that the reference - * counts don't go to zero and cause image data to be discarded. - */ - - if (butPtr->imageString != NULL) { - image = Tk_GetImage(butPtr->interp, butPtr->tkwin, - butPtr->imageString, ButtonImageProc, (ClientData) butPtr); - if (image == NULL) { - return TCL_ERROR; + if (butPtr->selectImage != NULL) { + Tk_FreeImage(butPtr->selectImage); } - } else { - image = NULL; - } - if (butPtr->image != NULL) { - Tk_FreeImage(butPtr->image); - } - butPtr->image = image; - if (butPtr->selectImageString != NULL) { - image = Tk_GetImage(butPtr->interp, butPtr->tkwin, - butPtr->selectImageString, ButtonSelectImageProc, - (ClientData) butPtr); - if (image == NULL) { - return TCL_ERROR; + butPtr->selectImage = image; + + if ((butPtr->imagePtr == NULL) && (butPtr->bitmap == None) + && (butPtr->textVarNamePtr != NULL)) { + /* + * The button must display the value of a variable: set up a trace + * on the variable's value, create the variable if it doesn't + * exist, and fetch its current value. + */ + + Tcl_Obj *valuePtr, *namePtr; + + namePtr = butPtr->textVarNamePtr; + valuePtr = Tcl_ObjGetVar2(interp, namePtr, NULL, TCL_GLOBAL_ONLY); + if (valuePtr == NULL) { + if (Tcl_ObjSetVar2(interp, namePtr, NULL, butPtr->textPtr, + TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) + == NULL) { + continue; + } + } else { + if (butPtr->textPtr != NULL) { + Tcl_DecrRefCount(butPtr->textPtr); + } + butPtr->textPtr = valuePtr; + Tcl_IncrRefCount(butPtr->textPtr); + } } - } else { - image = NULL; - } - if (butPtr->selectImage != NULL) { - Tk_FreeImage(butPtr->selectImage); - } - butPtr->selectImage = image; - - if ((butPtr->image == NULL) && (butPtr->bitmap == None) - && (butPtr->textVarName != NULL)) { - /* - * The button must display the value of a variable: set up a trace - * on the variable's value, create the variable if it doesn't - * exist, and fetch its current value. - */ - - char *value; - - value = Tcl_GetVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - if (Tcl_SetVar(interp, butPtr->textVarName, butPtr->text, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - return TCL_ERROR; + + if ((butPtr->bitmap != None) || (butPtr->imagePtr != NULL)) { + /* + * The button must display the contents of an image or + * bitmap. + */ + + if (Tk_GetPixelsFromObj(interp, butPtr->tkwin, butPtr->widthPtr, + &butPtr->width) != TCL_OK) { + widthError: + Tcl_AddErrorInfo(interp, "\n (processing -width option)"); + continue; + } + if (Tk_GetPixelsFromObj(interp, butPtr->tkwin, butPtr->heightPtr, + &butPtr->height) != TCL_OK) { + heightError: + Tcl_AddErrorInfo(interp, "\n (processing -height option)"); + continue; } } else { - if (butPtr->text != NULL) { - ckfree(butPtr->text); + /* + * The button displays an ordinary text string. + */ + + if (Tcl_GetIntFromObj(interp, butPtr->widthPtr, &butPtr->width) + != TCL_OK) { + goto widthError; + } + if (Tcl_GetIntFromObj(interp, butPtr->heightPtr, &butPtr->height) + != TCL_OK) { + goto heightError; } - butPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1)); - strcpy(butPtr->text, value); } - Tcl_TraceVar(interp, butPtr->textVarName, + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + } + + /* + * Reestablish the variable traces, if they're needed. + */ + + if (butPtr->textVarNamePtr != NULL) { + Tcl_TraceVar(interp, Tcl_GetString(butPtr->textVarNamePtr), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ButtonTextVarProc, (ClientData) butPtr); } - - if ((butPtr->bitmap != None) || (butPtr->image != NULL)) { - if (Tk_GetPixels(interp, butPtr->tkwin, butPtr->widthString, - &butPtr->width) != TCL_OK) { - widthError: - Tcl_AddErrorInfo(interp, "\n (processing -width option)"); - return TCL_ERROR; - } - if (Tk_GetPixels(interp, butPtr->tkwin, butPtr->heightString, - &butPtr->height) != TCL_OK) { - heightError: - Tcl_AddErrorInfo(interp, "\n (processing -height option)"); - return TCL_ERROR; - } - } else { - if (Tcl_GetInt(interp, butPtr->widthString, &butPtr->width) - != TCL_OK) { - goto widthError; - } - if (Tcl_GetInt(interp, butPtr->heightString, &butPtr->height) - != TCL_OK) { - goto heightError; - } + if (butPtr->selVarNamePtr != NULL) { + Tcl_TraceVar(interp, Tcl_GetString(butPtr->selVarNamePtr), + TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + ButtonVarProc, (ClientData) butPtr); } TkButtonWorldChanged((ClientData) butPtr); - return TCL_OK; + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + return TCL_OK; + } } /* @@ -914,60 +1267,48 @@ TkButtonWorldChanged(instanceData) gcValues.graphics_exposures = False; mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures; - newGC = Tk_GetGCColor(butPtr->tkwin, mask, &gcValues, - butPtr->normalFg, - Tk_3DBorderColor(butPtr->normalBorder)); + newGC = Tk_GetGC(butPtr->tkwin, mask, &gcValues); if (butPtr->normalTextGC != None) { Tk_FreeGC(butPtr->display, butPtr->normalTextGC); } butPtr->normalTextGC = newGC; if (butPtr->activeFg != NULL) { - gcValues.font = Tk_FontId(butPtr->tkfont); gcValues.foreground = butPtr->activeFg->pixel; gcValues.background = Tk_3DBorderColor(butPtr->activeBorder)->pixel; mask = GCForeground | GCBackground | GCFont; - newGC = Tk_GetGCColor(butPtr->tkwin, mask, &gcValues, - butPtr->activeFg, - Tk_3DBorderColor(butPtr->activeBorder)); + newGC = Tk_GetGC(butPtr->tkwin, mask, &gcValues); if (butPtr->activeTextGC != None) { Tk_FreeGC(butPtr->display, butPtr->activeTextGC); } butPtr->activeTextGC = newGC; } - if (butPtr->type != TYPE_LABEL) { - XColor *foreground, *background; - - gcValues.font = Tk_FontId(butPtr->tkfont); - background = Tk_3DBorderColor(butPtr->normalBorder); - gcValues.background = background->pixel; - if ((butPtr->disabledFg != NULL) && (butPtr->imageString == NULL)) { - foreground = butPtr->disabledFg; - gcValues.foreground = foreground->pixel; - mask = GCForeground | GCBackground | GCFont; - } else { - foreground = background; - background = NULL; - gcValues.foreground = gcValues.background; - mask = GCForeground; - if (butPtr->gray == None) { - butPtr->gray = Tk_GetBitmap(NULL, butPtr->tkwin, - Tk_GetUid("gray50")); - } - if (butPtr->gray != None) { - gcValues.fill_style = FillStippled; - gcValues.stipple = butPtr->gray; - mask |= GCFillStyle | GCStipple; - } + /* + * Allocate the disabled graphics context, for drawing the widget in + * its disabled state + */ + gcValues.background = Tk_3DBorderColor(butPtr->normalBorder)->pixel; + if ((butPtr->disabledFg != NULL) && (butPtr->imagePtr == NULL)) { + gcValues.foreground = butPtr->disabledFg->pixel; + mask = GCForeground | GCBackground | GCFont; + } else { + gcValues.foreground = gcValues.background; + mask = GCForeground; + if (butPtr->gray == None) { + butPtr->gray = Tk_GetBitmap(NULL, butPtr->tkwin, "gray50"); } - newGC = Tk_GetGCColor(butPtr->tkwin, mask, &gcValues, foreground, - background); - if (butPtr->disabledGC != None) { - Tk_FreeGC(butPtr->display, butPtr->disabledGC); + if (butPtr->gray != None) { + gcValues.fill_style = FillStippled; + gcValues.stipple = butPtr->gray; + mask |= GCFillStyle | GCStipple; } - butPtr->disabledGC = newGC; } + newGC = Tk_GetGC(butPtr->tkwin, mask, &gcValues); + if (butPtr->disabledGC != None) { + Tk_FreeGC(butPtr->display, butPtr->disabledGC); + } + butPtr->disabledGC = newGC; if (butPtr->copyGC == None) { butPtr->copyGC = Tk_GetGC(butPtr->tkwin, 0, &gcValues); @@ -1019,14 +1360,6 @@ ButtonEventProc(clientData, eventPtr) goto redraw; } else if (eventPtr->type == DestroyNotify) { - TkpDestroyButton(butPtr); - if (butPtr->tkwin != NULL) { - butPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(butPtr->interp, butPtr->widgetCmd); - } - if (butPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(TkpDisplayButton, (ClientData) butPtr); - } DestroyButton(butPtr); } else if (eventPtr->type == FocusIn) { if (eventPtr->xfocus.detail != NotifyInferior) { @@ -1075,18 +1408,16 @@ ButtonCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { TkButton *butPtr = (TkButton *) clientData; - Tk_Window tkwin = butPtr->tkwin; /* * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. + * destroyed and the command was then deleted or because the command + * was deleted, and then this procedure destroys the widget. The + * BUTTON_DELETED flag distinguishes these cases. */ - if (tkwin != NULL) { - butPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); + if (!(butPtr->flags & BUTTON_DELETED)) { + Tk_DestroyWindow(butPtr->tkwin); } } @@ -1102,7 +1433,7 @@ ButtonCmdDeletedProc(clientData) * * Results: * A standard Tcl return value. Information is also left in - * interp->result. + * the interp's result. * * Side effects: * Depends on the button and its associated command. @@ -1112,28 +1443,34 @@ ButtonCmdDeletedProc(clientData) int TkInvokeButton(butPtr) - register TkButton *butPtr; /* Information about button. */ + TkButton *butPtr; /* Information about button. */ { + Tcl_Obj *namePtr = butPtr->selVarNamePtr; + if (butPtr->type == TYPE_CHECK_BUTTON) { if (butPtr->flags & SELECTED) { - if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->offValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { + if (Tcl_ObjSetVar2(butPtr->interp, namePtr, NULL, + butPtr->offValuePtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) + == NULL) { return TCL_ERROR; } } else { - if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->onValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { + if (Tcl_ObjSetVar2(butPtr->interp, namePtr, NULL, + butPtr->onValuePtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) + == NULL) { return TCL_ERROR; } } } else if (butPtr->type == TYPE_RADIO_BUTTON) { - if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->onValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { + if (Tcl_ObjSetVar2(butPtr->interp, namePtr, NULL, butPtr->onValuePtr, + TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) + == NULL) { return TCL_ERROR; } } - if ((butPtr->type != TYPE_LABEL) && (butPtr->command != NULL)) { - return TkCopyAndGlobalEval(butPtr->interp, butPtr->command); + if ((butPtr->type != TYPE_LABEL) && (butPtr->commandPtr != NULL)) { + return Tcl_EvalObjEx(butPtr->interp, butPtr->commandPtr, + TCL_EVAL_GLOBAL); } return TCL_OK; } @@ -1167,7 +1504,10 @@ ButtonVarProc(clientData, interp, name1, name2, flags) int flags; /* Information about what happened. */ { register TkButton *butPtr = (TkButton *) clientData; - char *value; + char *name, *value; + Tcl_Obj *valuePtr; + + name = Tcl_GetString(butPtr->selVarNamePtr); /* * If the variable is being unset, then just re-establish the @@ -1177,7 +1517,7 @@ ButtonVarProc(clientData, interp, name1, name2, flags) if (flags & TCL_TRACE_UNSETS) { butPtr->flags &= ~SELECTED; if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { - Tcl_TraceVar(interp, butPtr->selVarName, + Tcl_TraceVar(interp, name, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ButtonVarProc, clientData); } @@ -1189,11 +1529,13 @@ ButtonVarProc(clientData, interp, name1, name2, flags) * the button. */ - value = Tcl_GetVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { + valuePtr = Tcl_GetVar2Ex(interp, name, NULL, TCL_GLOBAL_ONLY); + if (valuePtr == NULL) { value = ""; + } else { + value = Tcl_GetString(valuePtr); } - if (strcmp(value, butPtr->onValue) == 0) { + if (strcmp(value, Tcl_GetString(butPtr->onValuePtr)) == 0) { if (butPtr->flags & SELECTED) { return (char *) NULL; } @@ -1240,8 +1582,11 @@ ButtonTextVarProc(clientData, interp, name1, name2, flags) char *name2; /* Not used. */ int flags; /* Information about what happened. */ { - register TkButton *butPtr = (TkButton *) clientData; - char *value; + TkButton *butPtr = (TkButton *) clientData; + char *name; + Tcl_Obj *valuePtr; + + name = Tcl_GetString(butPtr->textVarNamePtr); /* * If the variable is unset, then immediately recreate it unless @@ -1250,24 +1595,22 @@ ButtonTextVarProc(clientData, interp, name1, name2, flags) if (flags & TCL_TRACE_UNSETS) { if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { - Tcl_SetVar(interp, butPtr->textVarName, butPtr->text, + Tcl_SetVar2Ex(interp, name, NULL, butPtr->textPtr, TCL_GLOBAL_ONLY); - Tcl_TraceVar(interp, butPtr->textVarName, + Tcl_TraceVar(interp, name, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ButtonTextVarProc, clientData); } return (char *) NULL; } - value = Tcl_GetVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - value = ""; - } - if (butPtr->text != NULL) { - ckfree(butPtr->text); + valuePtr = Tcl_GetVar2Ex(interp, name, NULL, TCL_GLOBAL_ONLY); + if (valuePtr == NULL) { + valuePtr = Tcl_NewObj(); } - butPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1)); - strcpy(butPtr->text, value); + Tcl_DecrRefCount(butPtr->textPtr); + butPtr->textPtr = valuePtr; + Tcl_IncrRefCount(butPtr->textPtr); TkpComputeButtonGeometry(butPtr); if ((butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin) @@ -1284,7 +1627,7 @@ ButtonTextVarProc(clientData, interp, name1, name2, flags) * ButtonImageProc -- * * This procedure is invoked by the image code whenever the manager - * for an image does something that affects the size of contents + * for an image does something that affects the size or contents * of an image displayed in a button. * * Results: @@ -1322,7 +1665,7 @@ ButtonImageProc(clientData, x, y, width, height, imgWidth, imgHeight) * ButtonSelectImageProc -- * * This procedure is invoked by the image code whenever the manager - * for an image does something that affects the size of contents + * for an image does something that affects the size or contents * of the image displayed in a button when it is selected. * * Results: diff --git a/tk/generic/tkButton.h b/tk/generic/tkButton.h index 6236fc74c30..d0e28822c16 100644 --- a/tk/generic/tkButton.h +++ b/tk/generic/tkButton.h @@ -4,7 +4,7 @@ * Declarations of types and functions used to implement * button-like widgets. * - * Copyright (c) 1996 by Sun Microsystems, Inc. + * Copyright (c) 1996-1998 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -25,6 +25,22 @@ #endif /* + * Legal values for the "state" field of TkButton records. + */ + +enum state { + STATE_ACTIVE, STATE_DISABLED, STATE_NORMAL +}; + +/* + * Legal values for the "defaultState" field of TkButton records. + */ + +enum defaultState { + DEFAULT_ACTIVE, DEFAULT_DISABLED, DEFAULT_NORMAL +}; + +/* * A data structure of the following type is kept for each * widget managed by this file: */ @@ -36,69 +52,88 @@ typedef struct { * free up resources after tkwin is gone. */ Tcl_Interp *interp; /* Interpreter associated with button. */ Tcl_Command widgetCmd; /* Token for button's widget command. */ - int type; /* Type of widget: restricts operations - * that may be performed on widget. See - * below for possible values. */ + int type; /* Type of widget, such as TYPE_LABEL: + * restricts operations that may be performed + * on widget. See below for legal values. */ + Tk_OptionTable optionTable; /* Table that defines configuration options + * available for this widget. */ /* * Information about what's in the button. */ - char *text; /* Text to display in button (malloc'ed) - * or NULL. */ - int underline; /* Index of character to underline. < 0 means + Tcl_Obj *textPtr; /* Value of -text option: specifies text to + * display in button. */ + int underline; /* Value of -underline option: specifies + * index of character to underline. < 0 means * don't underline anything. */ - char *textVarName; /* Name of variable (malloc'ed) or NULL. - * If non-NULL, button displays the contents - * of this variable. */ - Pixmap bitmap; /* Bitmap to display or None. If not None - * then text and textVar are ignored. */ - char *imageString; /* Name of image to display (malloc'ed), or - * NULL. If non-NULL, bitmap, text, and - * textVarName are ignored. */ - Tk_Image image; /* Image to display in window, or NULL if - * none. */ - char *selectImageString; /* Name of image to display when selected - * (malloc'ed), or NULL. */ - Tk_Image selectImage; /* Image to display in window when selected, - * or NULL if none. Ignored if image is + Tcl_Obj *textVarNamePtr; /* Value of -textvariable option: specifies + * name of variable or NULL. If non-NULL, + * button displays the contents of this + * variable. */ + Pixmap bitmap; /* Value of -bitmap option. If not None, + * specifies bitmap to display and text and + * textVar are ignored. */ + Tcl_Obj *imagePtr; /* Value of -image option: specifies image + * to display in window, or NULL if none. + * If non-NULL, bitmap, text, and textVarName + * are ignored.*/ + Tk_Image image; /* Derived from imagePtr by calling + * Tk_GetImage, or NULL if imagePtr is NULL. */ + Tcl_Obj *selectImagePtr; /* Value of -selectimage option: specifies + * image to display in window when selected, + * or NULL if none. Ignored if imagePtr is * NULL. */ + Tk_Image selectImage; /* Derived from selectImagePtr by calling + * Tk_GetImage, or NULL if selectImagePtr + * is NULL. */ /* * Information used when displaying widget: */ - Tk_Uid state; /* State of button for display purposes: - * normal, active, or disabled. */ - Tk_3DBorder normalBorder; /* Structure used to draw 3-D - * border and background when window - * isn't active. NULL means no such - * border exists. */ - Tk_3DBorder activeBorder; /* Structure used to draw 3-D - * border and background when window - * is active. NULL means no such - * border exists. */ - int borderWidth; /* Width of border. */ - int relief; /* 3-d effect: TK_RELIEF_RAISED, etc. */ - int highlightWidth; /* Width in pixels of highlight to draw - * around widget when it has the focus. + enum state state; /* Value of -state option: specifies + * state of button for display purposes.*/ + Tk_3DBorder normalBorder; /* Value of -background option: specifies + * color for background (and border) when + * window isn't active. */ + Tk_3DBorder activeBorder; /* Value of -activebackground option: + * this is the color used to draw 3-D border + * and background when widget is active. */ + Tcl_Obj *borderWidthPtr; /* Value of -borderWidth option: specifies + * width of border in pixels. */ + int borderWidth; /* Integer value corresponding to + * borderWidthPtr. Always >= 0. */ + int relief; /* Value of -relief option: specifies 3-d + * effect for border, such as + * TK_RELIEF_RAISED. */ + Tcl_Obj *highlightWidthPtr; /* Value of -highlightthickness option: + * specifies width in pixels of highlight to + * draw around widget when it has the focus. * <= 0 means don't draw a highlight. */ - Tk_3DBorder highlightBorder; - /* Structure used to draw 3-D default ring - * and focus highlight area when highlight - * is off. */ - XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ - + int highlightWidth; /* Integer value corresponding to + * highlightWidthPtr. Always >= 0. */ + Tk_3DBorder highlightBorder;/* Value of -highlightbackground option: + * specifies background with which to draw 3-D + * default ring and focus highlight area when + * highlight is off. */ + XColor *highlightColorPtr; /* Value of -highlightcolor option: + * specifies color for drawing traversal + * highlight. */ int inset; /* Total width of all borders, including * traversal highlight and 3-D border. * Indicates how much interior stuff must * be offset from outside edges to leave * room for borders. */ - Tk_Font tkfont; /* Information about text font, or NULL. */ - XColor *normalFg; /* Foreground color in normal mode. */ - XColor *activeFg; /* Foreground color in active mode. NULL - * means use normalFg instead. */ - XColor *disabledFg; /* Foreground color when disabled. NULL + Tk_Font tkfont; /* Value of -font option: specifies font + * to use for display text. */ + XColor *normalFg; /* Value of -font option: specifies foreground + * color in normal mode. */ + XColor *activeFg; /* Value of -activeforeground option: + * foreground color in active mode. NULL + * means use -foreground instead. */ + XColor *disabledFg; /* Value of -disabledforeground option: + * foreground color when disabled. NULL * means use normalFg with a 50% stipple * instead. */ GC normalTextGC; /* GC for drawing text in normal mode. Also @@ -106,36 +141,47 @@ typedef struct { * screen. */ GC activeTextGC; /* GC for drawing text in active mode (NULL * means use normalTextGC). */ - Pixmap gray; /* Pixmap for displaying disabled text if - * disabledFg is NULL. */ GC disabledGC; /* Used to produce disabled effect. If * disabledFg isn't NULL, this GC is used to * draw button text or icon. Otherwise * text or icon is drawn with normalGC and * this GC is used to stipple background * across it. For labels this is None. */ + Pixmap gray; /* Pixmap for displaying disabled text if + * disabledFg is NULL. */ GC copyGC; /* Used for copying information from an * off-screen pixmap to the screen. */ - char *widthString; /* Value of -width option. Malloc'ed. */ - char *heightString; /* Value of -height option. Malloc'ed. */ - int width, height; /* If > 0, these specify dimensions to request - * for window, in characters for text and in - * pixels for bitmaps. In this case the actual - * size of the text string or bitmap is - * ignored in computing desired window size. */ - int wrapLength; /* Line length (in pixels) at which to wrap + Tcl_Obj *widthPtr; /* Value of -width option. */ + int width; /* Integer value corresponding to widthPtr. */ + Tcl_Obj *heightPtr; /* Value of -height option. */ + int height; /* Integer value corresponding to heightPtr. */ + Tcl_Obj *wrapLengthPtr; /* Value of -wraplength option: specifies + * line length (in pixels) at which to wrap * onto next line. <= 0 means don't wrap * except at newlines. */ - int padX, padY; /* Extra space around text (pixels to leave - * on each side). Ignored for bitmaps and + int wrapLength; /* Integer value corresponding to + * wrapLengthPtr. */ + Tcl_Obj *padXPtr; /* Value of -padx option: specifies how many + * pixels of extra space to leave on left and + * right of text. Ignored for bitmaps and + * images. */ + int padX; /* Integer value corresponding to padXPtr. */ + Tcl_Obj *padYPtr; /* Value of -padx option: specifies how many + * pixels of extra space to leave above and + * below text. Ignored for bitmaps and * images. */ - Tk_Anchor anchor; /* Where text/bitmap should be displayed - * inside button region. */ - Tk_Justify justify; /* Justification to use for multi-line text. */ - int indicatorOn; /* True means draw indicator, false means - * don't draw it. */ - Tk_3DBorder selectBorder; /* For drawing indicator background, or perhaps - * widget background, when selected. */ + int padY; /* Integer value corresponding to padYPtr. */ + Tk_Anchor anchor; /* Value of -anchor option: specifies where + * text/bitmap should be displayed inside + * button region. */ + Tk_Justify justify; /* Value of -justify option: specifies how + * to align lines of multi-line text. */ + int indicatorOn; /* Value of -indicatoron option: 1 means + * draw indicator in checkbuttons and + * radiobuttons, 0 means don't draw it. */ + Tk_3DBorder selectBorder; /* Value of -selectcolor option: specifies + * color for drawing indicator background, or + * perhaps widget background, when selected. */ int textWidth; /* Width needed to display text as requested, * in pixels. */ int textHeight; /* Height needed to display text as requested, @@ -144,36 +190,42 @@ typedef struct { int indicatorSpace; /* Horizontal space (in pixels) allocated for * display of indicator. */ int indicatorDiameter; /* Diameter of indicator, in pixels. */ - Tk_Uid defaultState; /* State of default ring: normal, active, or - * disabled. */ - + enum defaultState defaultState; + /* Value of -default option, such as + * DEFAULT_NORMAL: specifies state + * of default ring for buttons (normal, + * active, or disabled). NULL for other + * classes. */ + /* * For check and radio buttons, the fields below are used * to manage the variable indicating the button's state. */ - char *selVarName; /* Name of variable used to control selected - * state of button. Malloc'ed (if - * not NULL). */ - char *onValue; /* Value to store in variable when - * this button is selected. Malloc'ed (if - * not NULL). */ - char *offValue; /* Value to store in variable when this - * button isn't selected. Malloc'ed - * (if not NULL). Valid only for check - * buttons. */ + Tcl_Obj *selVarNamePtr; /* Value of -variable option: specifies name + * of variable used to control selected + * state of button. */ + Tcl_Obj *onValuePtr; /* Value of -offvalue option: specifies value + * to store in variable when this button is + * selected. */ + Tcl_Obj *offValuePtr; /* Value of -offvalue option: specifies value + * to store in variable when this button + * isn't selected. Used only by + * checkbuttons. */ /* * Miscellaneous information: */ - Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *takeFocus; /* Value of -takefocus option; not used in + Tk_Cursor cursor; /* Value of -cursor option: if not None, + * specifies current cursor for window. */ + Tcl_Obj *takeFocusPtr; /* Value of -takefocus option; not used in * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ - char *command; /* Command to execute when button is - * invoked; valid for buttons only. - * If not NULL, it's malloc-ed. */ + * scripts. */ + Tcl_Obj *commandPtr; /* Value of -command option: specifies script + * to execute when button is invoked. If + * widget is label or has no command, this + * is NULL. */ int flags; /* Various flags; see below for * definitions. */ } TkButton; @@ -200,36 +252,31 @@ typedef struct { * so special highlight should be drawn. * GOT_FOCUS: Non-zero means this button currently * has the input focus. + * BUTTON_DELETED: Non-zero needs that this button has been + * deleted, or is in the process of being + * deleted. */ #define REDRAW_PENDING 1 #define SELECTED 2 #define GOT_FOCUS 4 - -/* - * Mask values used to selectively enable entries in the - * configuration specs: - */ - -#define LABEL_MASK TK_CONFIG_USER_BIT -#define BUTTON_MASK TK_CONFIG_USER_BIT << 1 -#define CHECK_BUTTON_MASK TK_CONFIG_USER_BIT << 2 -#define RADIO_BUTTON_MASK TK_CONFIG_USER_BIT << 3 -#define ALL_MASK (LABEL_MASK | BUTTON_MASK \ - | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK) +#define BUTTON_DELETED 0x8 /* * Declaration of variables shared between the files in the button module. */ extern TkClassProcs tkpButtonProcs; -extern Tk_ConfigSpec tkpButtonConfigSpecs[]; /* * Declaration of procedures used in the implementation of the button * widget. */ +#ifndef TkpButtonSetDefaults +EXTERN void TkpButtonSetDefaults _ANSI_ARGS_(( + Tk_OptionSpec *specPtr)); +#endif EXTERN void TkButtonWorldChanged _ANSI_ARGS_(( ClientData instanceData)); EXTERN void TkpComputeButtonGeometry _ANSI_ARGS_(( @@ -247,3 +294,4 @@ EXTERN int TkInvokeButton _ANSI_ARGS_((TkButton *butPtr)); # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TKBUTTON */ + diff --git a/tk/generic/tkCanvArc.c b/tk/generic/tkCanvArc.c index cec4ef2b5fb..e2c3504fd1e 100644 --- a/tk/generic/tkCanvArc.c +++ b/tk/generic/tkCanvArc.c @@ -4,7 +4,7 @@ * This file implements arc items for canvas widgets. * * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -15,14 +15,19 @@ #include <stdio.h> #include "tkPort.h" #include "tkInt.h" - +#include "tkCanvas.h" /* * The structure below defines the record for each arc item. */ +typedef enum { + PIESLICE_STYLE, CHORD_STYLE, ARC_STYLE +} Style; + typedef struct ArcItem { Tk_Item header; /* Generic stuff that's the same for all * types. MUST BE FIRST IN STRUCTURE. */ + Tk_Outline outline; /* Outline structure */ double bbox[4]; /* Coordinates (x1, y1, x2, y2) of bounding * box for oval of which arc is a piece. */ double start; /* Angle at which arc begins, in degrees @@ -38,16 +43,22 @@ typedef struct ArcItem { * for a chord). Malloc'ed. */ int numOutlinePoints; /* Number of points at outlinePtr. Zero * means no space allocated. */ - int width; /* Width of outline (in pixels). */ - XColor *outlineColor; /* Color for outline. NULL means don't - * draw outline. */ + Tk_TSOffset tsoffset; XColor *fillColor; /* Color for filling arc (used for drawing * outline too when style is "arc"). NULL * means don't fill arc. */ + XColor *activeFillColor; /* Color for filling arc (used for drawing + * outline too when style is "arc" and state + * is "active"). NULL means use fillColor. */ + XColor *disabledFillColor; /* Color for filling arc (used for drawing + * outline too when style is "arc" and state + * is "disabled". NULL means use fillColor */ Pixmap fillStipple; /* Stipple bitmap for filling item. */ - Pixmap outlineStipple; /* Stipple bitmap for outline. */ - Tk_Uid style; /* How to draw arc: arc, chord, or pieslice. */ - GC outlineGC; /* Graphics context for outline. */ + Pixmap activeFillStipple; /* Stipple bitmap for filling item if state + * is active. */ + Pixmap disabledFillStipple; /* Stipple bitmap for filling item if state + * is disabled. */ + Style style; /* How to draw arc: arc, chord, or pieslice. */ GC fillGC; /* Graphics context for filling item. */ double center1[2]; /* Coordinates of center of arc outline at * start (see ComputeArcOutline). */ @@ -68,29 +79,112 @@ typedef struct ArcItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static int StyleParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, + char *widgRec, int offset)); +static char * StylePrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); + +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption styleOption = { + (Tk_OptionParseProc *) StyleParseProc, + StylePrintProc, (ClientData) NULL +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; +static Tk_CustomOption dashOption = { + (Tk_OptionParseProc *) TkCanvasDashParseProc, + TkCanvasDashPrintProc, (ClientData) NULL +}; +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, (ClientData) (TK_OFFSET_RELATIVE) +}; +static Tk_CustomOption pixelOption = { + (Tk_OptionParseProc *) TkPixelParseProc, + TkPixelPrintProc, (ClientData) NULL +}; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_CUSTOM, "-activedash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.activeDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, activeFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-activeoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.activeColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activeoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.activeStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, activeFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-activewidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(ArcItem, outline.activeWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, + {TK_CONFIG_CUSTOM, "-dash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.dash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_PIXELS, "-dashoffset", (char *) NULL, (char *) NULL, + "0", Tk_Offset(ArcItem, outline.offset), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-disableddash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.disabledDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, disabledFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-disabledoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.disabledColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, outline.disabledStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, disabledFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-disabledwidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(ArcItem, outline.disabledWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_DOUBLE, "-extent", (char *) NULL, (char *) NULL, "90", Tk_Offset(ArcItem, extent), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ArcItem, fillColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(ArcItem, tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, - "black", Tk_Offset(ArcItem, outlineColor), TK_CONFIG_NULL_OK}, + "black", Tk_Offset(ArcItem, outline.color), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-outlineoffset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(ArcItem, outline.tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, {TK_CONFIG_BITMAP, "-outlinestipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(ArcItem, outlineStipple), TK_CONFIG_NULL_OK}, + (char *) NULL, Tk_Offset(ArcItem, outline.stipple), + TK_CONFIG_NULL_OK}, {TK_CONFIG_DOUBLE, "-start", (char *) NULL, (char *) NULL, "0", Tk_Offset(ArcItem, start), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ArcItem, fillStipple), TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-style", (char *) NULL, (char *) NULL, - "pieslice", Tk_Offset(ArcItem, style), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-style", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ArcItem, style), TK_CONFIG_DONT_SET_DEFAULT, + &styleOption}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(ArcItem, width), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-width", (char *) NULL, (char *) NULL, + "1.0", Tk_Offset(ArcItem, outline.width), TK_CONFIG_DONT_SET_DEFAULT, + &pixelOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; @@ -103,10 +197,10 @@ static void ComputeArcBbox _ANSI_ARGS_((Tk_Canvas canvas, ArcItem *arcPtr)); static int ConfigureArc _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateArc _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteArc _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayArc _ANSI_ARGS_((Tk_Canvas canvas, @@ -114,7 +208,7 @@ static void DisplayArc _ANSI_ARGS_((Tk_Canvas canvas, int x, int y, int width, int height)); static int ArcCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); + Tcl_Obj *CONST argv[])); static int ArcToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); static double ArcToPoint _ANSI_ARGS_((Tk_Canvas canvas, @@ -128,7 +222,8 @@ static void TranslateArc _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY)); static int AngleInRange _ANSI_ARGS_((double x, double y, double start, double extent)); -static void ComputeArcOutline _ANSI_ARGS_((ArcItem *arcPtr)); +static void ComputeArcOutline _ANSI_ARGS_((Tk_Canvas canvas, + ArcItem *arcPtr)); static int HorizLineToArc _ANSI_ARGS_((double x1, double x2, double y, double rx, double ry, double start, double extent)); @@ -150,7 +245,7 @@ Tk_ItemType tkArcType = { ArcCoords, /* coordProc */ DeleteArc, /* deleteProc */ DisplayArc, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ ArcToPoint, /* pointProc */ ArcToArea, /* areaProc */ ArcToPostscript, /* postscriptProc */ @@ -161,21 +256,13 @@ Tk_ItemType tkArcType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; #ifndef PI # define PI 3.14159265358979323846 #endif -/* - * The uid's below comprise the legal values for the "-style" - * option for arcs. - */ - -static Tk_Uid arcUid = NULL; -static Tk_Uid chordUid = NULL; -static Tk_Uid pieSliceUid = NULL; /* *-------------------------------------------------------------- @@ -188,7 +275,7 @@ static Tk_Uid pieSliceUid = NULL; * Results: * A standard Tcl return value. If an error occurred in * creating the item, then an error message is left in - * interp->result; in this case itemPtr is + * the interp's result; in this case itemPtr is * left uninitialized, so it can be safely freed by the * caller. * @@ -205,11 +292,23 @@ CreateArc(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing arc. */ + Tcl_Obj *CONST argv[]; /* Arguments describing arc. */ { ArcItem *arcPtr = (ArcItem *) itemPtr; + int i; - if (argc < 4) { + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj(argv[1], NULL); + if ((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z')) { + i = 1; + } else { + i = 4; + } + } + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?\"", @@ -218,52 +317,40 @@ CreateArc(interp, canvas, itemPtr, argc, argv) } /* - * Carry out once-only initialization. - */ - - if (arcUid == NULL) { - arcUid = Tk_GetUid("arc"); - chordUid = Tk_GetUid("chord"); - pieSliceUid = Tk_GetUid("pieslice"); - } - - /* * Carry out initialization that is needed in order to clean * up after errors during the the remainder of this procedure. */ + Tk_CreateOutline(&(arcPtr->outline)); arcPtr->start = 0; arcPtr->extent = 90; arcPtr->outlinePtr = NULL; arcPtr->numOutlinePoints = 0; - arcPtr->width = 1; - arcPtr->outlineColor = NULL; + arcPtr->tsoffset.flags = 0; + arcPtr->tsoffset.xoffset = 0; + arcPtr->tsoffset.yoffset = 0; arcPtr->fillColor = NULL; + arcPtr->activeFillColor = NULL; + arcPtr->disabledFillColor = NULL; arcPtr->fillStipple = None; - arcPtr->outlineStipple = None; - arcPtr->style = pieSliceUid; - arcPtr->outlineGC = None; + arcPtr->activeFillStipple = None; + arcPtr->disabledFillStipple = None; + arcPtr->style = PIESLICE_STYLE; arcPtr->fillGC = None; /* * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &arcPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &arcPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], - &arcPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], - &arcPtr->bbox[3]) != TCL_OK)) { - return TCL_ERROR; + if ((ArcCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureArc(interp, canvas, itemPtr, argc-4, argv+4, 0) != TCL_OK) { - DeleteArc(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureArc(interp, canvas, itemPtr, argc-4, argv+4, 0) == TCL_OK) { + return TCL_OK; } - return TCL_OK; + error: + DeleteArc(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -276,7 +363,7 @@ CreateArc(interp, canvas, itemPtr, argc, argv) * on what it does. * * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. * * Side effects: * The coordinates for the given item may be changed. @@ -292,36 +379,51 @@ ArcCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { ArcItem *arcPtr = (ArcItem *) itemPtr; - char c0[TCL_DOUBLE_SPACE], c1[TCL_DOUBLE_SPACE]; - char c2[TCL_DOUBLE_SPACE], c3[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, arcPtr->bbox[0], c0); - Tcl_PrintDouble(interp, arcPtr->bbox[1], c1); - Tcl_PrintDouble(interp, arcPtr->bbox[2], c2); - Tcl_PrintDouble(interp, arcPtr->bbox[3], c3); - Tcl_AppendResult(interp, c0, " ", c1, " ", c2, " ", c3, - (char *) NULL); - } else if (argc == 4) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], - &arcPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(arcPtr->bbox[0]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(arcPtr->bbox[1]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(arcPtr->bbox[2]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(arcPtr->bbox[3]); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if ((argc == 1)||(argc == 4)) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 4) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 4, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], + &arcPtr->bbox[0]) != TCL_OK) + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], &arcPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[2], &arcPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[3], &arcPtr->bbox[3]) != TCL_OK)) { return TCL_ERROR; } ComputeArcBbox(canvas, arcPtr); } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 4, got %d", - argc); + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 4, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; @@ -337,7 +439,7 @@ ArcCoords(interp, canvas, itemPtr, argc, argv) * * Results: * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. + * an error message is left in the interp's result. * * Side effects: * Configuration information, such as colors and stipple @@ -352,7 +454,7 @@ ConfigureArc(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Arc item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { ArcItem *arcPtr = (ArcItem *) itemPtr; @@ -361,18 +463,52 @@ ConfigureArc(interp, canvas, itemPtr, argc, argv, flags) unsigned long mask; int i; Tk_Window tkwin; + Tk_TSOffset *tsoffset; + XColor *color; + Pixmap stipple; + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) arcPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) arcPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } + state = itemPtr->state; + /* * A few of the options require additional processing, such as * style and graphics contexts. */ + if (arcPtr->outline.activeWidth > arcPtr->outline.width || + arcPtr->outline.activeDash.number != 0 || + arcPtr->outline.activeColor != NULL || + arcPtr->outline.activeStipple != None || + arcPtr->activeFillColor != NULL || + arcPtr->activeFillStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + tsoffset = &arcPtr->outline.tsoffset; + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (arcPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) ((arcPtr->bbox[0]+arcPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (arcPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (arcPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) ((arcPtr->bbox[1]+arcPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (arcPtr->bbox[2] + 0.5); + } + i = (int) (arcPtr->start/360.0); arcPtr->start -= i*360.0; if (arcPtr->start < 0) { @@ -381,60 +517,87 @@ ConfigureArc(interp, canvas, itemPtr, argc, argv, flags) i = (int) (arcPtr->extent/360.0); arcPtr->extent -= i*360.0; - if ((arcPtr->style != arcUid) && (arcPtr->style != chordUid) - && (arcPtr->style != pieSliceUid)) { - Tcl_AppendResult(interp, "bad -style option \"", - arcPtr->style, "\": must be arc, chord, or pieslice", - (char *) NULL); - arcPtr->style = pieSliceUid; - return TCL_ERROR; + mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, + &(arcPtr->outline)); + if (mask) { + gcValues.cap_style = CapButt; + mask |= GCCapStyle; + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = None; } - - if (arcPtr->width < 0) { - arcPtr->width = 1; + if (arcPtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), arcPtr->outline.gc); } - if (arcPtr->outlineColor == NULL) { - newGC = None; - } else { - gcValues.foreground = arcPtr->outlineColor->pixel; - gcValues.cap_style = CapButt; - gcValues.line_width = arcPtr->width; - mask = GCForeground|GCCapStyle|GCLineWidth; - if (arcPtr->outlineStipple != None) { - gcValues.stipple = arcPtr->outlineStipple; - gcValues.fill_style = FillStippled; - mask |= GCStipple|GCFillStyle; - } - newGC = Tk_GetGCColor(tkwin, mask, &gcValues, arcPtr->outlineColor, - NULL); + arcPtr->outline.gc = newGC; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; } - if (arcPtr->outlineGC != None) { - Tk_FreeGC(Tk_Display(tkwin), arcPtr->outlineGC); + if (state==TK_STATE_HIDDEN) { + ComputeArcBbox(canvas, arcPtr); + return TCL_OK; } - arcPtr->outlineGC = newGC; - if ((arcPtr->fillColor == NULL) || (arcPtr->style == arcUid)) { + color = arcPtr->fillColor; + stipple = arcPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->activeFillColor!=NULL) { + color = arcPtr->activeFillColor; + } + if (arcPtr->activeFillStipple!=None) { + stipple = arcPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->disabledFillColor!=NULL) { + color = arcPtr->disabledFillColor; + } + if (arcPtr->disabledFillStipple!=None) { + stipple = arcPtr->disabledFillStipple; + } + } + + if (arcPtr->style == ARC_STYLE) { + newGC = None; + } else if (color == NULL) { newGC = None; } else { - gcValues.foreground = arcPtr->fillColor->pixel; - if (arcPtr->style == chordUid) { + gcValues.foreground = color->pixel; + if (arcPtr->style == CHORD_STYLE) { gcValues.arc_mode = ArcChord; } else { gcValues.arc_mode = ArcPieSlice; } mask = GCForeground|GCArcMode; - if (arcPtr->fillStipple != None) { - gcValues.stipple = arcPtr->fillStipple; + if (stipple != None) { + gcValues.stipple = stipple; gcValues.fill_style = FillStippled; mask |= GCStipple|GCFillStyle; } - newGC = Tk_GetGCColor(tkwin, mask, &gcValues, arcPtr->fillColor, NULL); + newGC = Tk_GetGC(tkwin, mask, &gcValues); } if (arcPtr->fillGC != None) { Tk_FreeGC(Tk_Display(tkwin), arcPtr->fillGC); } arcPtr->fillGC = newGC; + tsoffset = &arcPtr->tsoffset; + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (arcPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) ((arcPtr->bbox[0]+arcPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (arcPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (arcPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) ((arcPtr->bbox[1]+arcPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (arcPtr->bbox[3] + 0.5); + } + ComputeArcBbox(canvas, arcPtr); return TCL_OK; } @@ -465,23 +628,27 @@ DeleteArc(canvas, itemPtr, display) { ArcItem *arcPtr = (ArcItem *) itemPtr; + Tk_DeleteOutline(display, &(arcPtr->outline)); if (arcPtr->numOutlinePoints != 0) { ckfree((char *) arcPtr->outlinePtr); } - if (arcPtr->outlineColor != NULL) { - Tk_FreeColor(arcPtr->outlineColor); - } if (arcPtr->fillColor != NULL) { Tk_FreeColor(arcPtr->fillColor); } + if (arcPtr->activeFillColor != NULL) { + Tk_FreeColor(arcPtr->activeFillColor); + } + if (arcPtr->disabledFillColor != NULL) { + Tk_FreeColor(arcPtr->disabledFillColor); + } if (arcPtr->fillStipple != None) { Tk_FreeBitmap(display, arcPtr->fillStipple); } - if (arcPtr->outlineStipple != None) { - Tk_FreeBitmap(display, arcPtr->outlineStipple); + if (arcPtr->activeFillStipple != None) { + Tk_FreeBitmap(display, arcPtr->activeFillStipple); } - if (arcPtr->outlineGC != None) { - Tk_FreeGC(display, arcPtr->outlineGC); + if (arcPtr->disabledFillStipple != None) { + Tk_FreeBitmap(display, arcPtr->disabledFillStipple); } if (arcPtr->fillGC != None) { Tk_FreeGC(display, arcPtr->fillGC); @@ -514,6 +681,30 @@ ComputeArcBbox(canvas, arcPtr) * recomputed. */ { double tmp, center[2], point[2]; + double width; + Tk_State state = arcPtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = arcPtr->outline.width; + if (width < 1.0) { + width = 1.0; + } + if (state==TK_STATE_HIDDEN) { + arcPtr->header.x1 = arcPtr->header.x2 = + arcPtr->header.y1 = arcPtr->header.y2 = -1; + return; + } else if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *) arcPtr) { + if (arcPtr->outline.activeWidth>width) { + width = arcPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->outline.disabledWidth>0) { + width = arcPtr->outline.disabledWidth; + } + } /* * Make sure that the first coordinates are the lowest ones. @@ -532,7 +723,7 @@ ComputeArcBbox(canvas, arcPtr) arcPtr->bbox[0] = tmp; } - ComputeArcOutline(arcPtr); + ComputeArcOutline(canvas,arcPtr); /* * To compute the bounding box, start with the the bbox formed @@ -546,7 +737,7 @@ ComputeArcBbox(canvas, arcPtr) TkIncludePoint((Tk_Item *) arcPtr, arcPtr->center2); center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2; center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2; - if (arcPtr->style == pieSliceUid) { + if (arcPtr->style == PIESLICE_STYLE) { TkIncludePoint((Tk_Item *) arcPtr, center); } @@ -592,10 +783,10 @@ ComputeArcBbox(canvas, arcPtr) * being drawn) and add one extra pixel just for safety. */ - if (arcPtr->outlineColor == NULL) { + if (arcPtr->outline.gc == None) { tmp = 1; } else { - tmp = (arcPtr->width + 1)/2 + 1; + tmp = (int) ((width + 1.0)/2.0 + 1); } arcPtr->header.x1 -= (int) tmp; arcPtr->header.y1 -= (int) tmp; @@ -633,7 +824,41 @@ DisplayArc(canvas, itemPtr, display, drawable, x, y, width, height) { ArcItem *arcPtr = (ArcItem *) itemPtr; short x1, y1, x2, y2; - int start, extent; + int start, extent, dashnumber; + double lineWidth; + Tk_State state = itemPtr->state; + Pixmap stipple; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + lineWidth = arcPtr->outline.width; + if (lineWidth < 1.0) { + lineWidth = 1.0; + } + dashnumber = arcPtr->outline.dash.number; + stipple = arcPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeWidth>lineWidth) { + lineWidth = arcPtr->outline.activeWidth; + } + if (arcPtr->outline.activeDash.number != 0) { + dashnumber = arcPtr->outline.activeDash.number; + } + if (arcPtr->activeFillStipple != None) { + stipple = arcPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->outline.disabledWidth > 0) { + lineWidth = arcPtr->outline.disabledWidth; + } + if (arcPtr->outline.disabledDash.number != 0) { + dashnumber = arcPtr->outline.disabledDash.number; + } + if (arcPtr->disabledFillStipple != None) { + stipple = arcPtr->disabledFillStipple; + } + } /* * Compute the screen coordinates of the bounding box for the item, @@ -660,65 +885,86 @@ DisplayArc(canvas, itemPtr, display, drawable, x, y, width, height) */ if ((arcPtr->fillGC != None) && (extent != 0)) { - if (arcPtr->fillStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, arcPtr->fillGC); + if (stipple != None) { + int w=0; int h=0; + Tk_TSOffset *tsoffset = &arcPtr->tsoffset; + int flags = tsoffset->flags; + if (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE)) { + Tk_SizeOfBitmap(display, stipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset->xoffset -= w; + tsoffset->yoffset -= h; + Tk_CanvasSetOffset(canvas, arcPtr->fillGC, tsoffset); + if (tsoffset) { + tsoffset->xoffset += w; + tsoffset->yoffset += h; + } } XFillArc(display, drawable, arcPtr->fillGC, x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), start, extent); - if (arcPtr->fillStipple != None) { + if (stipple != None) { XSetTSOrigin(display, arcPtr->fillGC, 0, 0); } } - if (arcPtr->outlineGC != None) { - if (arcPtr->outlineStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, arcPtr->outlineGC); - } + if (arcPtr->outline.gc != None) { + Tk_ChangeOutlineGC(canvas, itemPtr, &(arcPtr->outline)); + if (extent != 0) { - XDrawArc(display, drawable, arcPtr->outlineGC, x1, y1, + XDrawArc(display, drawable, arcPtr->outline.gc, x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), start, extent); } /* * If the outline width is very thin, don't use polygons to draw * the linear parts of the outline (this often results in nothing - * being displayed); just draw lines instead. + * being displayed); just draw lines instead. The same is done if + * the outline is dashed, because then polygons don't work. */ - if (arcPtr->width <= 2) { + if (lineWidth < 1.5 || dashnumber != 0) { Tk_CanvasDrawableCoords(canvas, arcPtr->center1[0], arcPtr->center1[1], &x1, &y1); Tk_CanvasDrawableCoords(canvas, arcPtr->center2[0], arcPtr->center2[1], &x2, &y2); - if (arcPtr->style == chordUid) { - XDrawLine(display, drawable, arcPtr->outlineGC, + if (arcPtr->style == CHORD_STYLE) { + XDrawLine(display, drawable, arcPtr->outline.gc, x1, y1, x2, y2); - } else if (arcPtr->style == pieSliceUid) { + } else if (arcPtr->style == PIESLICE_STYLE) { short cx, cy; Tk_CanvasDrawableCoords(canvas, (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0, (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0, &cx, &cy); - XDrawLine(display, drawable, arcPtr->outlineGC, + XDrawLine(display, drawable, arcPtr->outline.gc, cx, cy, x1, y1); - XDrawLine(display, drawable, arcPtr->outlineGC, + XDrawLine(display, drawable, arcPtr->outline.gc, cx, cy, x2, y2); } } else { - if (arcPtr->style == chordUid) { + if (arcPtr->style == CHORD_STYLE) { TkFillPolygon(canvas, arcPtr->outlinePtr, CHORD_OUTLINE_PTS, - display, drawable, arcPtr->outlineGC, None); - } else if (arcPtr->style == pieSliceUid) { + display, drawable, arcPtr->outline.gc, None); + } else if (arcPtr->style == PIESLICE_STYLE) { TkFillPolygon(canvas, arcPtr->outlinePtr, PIE_OUTLINE1_PTS, - display, drawable, arcPtr->outlineGC, None); + display, drawable, arcPtr->outline.gc, None); TkFillPolygon(canvas, arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, - PIE_OUTLINE2_PTS, display, drawable, arcPtr->outlineGC, + PIE_OUTLINE2_PTS, display, drawable, arcPtr->outline.gc, None); } } - if (arcPtr->outlineStipple != None) { - XSetTSOrigin(display, arcPtr->outlineGC, 0, 0); - } + + Tk_ResetOutlineGC(canvas, itemPtr, &(arcPtr->outline)); } } @@ -756,6 +1002,22 @@ ArcToPoint(canvas, itemPtr, pointPtr) double vertex[2], pointAngle, diff, dist, newDist; double poly[8], polyDist, width, t1, t2; int filled, angleInRange; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = (double) arcPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeWidth>width) { + width = (double) arcPtr->outline.activeWidth; + } + } else if (state == TK_STATE_DISABLED) { + if (arcPtr->outline.disabledWidth>0) { + width = (double) arcPtr->outline.disabledWidth; + } + } /* * See if the point is within the angular range of the arc. @@ -766,8 +1028,14 @@ ArcToPoint(canvas, itemPtr, pointPtr) vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; - t1 = (pointPtr[1] - vertex[1])/(arcPtr->bbox[3] - arcPtr->bbox[1]); - t2 = (pointPtr[0] - vertex[0])/(arcPtr->bbox[2] - arcPtr->bbox[0]); + t1 = arcPtr->bbox[3] - arcPtr->bbox[1]; + if (t1 != 0.0) { + t1 = (pointPtr[1] - vertex[1]) / t1; + } + t2 = arcPtr->bbox[2] - arcPtr->bbox[0]; + if (t2 != 0.0) { + t2 = (pointPtr[0] - vertex[0]) / t2; + } if ((t1 == 0.0) && (t2 == 0.0)) { pointAngle = 0; } else { @@ -786,9 +1054,9 @@ ArcToPoint(canvas, itemPtr, pointPtr) * we're dealing with. */ - if (arcPtr->style == arcUid) { + if (arcPtr->style == ARC_STYLE) { if (angleInRange) { - return TkOvalToPoint(arcPtr->bbox, (double) arcPtr->width, + return TkOvalToPoint(arcPtr->bbox, width, 0, pointPtr); } dist = hypot(pointPtr[0] - arcPtr->center1[0], @@ -801,18 +1069,16 @@ ArcToPoint(canvas, itemPtr, pointPtr) return dist; } - if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) { + if ((arcPtr->fillGC != None) || (arcPtr->outline.gc == None)) { filled = 1; } else { filled = 0; } - if (arcPtr->outlineGC == None) { + if (arcPtr->outline.gc == None) { width = 0.0; - } else { - width = arcPtr->width; } - if (arcPtr->style == pieSliceUid) { + if (arcPtr->style == PIESLICE_STYLE) { if (width > 1.0) { dist = TkPolygonToPoint(arcPtr->outlinePtr, PIE_OUTLINE1_PTS, pointPtr); @@ -917,16 +1183,29 @@ ArcToArea(canvas, itemPtr, rectPtr) * every test so far shows arc to be outside * of rectangle. */ int newInside; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = (double) arcPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeWidth>width) { + width = (double) arcPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->outline.disabledWidth>0) { + width = (double) arcPtr->outline.disabledWidth; + } + } - if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) { + if ((arcPtr->fillGC != None) || (arcPtr->outline.gc == None)) { filled = 1; } else { filled = 0; } - if (arcPtr->outlineGC == None) { + if (arcPtr->outline.gc == None) { width = 0.0; - } else { - width = arcPtr->width; } /* @@ -967,7 +1246,7 @@ ArcToArea(canvas, itemPtr, rectPtr) numPoints = 2; pointPtr += 4; - if ((arcPtr->style == pieSliceUid) && (arcPtr->extent < 180.0)) { + if ((arcPtr->style == PIESLICE_STYLE) && (arcPtr->extent < 180.0)) { pointPtr[0] = 0.0; pointPtr[1] = 0.0; numPoints++; @@ -1041,7 +1320,7 @@ ArcToArea(canvas, itemPtr, rectPtr) * polygon(s) forming the sides of a chord or pie-slice. */ - if (arcPtr->style == pieSliceUid) { + if (arcPtr->style == PIESLICE_STYLE) { if (width >= 1.0) { if (TkPolygonToArea(arcPtr->outlinePtr, PIE_OUTLINE1_PTS, rectPtr) != -1) { @@ -1057,7 +1336,7 @@ ArcToArea(canvas, itemPtr, rectPtr) return 0; } } - } else if (arcPtr->style == chordUid) { + } else if (arcPtr->style == CHORD_STYLE) { if (width >= 1.0) { if (TkPolygonToArea(arcPtr->outlinePtr, CHORD_OUTLINE_PTS, rectPtr) != -1) { @@ -1209,13 +1488,16 @@ TranslateArc(canvas, itemPtr, deltaX, deltaY) */ static void -ComputeArcOutline(arcPtr) +ComputeArcOutline(canvas,arcPtr) + Tk_Canvas canvas; /* Information about overall canvas. */ ArcItem *arcPtr; /* Information about arc. */ { - double sin1, cos1, sin2, cos2, angle, halfWidth; + double sin1, cos1, sin2, cos2, angle, width, halfWidth; double boxWidth, boxHeight; double vertex[2], corner1[2], corner2[2]; double *outlinePtr; + Tk_State state = arcPtr->header.state; + /* * Make sure that the outlinePtr array is large enough to hold @@ -1229,6 +1511,10 @@ ComputeArcOutline(arcPtr) } outlinePtr = arcPtr->outlinePtr; + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + /* * First compute the two points that lie at the centers of * the ends of the curved arc segment, which are marked with @@ -1285,7 +1571,18 @@ ComputeArcOutline(arcPtr) * the oval. */ - halfWidth = arcPtr->width/2.0; + width = arcPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *) arcPtr) { + if (arcPtr->outline.activeWidth>arcPtr->outline.width) { + width = arcPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->outline.disabledWidth>arcPtr->outline.width) { + width = arcPtr->outline.disabledWidth; + } + } + halfWidth = width/2.0; + if (((boxWidth*sin1) == 0.0) && ((boxHeight*cos1) == 0.0)) { angle = 0.0; } else { @@ -1308,11 +1605,11 @@ ComputeArcOutline(arcPtr) * center point. The second point is the corner point. */ - if (arcPtr->style == chordUid) { + if (arcPtr->style == CHORD_STYLE) { outlinePtr[0] = outlinePtr[12] = corner1[0]; outlinePtr[1] = outlinePtr[13] = corner1[1]; TkGetButtPoints(arcPtr->center2, arcPtr->center1, - (double) arcPtr->width, 0, outlinePtr+10, outlinePtr+2); + width, 0, outlinePtr+10, outlinePtr+2); outlinePtr[4] = arcPtr->center2[0] + outlinePtr[2] - arcPtr->center1[0]; outlinePtr[5] = arcPtr->center2[1] + outlinePtr[3] @@ -1323,7 +1620,7 @@ ComputeArcOutline(arcPtr) - arcPtr->center1[0]; outlinePtr[9] = arcPtr->center2[1] + outlinePtr[11] - arcPtr->center1[1]; - } else if (arcPtr->style == pieSliceUid) { + } else if (arcPtr->style == PIESLICE_STYLE) { /* * For pie slices, generate two polygons, one for each side * of the pie slice. The first arm has a shape like this, @@ -1339,7 +1636,7 @@ ComputeArcOutline(arcPtr) * */ - TkGetButtPoints(arcPtr->center1, vertex, (double) arcPtr->width, 0, + TkGetButtPoints(arcPtr->center1, vertex, width, 0, outlinePtr, outlinePtr+2); outlinePtr[4] = arcPtr->center1[0] + outlinePtr[2] - vertex[0]; outlinePtr[5] = arcPtr->center1[1] + outlinePtr[3] - vertex[1]; @@ -1368,7 +1665,7 @@ ComputeArcOutline(arcPtr) * first two points of the first arm, depending on extent. */ - TkGetButtPoints(arcPtr->center2, vertex, (double) arcPtr->width, 0, + TkGetButtPoints(arcPtr->center2, vertex, width, 0, outlinePtr+12, outlinePtr+16); if ((arcPtr->extent > 180) || ((arcPtr->extent < 0) && (arcPtr->extent > -180))) { @@ -1575,7 +1872,7 @@ AngleInRange(x, y, start, extent) * Results: * The return value is a standard Tcl result. If an error * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used + * left in the interp's result, replacing whatever used * to be there. If no error occurs, then Postscript for the * item is appended to the result. * @@ -1599,6 +1896,11 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) ArcItem *arcPtr = (ArcItem *) itemPtr; char buffer[400]; double y1, y2, ang1, ang2; + XColor *color; + Pixmap stipple; + XColor *fillColor; + Pixmap fillStipple; + Tk_State state = itemPtr->state; y1 = Tk_CanvasPsY(canvas, arcPtr->bbox[1]); y2 = Tk_CanvasPsY(canvas, arcPtr->bbox[3]); @@ -1609,6 +1911,41 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) ang2 = arcPtr->start; } + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + color = arcPtr->outline.color; + stipple = arcPtr->outline.stipple; + fillColor = arcPtr->fillColor; + fillStipple = arcPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeColor!=NULL) { + color = arcPtr->outline.activeColor; + } + if (arcPtr->outline.activeStipple!=None) { + stipple = arcPtr->outline.activeStipple; + } + if (arcPtr->activeFillColor!=NULL) { + fillColor = arcPtr->activeFillColor; + } + if (arcPtr->activeFillStipple!=None) { + fillStipple = arcPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (arcPtr->outline.disabledColor!=NULL) { + color = arcPtr->outline.disabledColor; + } + if (arcPtr->outline.disabledStipple!=None) { + stipple = arcPtr->outline.disabledStipple; + } + if (arcPtr->disabledFillColor!=NULL) { + fillColor = arcPtr->disabledFillColor; + } + if (arcPtr->disabledFillStipple!=None) { + fillStipple = arcPtr->disabledFillStipple; + } + } + /* * If the arc is filled, output Postscript for the interior region * of the arc. @@ -1619,7 +1956,7 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2, (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2); Tcl_AppendResult(interp, buffer, (char *) NULL); - if (arcPtr->style == chordUid) { + if (arcPtr->style == CHORD_STYLE) { sprintf(buffer, "0 0 1 %.15g %.15g arc closepath\nsetmatrix\n", ang1, ang2); } else { @@ -1628,16 +1965,16 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) ang1, ang2); } Tcl_AppendResult(interp, buffer, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, arcPtr->fillColor) != TCL_OK) { + if (Tk_CanvasPsColor(interp, canvas, fillColor) != TCL_OK) { return TCL_ERROR; }; - if (arcPtr->fillStipple != None) { + if (fillStipple != None) { Tcl_AppendResult(interp, "clip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, arcPtr->fillStipple) + if (Tk_CanvasPsStipple(interp, canvas, fillStipple) != TCL_OK) { return TCL_ERROR; } - if (arcPtr->outlineGC != None) { + if (arcPtr->outline.gc != None) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } } else { @@ -1649,44 +1986,34 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) * If there's an outline for the arc, draw it. */ - if (arcPtr->outlineGC != None) { + if (arcPtr->outline.gc != None) { sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n", (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2, (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2); Tcl_AppendResult(interp, buffer, (char *) NULL); - sprintf(buffer, "0 0 1 %.15g %.15g arc\nsetmatrix\n", ang1, ang2); - Tcl_AppendResult(interp, buffer, (char *) NULL); - sprintf(buffer, "%d setlinewidth\n0 setlinecap\n", arcPtr->width); - Tcl_AppendResult(interp, buffer, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor) - != TCL_OK) { + sprintf(buffer, "0 0 1 %.15g %.15g", ang1, ang2); + Tcl_AppendResult(interp, buffer, + " arc\nsetmatrix\n0 setlinecap\n", (char *) NULL); + if (Tk_CanvasPsOutline(canvas, itemPtr, + &(arcPtr->outline)) != TCL_OK) { return TCL_ERROR; } - if (arcPtr->outlineStipple != None) { - Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, - arcPtr->outlineStipple) != TCL_OK) { - return TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); - } - if (arcPtr->style != arcUid) { + if (arcPtr->style != ARC_STYLE) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); - if (arcPtr->style == chordUid) { + if (arcPtr->style == CHORD_STYLE) { Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr, CHORD_OUTLINE_PTS); } else { Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr, PIE_OUTLINE1_PTS); - if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor) + if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) { return TCL_ERROR; } - if (arcPtr->outlineStipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "clip ", (char *) NULL); if (Tk_CanvasPsStipple(interp, canvas, - arcPtr->outlineStipple) != TCL_OK) { + stipple) != TCL_OK) { return TCL_ERROR; } } else { @@ -1697,14 +2024,14 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, PIE_OUTLINE2_PTS); } - if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor) + if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) { return TCL_ERROR; } - if (arcPtr->outlineStipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "clip ", (char *) NULL); if (Tk_CanvasPsStipple(interp, canvas, - arcPtr->outlineStipple) != TCL_OK) { + stipple) != TCL_OK) { return TCL_ERROR; } } else { @@ -1715,3 +2042,107 @@ ArcToPostscript(interp, canvas, itemPtr, prepass) return TCL_OK; } + +/* + *-------------------------------------------------------------- + * + * StyleParseProc -- + * + * This procedure is invoked during option processing to handle + * the "-style" option. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The state for a given item gets replaced by the state + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +static int +StyleParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + int c; + size_t length; + + register Style *stylePtr = (Style *) (widgRec + offset); + + if(value == NULL || *value == 0) { + *stylePtr = PIESLICE_STYLE; + return TCL_OK; + } + + c = value[0]; + length = strlen(value); + + if ((c == 'a') && (strncmp(value, "arc", length) == 0)) { + *stylePtr = ARC_STYLE; + return TCL_OK; + } + if ((c == 'c') && (strncmp(value, "chord", length) == 0)) { + *stylePtr = CHORD_STYLE; + return TCL_OK; + } + if ((c == 'p') && (strncmp(value, "pieslice", length) == 0)) { + *stylePtr = PIESLICE_STYLE; + return TCL_OK; + } + + Tcl_AppendResult(interp, "bad -style option \"", + value, "\": must be arc, chord, or pieslice", + (char *) NULL); + *stylePtr = PIESLICE_STYLE; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * StylePrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-style" + * configuration option. + * + * Results: + * The return value is a string describing the state for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static char * +StylePrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Ignored. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register Style *stylePtr = (Style *) (widgRec + offset); + + if (*stylePtr==ARC_STYLE) { + return "arc"; + } else if (*stylePtr==CHORD_STYLE) { + return "chord"; + } else { + return "pieslice"; + } +} + diff --git a/tk/generic/tkCanvBmap.c b/tk/generic/tkCanvBmap.c index 74087e2db57..dc35890505d 100644 --- a/tk/generic/tkCanvBmap.c +++ b/tk/generic/tkCanvBmap.c @@ -4,7 +4,7 @@ * This file implements bitmap items for canvas widgets. * * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -29,8 +29,14 @@ typedef struct BitmapItem { Tk_Anchor anchor; /* Where to anchor bitmap relative to * (x,y). */ Pixmap bitmap; /* Bitmap to display in window. */ + Pixmap activeBitmap; /* Bitmap to display in window. */ + Pixmap disabledBitmap; /* Bitmap to display in window. */ XColor *fgColor; /* Foreground color to use for bitmap. */ + XColor *activeFgColor; /* Foreground color to use for bitmap. */ + XColor *disabledFgColor; /* Foreground color to use for bitmap. */ XColor *bgColor; /* Background color to use for bitmap. */ + XColor *activeBgColor; /* Background color to use for bitmap. */ + XColor *disabledBgColor; /* Background color to use for bitmap. */ GC gc; /* Graphics context to use for drawing * bitmap on screen. */ } BitmapItem; @@ -39,19 +45,42 @@ typedef struct BitmapItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_COLOR, "-activebackground", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, activeBgColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activebitmap", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, activeBitmap), TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-activeforeground", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, activeFgColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, "center", Tk_Offset(BitmapItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_COLOR, "-background", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(BitmapItem, bgColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_BITMAP, "-bitmap", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(BitmapItem, bitmap), TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-disabledbackground", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, disabledBgColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledbitmap", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, disabledBitmap), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-disabledforeground", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(BitmapItem, disabledFgColor), + TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-foreground", (char *) NULL, (char *) NULL, "black", Tk_Offset(BitmapItem, fgColor), 0}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, @@ -64,7 +93,7 @@ static Tk_ConfigSpec configSpecs[] = { static int BitmapCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); + Tcl_Obj *CONST argv[])); static int BitmapToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); static double BitmapToPoint _ANSI_ARGS_((Tk_Canvas canvas, @@ -75,10 +104,10 @@ static void ComputeBitmapBbox _ANSI_ARGS_((Tk_Canvas canvas, BitmapItem *bmapPtr)); static int ConfigureBitmap _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); -static int tkCreateBitmap _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *CONST argv[], int flags)); +static int CreateBitmap _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteBitmap _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayBitmap _ANSI_ARGS_((Tk_Canvas canvas, @@ -98,13 +127,13 @@ static void TranslateBitmap _ANSI_ARGS_((Tk_Canvas canvas, Tk_ItemType tkBitmapType = { "bitmap", /* name */ sizeof(BitmapItem), /* itemSize */ - tkCreateBitmap, /* createProc */ + CreateBitmap, /* createProc */ configSpecs, /* configSpecs */ ConfigureBitmap, /* configureProc */ BitmapCoords, /* coordProc */ DeleteBitmap, /* deleteProc */ DisplayBitmap, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ BitmapToPoint, /* pointProc */ BitmapToArea, /* areaProc */ BitmapToPostscript, /* postscriptProc */ @@ -115,13 +144,13 @@ Tk_ItemType tkBitmapType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* *-------------------------------------------------------------- * - * tkCreateBitmap -- + * CreateBitmap -- * * This procedure is invoked to create a new bitmap * item in a canvas. @@ -129,7 +158,7 @@ Tk_ItemType tkBitmapType = { * Results: * A standard Tcl return value. If an error occurred in * creating the item, then an error message is left in - * interp->result; in this case itemPtr is left uninitialized, + * the interp's result; in this case itemPtr is left uninitialized, * so it can be safely freed by the caller. * * Side effects: @@ -139,17 +168,30 @@ Tk_ItemType tkBitmapType = { */ static int -tkCreateBitmap(interp, canvas, itemPtr, argc, argv) +CreateBitmap(interp, canvas, itemPtr, argc, argv) Tcl_Interp *interp; /* Interpreter for error reporting. */ Tk_Canvas canvas; /* Canvas to hold new item. */ Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ + Tcl_Obj *CONST argv[]; /* Arguments describing rectangle. */ { BitmapItem *bmapPtr = (BitmapItem *) itemPtr; + int i; + + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj(argv[1], NULL); + if (((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z'))) { + i = 1; + } else { + i = 2; + } + } - if (argc < 2) { + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x y ?options?\"", @@ -163,25 +205,30 @@ tkCreateBitmap(interp, canvas, itemPtr, argc, argv) bmapPtr->anchor = TK_ANCHOR_CENTER; bmapPtr->bitmap = None; + bmapPtr->activeBitmap = None; + bmapPtr->disabledBitmap = None; bmapPtr->fgColor = NULL; + bmapPtr->activeFgColor = NULL; + bmapPtr->disabledFgColor = NULL; bmapPtr->bgColor = NULL; + bmapPtr->activeBgColor = NULL; + bmapPtr->disabledBgColor = NULL; bmapPtr->gc = None; /* * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &bmapPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &bmapPtr->y) - != TCL_OK)) { - return TCL_ERROR; + if ((BitmapCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureBitmap(interp, canvas, itemPtr, argc-2, argv+2, 0) != TCL_OK) { - DeleteBitmap(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureBitmap(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { + return TCL_OK; } - return TCL_OK; + + error: + DeleteBitmap(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -194,7 +241,7 @@ tkCreateBitmap(interp, canvas, itemPtr, argc, argv) * details on what it does. * * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. * * Side effects: * The coordinates for the given item may be changed. @@ -210,26 +257,42 @@ BitmapCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { BitmapItem *bmapPtr = (BitmapItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, bmapPtr->x, x); - Tcl_PrintDouble(interp, bmapPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &bmapPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &bmapPtr->y) - != TCL_OK)) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(bmapPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(bmapPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (argc <3) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 2) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], &bmapPtr->x) != TCL_OK) + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], &bmapPtr->y) + != TCL_OK)) { return TCL_ERROR; } ComputeBitmapBbox(canvas, bmapPtr); } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 2, got %d", argc); + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; @@ -245,7 +308,7 @@ BitmapCoords(interp, canvas, itemPtr, argc, argv) * * Results: * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. + * an error message is left in the interp's result. * * Side effects: * Configuration information may be set for itemPtr. @@ -259,7 +322,7 @@ ConfigureBitmap(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Bitmap item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { BitmapItem *bmapPtr = (BitmapItem *) itemPtr; @@ -267,10 +330,14 @@ ConfigureBitmap(interp, canvas, itemPtr, argc, argv, flags) GC newGC; Tk_Window tkwin; unsigned long mask; + XColor *fgColor; + XColor *bgColor; + Pixmap bitmap; + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) bmapPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) bmapPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -279,17 +346,67 @@ ConfigureBitmap(interp, canvas, itemPtr, argc, argv, flags) * that determine the graphics context. */ - gcValues.foreground = bmapPtr->fgColor->pixel; + state = itemPtr->state; + + if (bmapPtr->activeFgColor!=NULL || + bmapPtr->activeBgColor!=NULL || + bmapPtr->activeBitmap!=None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (state==TK_STATE_HIDDEN) { + ComputeBitmapBbox(canvas, bmapPtr); + return TCL_OK; + } + fgColor = bmapPtr->fgColor; + bgColor = bmapPtr->bgColor; + bitmap = bmapPtr->bitmap; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (bmapPtr->activeFgColor!=NULL) { + fgColor = bmapPtr->activeFgColor; + } + if (bmapPtr->activeBgColor!=NULL) { + bgColor = bmapPtr->activeBgColor; + } + if (bmapPtr->activeBitmap!=None) { + bitmap = bmapPtr->activeBitmap; + } + } else if (state==TK_STATE_DISABLED) { + if (bmapPtr->disabledFgColor!=NULL) { + fgColor = bmapPtr->disabledFgColor; + } + if (bmapPtr->disabledBgColor!=NULL) { + bgColor = bmapPtr->disabledBgColor; + } + if (bmapPtr->disabledBitmap!=None) { + bitmap = bmapPtr->disabledBitmap; + } + } + + if (state==TK_STATE_DISABLED || bitmap == None) { + ComputeBitmapBbox(canvas, bmapPtr); + return TCL_OK; + } + + gcValues.foreground = fgColor->pixel; mask = GCForeground; - if (bmapPtr->bgColor != NULL) { - gcValues.background = bmapPtr->bgColor->pixel; + if (bgColor != NULL) { + gcValues.background = bgColor->pixel; mask |= GCBackground; } else { - gcValues.clip_mask = bmapPtr->bitmap; + gcValues.clip_mask = bitmap; mask |= GCClipMask; } - newGC = Tk_GetGCColor(tkwin, mask, &gcValues, bmapPtr->fgColor, - bmapPtr->bgColor); + if (bitmap == None) { + newGC = None; + } else { + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } if (bmapPtr->gc != None) { Tk_FreeGC(Tk_Display(tkwin), bmapPtr->gc); } @@ -329,12 +446,30 @@ DeleteBitmap(canvas, itemPtr, display) if (bmapPtr->bitmap != None) { Tk_FreeBitmap(display, bmapPtr->bitmap); } + if (bmapPtr->activeBitmap != None) { + Tk_FreeBitmap(display, bmapPtr->activeBitmap); + } + if (bmapPtr->disabledBitmap != None) { + Tk_FreeBitmap(display, bmapPtr->disabledBitmap); + } if (bmapPtr->fgColor != NULL) { Tk_FreeColor(bmapPtr->fgColor); } + if (bmapPtr->activeFgColor != NULL) { + Tk_FreeColor(bmapPtr->activeFgColor); + } + if (bmapPtr->disabledFgColor != NULL) { + Tk_FreeColor(bmapPtr->disabledFgColor); + } if (bmapPtr->bgColor != NULL) { Tk_FreeColor(bmapPtr->bgColor); } + if (bmapPtr->activeBgColor != NULL) { + Tk_FreeColor(bmapPtr->activeBgColor); + } + if (bmapPtr->disabledBgColor != NULL) { + Tk_FreeColor(bmapPtr->disabledBgColor); + } if (bmapPtr->gc != NULL) { Tk_FreeGC(display, bmapPtr->gc); } @@ -369,11 +504,27 @@ ComputeBitmapBbox(canvas, bmapPtr) { int width, height; int x, y; + Pixmap bitmap; + Tk_State state = bmapPtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + bitmap = bmapPtr->bitmap; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)bmapPtr) { + if (bmapPtr->activeBitmap!=None) { + bitmap = bmapPtr->activeBitmap; + } + } else if (state==TK_STATE_DISABLED) { + if (bmapPtr->disabledBitmap!=None) { + bitmap = bmapPtr->disabledBitmap; + } + } x = (int) (bmapPtr->x + ((bmapPtr->x >= 0) ? 0.5 : - 0.5)); y = (int) (bmapPtr->y + ((bmapPtr->y >= 0) ? 0.5 : - 0.5)); - if (bmapPtr->bitmap == None) { + if (state==TK_STATE_HIDDEN || bitmap == None) { bmapPtr->header.x1 = bmapPtr->header.x2 = x; bmapPtr->header.y1 = bmapPtr->header.y2 = y; return; @@ -459,6 +610,10 @@ DisplayBitmap(canvas, itemPtr, display, drawable, x, y, width, height) BitmapItem *bmapPtr = (BitmapItem *) itemPtr; int bmapX, bmapY, bmapWidth, bmapHeight; short drawableX, drawableY; + XColor *fgColor; + XColor *bgColor; + Pixmap bitmap; + Tk_State state = itemPtr->state; /* * If the area being displayed doesn't cover the whole bitmap, @@ -466,7 +621,35 @@ DisplayBitmap(canvas, itemPtr, display, drawable, x, y, width, height) * redisplay. */ - if (bmapPtr->bitmap != None) { + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + fgColor = bmapPtr->fgColor; + bgColor = bmapPtr->bgColor; + bitmap = bmapPtr->bitmap; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (bmapPtr->activeFgColor!=NULL) { + fgColor = bmapPtr->activeFgColor; + } + if (bmapPtr->activeBgColor!=NULL) { + bgColor = bmapPtr->activeBgColor; + } + if (bmapPtr->activeBitmap!=None) { + bitmap = bmapPtr->activeBitmap; + } + } else if (state==TK_STATE_DISABLED) { + if (bmapPtr->disabledFgColor!=NULL) { + fgColor = bmapPtr->disabledFgColor; + } + if (bmapPtr->disabledBgColor!=NULL) { + bgColor = bmapPtr->disabledBgColor; + } + if (bmapPtr->disabledBitmap!=None) { + bitmap = bmapPtr->disabledBitmap; + } + } + + if (bitmap != None) { if (x > bmapPtr->header.x1) { bmapX = x - bmapPtr->header.x1; bmapWidth = bmapPtr->header.x2 - x; @@ -502,9 +685,10 @@ DisplayBitmap(canvas, itemPtr, display, drawable, x, y, width, height) XSetClipOrigin(display, bmapPtr->gc, drawableX - bmapX, drawableY - bmapY); - XCopyPlane(display, bmapPtr->bitmap, drawable, + XCopyPlane(display, bitmap, drawable, bmapPtr->gc, bmapX, bmapY, (unsigned int) bmapWidth, (unsigned int) bmapHeight, drawableX, drawableY, 1); + XSetClipOrigin(display, bmapPtr->gc, 0, 0); } } @@ -691,7 +875,7 @@ TranslateBitmap(canvas, itemPtr, deltaX, deltaY) * Results: * The return value is a standard Tcl result. If an error * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used to be there. + * left in the interp's result, replacing whatever used to be there. * If no error occurs, then Postscript for the item is appended * to the result. * @@ -716,7 +900,7 @@ BitmapToPostscript(interp, canvas, itemPtr, prepass) double x, y; int width, height, rowsAtOnce, rowsThisTime; int curRow; - char buffer[200]; + char buffer[100 + TCL_DOUBLE_SPACE * 2 + TCL_INTEGER_SPACE * 4]; if (bmapPtr->bitmap == None) { return TCL_OK; @@ -750,7 +934,7 @@ BitmapToPostscript(interp, canvas, itemPtr, prepass) if (bmapPtr->bgColor != NULL) { sprintf(buffer, "%.15g %.15g moveto %d 0 rlineto 0 %d rlineto %d %s\n", - x, y, width, height, -width,"0 rlineto closepath"); + x, y, width, height, -width, "0 rlineto closepath"); Tcl_AppendResult(interp, buffer, (char *) NULL); if (Tk_CanvasPsColor(interp, canvas, bmapPtr->bgColor) != TCL_OK) { return TCL_ERROR; diff --git a/tk/generic/tkCanvImg.c b/tk/generic/tkCanvImg.c index eb3df385c6b..ebfed526748 100644 --- a/tk/generic/tkCanvImg.c +++ b/tk/generic/tkCanvImg.c @@ -4,7 +4,7 @@ * This file implements image items for canvas widgets. * * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -31,23 +31,45 @@ typedef struct ImageItem { * (x,y). */ char *imageString; /* String describing -image option (malloc-ed). * NULL means no image right now. */ + char *activeImageString; /* String describing -activeimage option. + * NULL means no image right now. */ + char *disabledImageString; /* String describing -disabledimage option. + * NULL means no image right now. */ Tk_Image image; /* Image to display in window, or NULL if * no image at present. */ + Tk_Image activeImage; /* Image to display in window, or NULL if + * no image at present. */ + Tk_Image disabledImage; /* Image to display in window, or NULL if + * no image at present. */ } ImageItem; /* * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_STRING, "-activeimage", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ImageItem, activeImageString), + TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, "center", Tk_Offset(ImageItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_STRING, "-disabledimage", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(ImageItem, disabledImageString), + TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ImageItem, imageString), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, @@ -63,19 +85,21 @@ static void ImageChangedProc _ANSI_ARGS_((ClientData clientData, int imgHeight)); static int ImageCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); + Tcl_Obj *CONST argv[])); static int ImageToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); static double ImageToPoint _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *coordPtr)); +static int ImageToPostscript _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); static void ComputeImageBbox _ANSI_ARGS_((Tk_Canvas canvas, ImageItem *imgPtr)); static int ConfigureImage _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateImage _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteImage _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayImage _ANSI_ARGS_((Tk_Canvas canvas, @@ -101,10 +125,10 @@ Tk_ItemType tkImageType = { ImageCoords, /* coordProc */ DeleteImage, /* deleteProc */ DisplayImage, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ ImageToPoint, /* pointProc */ ImageToArea, /* areaProc */ - (Tk_ItemPostscriptProc *) NULL, /* postscriptProc */ + ImageToPostscript, /* postscriptProc */ ScaleImage, /* scaleProc */ TranslateImage, /* translateProc */ (Tk_ItemIndexProc *) NULL, /* indexProc */ @@ -112,7 +136,7 @@ Tk_ItemType tkImageType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* @@ -126,7 +150,7 @@ Tk_ItemType tkImageType = { * Results: * A standard Tcl return value. If an error occurred in * creating the item, then an error message is left in - * interp->result; in this case itemPtr is left uninitialized, + * the interp's result; in this case itemPtr is left uninitialized, * so it can be safely freed by the caller. * * Side effects: @@ -142,11 +166,24 @@ CreateImage(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ + Tcl_Obj *CONST argv[]; /* Arguments describing rectangle. */ { ImageItem *imgPtr = (ImageItem *) itemPtr; + int i; - if (argc < 2) { + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj((Tcl_Obj *) argv[1], NULL); + if (((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z'))) { + i = 1; + } else { + i = 2; + } + } + + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x y ?options?\"", @@ -161,23 +198,26 @@ CreateImage(interp, canvas, itemPtr, argc, argv) imgPtr->canvas = canvas; imgPtr->anchor = TK_ANCHOR_CENTER; imgPtr->imageString = NULL; + imgPtr->activeImageString = NULL; + imgPtr->disabledImageString = NULL; imgPtr->image = NULL; + imgPtr->activeImage = NULL; + imgPtr->disabledImage = NULL; /* * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &imgPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &imgPtr->y) - != TCL_OK)) { - return TCL_ERROR; + if ((ImageCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureImage(interp, canvas, itemPtr, argc-2, argv+2, 0) != TCL_OK) { - DeleteImage(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureImage(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { + return TCL_OK; } - return TCL_OK; + + error: + DeleteImage(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -190,7 +230,7 @@ CreateImage(interp, canvas, itemPtr, argc, argv) * details on what it does. * * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. * * Side effects: * The coordinates for the given item may be changed. @@ -206,26 +246,42 @@ ImageCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { ImageItem *imgPtr = (ImageItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, imgPtr->x, x); - Tcl_PrintDouble(interp, imgPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &imgPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &imgPtr->y) != TCL_OK)) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(imgPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(imgPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (argc < 3) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 2) { + char buf[64]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], &imgPtr->x) != TCL_OK) + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], + &imgPtr->y) != TCL_OK)) { return TCL_ERROR; } ComputeImageBbox(canvas, imgPtr); } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 2, got %d", argc); + char buf[64]; + + sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; @@ -241,7 +297,7 @@ ImageCoords(interp, canvas, itemPtr, argc, argv) * * Results: * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. + * an error message is left in the interp's result. * * Side effects: * Configuration information may be set for itemPtr. @@ -255,7 +311,7 @@ ConfigureImage(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Image item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { ImageItem *imgPtr = (ImageItem *) itemPtr; @@ -263,8 +319,8 @@ ConfigureImage(interp, canvas, itemPtr, argc, argv, flags) Tk_Image image; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, - argv, (char *) imgPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) imgPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -275,6 +331,11 @@ ConfigureImage(interp, canvas, itemPtr, argc, argv, flags) * if it hasn't changed. */ + if (imgPtr->activeImageString != NULL) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } if (imgPtr->imageString != NULL) { image = Tk_GetImage(interp, tkwin, imgPtr->imageString, ImageChangedProc, (ClientData) imgPtr); @@ -288,6 +349,32 @@ ConfigureImage(interp, canvas, itemPtr, argc, argv, flags) Tk_FreeImage(imgPtr->image); } imgPtr->image = image; + if (imgPtr->activeImageString != NULL) { + image = Tk_GetImage(interp, tkwin, imgPtr->activeImageString, + ImageChangedProc, (ClientData) imgPtr); + if (image == NULL) { + return TCL_ERROR; + } + } else { + image = NULL; + } + if (imgPtr->activeImage != NULL) { + Tk_FreeImage(imgPtr->activeImage); + } + imgPtr->activeImage = image; + if (imgPtr->disabledImageString != NULL) { + image = Tk_GetImage(interp, tkwin, imgPtr->disabledImageString, + ImageChangedProc, (ClientData) imgPtr); + if (image == NULL) { + return TCL_ERROR; + } + } else { + image = NULL; + } + if (imgPtr->disabledImage != NULL) { + Tk_FreeImage(imgPtr->disabledImage); + } + imgPtr->disabledImage = image; ComputeImageBbox(canvas, imgPtr); return TCL_OK; } @@ -321,9 +408,21 @@ DeleteImage(canvas, itemPtr, display) if (imgPtr->imageString != NULL) { ckfree(imgPtr->imageString); } + if (imgPtr->activeImageString != NULL) { + ckfree(imgPtr->activeImageString); + } + if (imgPtr->disabledImageString != NULL) { + ckfree(imgPtr->disabledImageString); + } if (imgPtr->image != NULL) { Tk_FreeImage(imgPtr->image); } + if (imgPtr->activeImage != NULL) { + Tk_FreeImage(imgPtr->activeImage); + } + if (imgPtr->disabledImage != NULL) { + Tk_FreeImage(imgPtr->disabledImage); + } } /* @@ -355,11 +454,27 @@ ComputeImageBbox(canvas, imgPtr) { int width, height; int x, y; + Tk_Image image; + Tk_State state = imgPtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + image = imgPtr->image; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)imgPtr) { + if (imgPtr->activeImage != NULL) { + image = imgPtr->activeImage; + } + } else if (state == TK_STATE_DISABLED) { + if (imgPtr->disabledImage != NULL) { + image = imgPtr->disabledImage; + } + } x = (int) (imgPtr->x + ((imgPtr->x >= 0) ? 0.5 : - 0.5)); y = (int) (imgPtr->y + ((imgPtr->y >= 0) ? 0.5 : - 0.5)); - if (imgPtr->image == None) { + if ((state == TK_STATE_HIDDEN) || (image == None)) { imgPtr->header.x1 = imgPtr->header.x2 = x; imgPtr->header.y1 = imgPtr->header.y2 = y; return; @@ -369,7 +484,7 @@ ComputeImageBbox(canvas, imgPtr) * Compute location and size of image, using anchor information. */ - Tk_SizeOfImage(imgPtr->image, &width, &height); + Tk_SizeOfImage(image, &width, &height); switch (imgPtr->anchor) { case TK_ANCHOR_N: x -= width/2; @@ -443,8 +558,25 @@ DisplayImage(canvas, itemPtr, display, drawable, x, y, width, height) { ImageItem *imgPtr = (ImageItem *) itemPtr; short drawableX, drawableY; + Tk_Image image; + Tk_State state = itemPtr->state; - if (imgPtr->image == NULL) { + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + image = imgPtr->image; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (imgPtr->activeImage != NULL) { + image = imgPtr->activeImage; + } + } else if (state == TK_STATE_DISABLED) { + if (imgPtr->disabledImage != NULL) { + image = imgPtr->disabledImage; + } + } + + if (image == NULL) { return; } @@ -454,7 +586,7 @@ DisplayImage(canvas, itemPtr, display, drawable, x, y, width, height) Tk_CanvasDrawableCoords(canvas, (double) x, (double) y, &drawableX, &drawableY); - Tk_RedrawImage(imgPtr->image, x - imgPtr->header.x1, y - imgPtr->header.y1, + Tk_RedrawImage(image, x - imgPtr->header.x1, y - imgPtr->header.y1, width, height, drawable, drawableX, drawableY); } @@ -563,6 +695,96 @@ ImageToArea(canvas, itemPtr, rectPtr) /* *-------------------------------------------------------------- * + * ImageToPostscript -- + * + * This procedure is called to generate Postscript for + * image items. + * + * Results: + * The return value is a standard Tcl result. If an error + * occurs in generating Postscript then an error message is + * left in interp->result, replacing whatever used to be there. + * If no error occurs, then Postscript for the item is appended + * to the result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +ImageToPostscript(interp, canvas, itemPtr, prepass) + Tcl_Interp *interp; /* Leave Postscript or error message + * here. */ + Tk_Canvas canvas; /* Information about overall canvas. */ + Tk_Item *itemPtr; /* Item for which Postscript is + * wanted. */ + int prepass; /* 1 means this is a prepass to + * collect font information; 0 means + * final Postscript is being created.*/ +{ + ImageItem *imgPtr = (ImageItem *)itemPtr; + Tk_Window canvasWin = Tk_CanvasTkwin(canvas); + + char buffer[256]; + double x, y; + int width, height; + Tk_Image image; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + image = imgPtr->image; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (imgPtr->activeImage != NULL) { + image = imgPtr->activeImage; + } + } else if (state == TK_STATE_DISABLED) { + if (imgPtr->disabledImage != NULL) { + image = imgPtr->disabledImage; + } + } + Tk_SizeOfImage(image, &width, &height); + + /* + * Compute the coordinates of the lower-left corner of the image, + * taking into account the anchor position for the image. + */ + + x = imgPtr->x; + y = Tk_CanvasPsY(canvas, imgPtr->y); + + switch (imgPtr->anchor) { + case TK_ANCHOR_NW: y -= height; break; + case TK_ANCHOR_N: x -= width/2.0; y -= height; break; + case TK_ANCHOR_NE: x -= width; y -= height; break; + case TK_ANCHOR_E: x -= width; y -= height/2.0; break; + case TK_ANCHOR_SE: x -= width; break; + case TK_ANCHOR_S: x -= width/2.0; break; + case TK_ANCHOR_SW: break; + case TK_ANCHOR_W: y -= height/2.0; break; + case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break; + } + + if (image == NULL) { + return TCL_OK; + } + + if (!prepass) { + sprintf(buffer, "%.15g %.15g", x, y); + Tcl_AppendResult(interp, buffer, " translate\n", (char *) NULL); + } + + return Tk_PostscriptImage(image, interp, canvasWin, + ((TkCanvas *) canvas)->psInfo, 0, 0, width, height, prepass); +} + +/* + *-------------------------------------------------------------- + * * ScaleImage -- * * This procedure is invoked to rescale an item. @@ -675,3 +897,4 @@ ImageChangedProc(clientData, x, y, width, height, imgWidth, imgHeight) imgPtr->header.y1 + y, (int) (imgPtr->header.x1 + x + width), (int) (imgPtr->header.y1 + y + height)); } + diff --git a/tk/generic/tkCanvLine.c b/tk/generic/tkCanvLine.c index 2125446742d..fc2174b710b 100644 --- a/tk/generic/tkCanvLine.c +++ b/tk/generic/tkCanvLine.c @@ -4,7 +4,8 @@ * This file implements line items for canvas widgets. * * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -15,17 +16,23 @@ #include <stdio.h> #include "tkInt.h" #include "tkPort.h" +#include "tkCanvas.h" /* * The structure below defines the record for each line item. */ +typedef enum { + ARROWS_NONE, ARROWS_FIRST, ARROWS_LAST, ARROWS_BOTH +} Arrows; + typedef struct LineItem { Tk_Item header; /* Generic stuff that's the same for all * types. MUST BE FIRST IN STRUCTURE. */ + Tk_Outline outline; /* Outline structure */ Tk_Canvas canvas; /* Canvas containing item. Needed for * parsing arrow shapes. */ - int numPoints; /* Number of points in line (always >= 2). */ + int numPoints; /* Number of points in line (always >= 0). */ double *coordPtr; /* Pointer to malloc-ed array containing * x- and y-coords of all points in line. * X-coords are even-valued indices, y-coords @@ -36,14 +43,10 @@ typedef struct LineItem { * their tips. The actual endpoints are * stored in the *firstArrowPtr and * *lastArrowPtr, if they exist. */ - int width; /* Width of line. */ - XColor *fg; /* Foreground color for line. */ - Pixmap fillStipple; /* Stipple bitmap for filling line. */ int capStyle; /* Cap style for line. */ int joinStyle; /* Join style for line. */ - GC gc; /* Graphics context for filling line. */ GC arrowGC; /* Graphics context for drawing arrowheads. */ - Tk_Uid arrow; /* Indicates whether or not to draw arrowheads: + Arrows arrow; /* Indicates whether or not to draw arrowheads: * "none", "first", "last", or "both". */ float arrowShapeA; /* Distance from tip of arrowhead to center. */ float arrowShapeB; /* Distance from tip of arrowhead to trailing @@ -59,7 +62,7 @@ typedef struct LineItem { * point in line (PTS_IN_ARROW points, first * of which is tip). Malloc'ed. NULL means * no arrowhead at last point. */ - int smooth; /* Non-zero means draw line smoothed (i.e. + Tk_SmoothMethod *smooth; /* Non-zero means draw line smoothed (i.e. * with Bezier splines). */ int splineSteps; /* Number of steps in each spline segment. */ } LineItem; @@ -81,29 +84,42 @@ static void ComputeLineBbox _ANSI_ARGS_((Tk_Canvas canvas, LineItem *linePtr)); static int ConfigureLine _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int ConfigureArrows _ANSI_ARGS_((Tk_Canvas canvas, LineItem *linePtr)); static int CreateLine _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteLine _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayLine _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, Drawable dst, int x, int y, int width, int height)); +static int GetLineIndex _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, + Tcl_Obj *obj, int *indexPtr)); static int LineCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); +static void LineDeleteCoords _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, int first, int last)); +static void LineInsert _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, int beforeThis, Tcl_Obj *obj)); static int LineToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); static double LineToPoint _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *coordPtr)); static int LineToPostscript _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); +static int ArrowParseProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, + CONST char *value, char *recordPtr, int offset)); +static char * ArrowPrintProc _ANSI_ARGS_((ClientData clientData, + Tk_Window tkwin, char *recordPtr, int offset, + Tcl_FreeProc **freeProcPtr)); static int ParseArrowShape _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, Tk_Window tkwin, char *value, - char *recordPtr, int offset)); + Tcl_Interp *interp, Tk_Window tkwin, + CONST char *value, char *recordPtr, int offset)); static char * PrintArrowShape _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *recordPtr, int offset, Tcl_FreeProc **freeProcPtr)); @@ -119,34 +135,101 @@ static void TranslateLine _ANSI_ARGS_((Tk_Canvas canvas, * values in CreateLine. */ -static Tk_CustomOption arrowShapeOption = {ParseArrowShape, - PrintArrowShape, (ClientData) NULL}; -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption arrowShapeOption = { + (Tk_OptionParseProc *) ParseArrowShape, + PrintArrowShape, (ClientData) NULL +}; +static Tk_CustomOption arrowOption = { + (Tk_OptionParseProc *) ArrowParseProc, + ArrowPrintProc, (ClientData) NULL +}; +static Tk_CustomOption smoothOption = { + (Tk_OptionParseProc *) TkSmoothParseProc, + TkSmoothPrintProc, (ClientData) NULL +}; +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; +static Tk_CustomOption dashOption = { + (Tk_OptionParseProc *) TkCanvasDashParseProc, + TkCanvasDashPrintProc, (ClientData) NULL +}; +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, + (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX) +}; +static Tk_CustomOption pixelOption = { + (Tk_OptionParseProc *) TkPixelParseProc, + TkPixelPrintProc, (ClientData) NULL +}; static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_UID, "-arrow", (char *) NULL, (char *) NULL, - "none", Tk_Offset(LineItem, arrow), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-activedash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.activeDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.activeColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.activeStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-activewidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(LineItem, outline.activeWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, + {TK_CONFIG_CUSTOM, "-arrow", (char *) NULL, (char *) NULL, + "none", Tk_Offset(LineItem, arrow), TK_CONFIG_DONT_SET_DEFAULT, &arrowOption}, {TK_CONFIG_CUSTOM, "-arrowshape", (char *) NULL, (char *) NULL, "8 10 3", Tk_Offset(LineItem, arrowShapeA), TK_CONFIG_DONT_SET_DEFAULT, &arrowShapeOption}, {TK_CONFIG_CAP_STYLE, "-capstyle", (char *) NULL, (char *) NULL, "butt", Tk_Offset(LineItem, capStyle), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, - "black", Tk_Offset(LineItem, fg), TK_CONFIG_NULL_OK}, + "black", Tk_Offset(LineItem, outline.color), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-dash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.dash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_PIXELS, "-dashoffset", (char *) NULL, (char *) NULL, + "0", Tk_Offset(LineItem, outline.offset), + TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-disableddash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.disabledDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.disabledColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(LineItem, outline.disabledStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-disabledwidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(LineItem, outline.disabledWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_JOIN_STYLE, "-joinstyle", (char *) NULL, (char *) NULL, "round", Tk_Offset(LineItem, joinStyle), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL, - "0", Tk_Offset(LineItem, smooth), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(LineItem, outline.tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, + {TK_CONFIG_CUSTOM, "-smooth", (char *) NULL, (char *) NULL, + "0", Tk_Offset(LineItem, smooth), + TK_CONFIG_DONT_SET_DEFAULT, &smoothOption}, {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL, "12", Tk_Offset(LineItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(LineItem, fillStipple), TK_CONFIG_NULL_OK}, + (char *) NULL, Tk_Offset(LineItem, outline.stipple), + TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(LineItem, width), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-width", (char *) NULL, (char *) NULL, + "1.0", Tk_Offset(LineItem, outline.width), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; @@ -165,30 +248,21 @@ Tk_ItemType tkLineType = { LineCoords, /* coordProc */ DeleteLine, /* deleteProc */ DisplayLine, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ LineToPoint, /* pointProc */ LineToArea, /* areaProc */ LineToPostscript, /* postscriptProc */ ScaleLine, /* scaleProc */ TranslateLine, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ + (Tk_ItemIndexProc *) GetLineIndex, /* indexProc */ (Tk_ItemCursorProc *) NULL, /* icursorProc */ (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemInsertProc *) LineInsert, /* insertProc */ + LineDeleteCoords, /* dTextProc */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* - * The Tk_Uid's below refer to uids for the various arrow types: - */ - -static Tk_Uid noneUid = NULL; -static Tk_Uid firstUid = NULL; -static Tk_Uid lastUid = NULL; -static Tk_Uid bothUid = NULL; - -/* * The definition below determines how large are static arrays * used to hold spline points (splines larger than this have to * have their arrays malloc-ed). @@ -207,7 +281,7 @@ static Tk_Uid bothUid = NULL; * Results: * A standard Tcl return value. If an error occurred in * creating the item, then an error message is left in - * interp->result; in this case itemPtr is left uninitialized, + * the interp's result; in this case itemPtr is left uninitialized, * so it can be safely freed by the caller. * * Side effects: @@ -223,48 +297,31 @@ CreateLine(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing line. */ + Tcl_Obj *CONST argv[]; /* Arguments describing line. */ { LineItem *linePtr = (LineItem *) itemPtr; int i; - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, " x1 y1 x2 y2 ?x3 y3 ...? ?options?\"", - (char *) NULL); - return TCL_ERROR; - } - /* * Carry out initialization that is needed to set defaults and to * allow proper cleanup after errors during the the remainder of * this procedure. */ + Tk_CreateOutline(&(linePtr->outline)); linePtr->canvas = canvas; linePtr->numPoints = 0; linePtr->coordPtr = NULL; - linePtr->width = 1; - linePtr->fg = None; - linePtr->fillStipple = None; linePtr->capStyle = CapButt; linePtr->joinStyle = JoinRound; - linePtr->gc = None; linePtr->arrowGC = None; - if (noneUid == NULL) { - noneUid = Tk_GetUid("none"); - firstUid = Tk_GetUid("first"); - lastUid = Tk_GetUid("last"); - bothUid = Tk_GetUid("both"); - } - linePtr->arrow = noneUid; + linePtr->arrow = ARROWS_NONE; linePtr->arrowShapeA = (float)8.0; linePtr->arrowShapeB = (float)10.0; linePtr->arrowShapeC = (float)3.0; linePtr->firstArrowPtr = NULL; linePtr->lastArrowPtr = NULL; - linePtr->smooth = 0; + linePtr->smooth = (Tk_SmoothMethod *) NULL; linePtr->splineSteps = 12; /* @@ -273,14 +330,14 @@ CreateLine(interp, canvas, itemPtr, argc, argv) * start with a digit or a minus sign followed by a digit. */ - for (i = 4; i < (argc-1); i+=2) { - if ((!isdigit(UCHAR(argv[i][0]))) && - ((argv[i][0] != '-') - || ((argv[i][1] != '.') && !isdigit(UCHAR(argv[i][1]))))) { + for (i = 0; i < argc; i++) { + char *arg = Tcl_GetStringFromObj(argv[i], NULL); + if ((arg[0] == '-') && (arg[1] >= 'a') + && (arg[1] <= 'z')) { break; } } - if (LineCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) { + if (i && (LineCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { goto error; } if (ConfigureLine(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { @@ -302,7 +359,7 @@ CreateLine(interp, canvas, itemPtr, argc, argv) * on what it does. * * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. * * Side effects: * The coordinates for the given item may be changed. @@ -318,16 +375,16 @@ LineCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { LineItem *linePtr = (LineItem *) itemPtr; - char buffer[TCL_DOUBLE_SPACE]; int i, numPoints; + double *coordPtr; if (argc == 0) { - double *coordPtr; int numCoords; + Tcl_Obj *subobj, *obj = Tcl_NewObj(); numCoords = 2*linePtr->numPoints; if (linePtr->firstArrowPtr != NULL) { @@ -342,35 +399,46 @@ LineCoords(interp, canvas, itemPtr, argc, argv) if ((linePtr->lastArrowPtr != NULL) && (i == (numCoords-2))) { coordPtr = linePtr->lastArrowPtr; } - Tcl_PrintDouble(interp, *coordPtr, buffer); - Tcl_AppendElement(interp, buffer); + subobj = Tcl_NewDoubleObj(*coordPtr); + Tcl_ListObjAppendElement(interp, obj, subobj); } - } else if (argc < 4) { + Tcl_SetObjResult(interp, obj); + return TCL_OK; + } + if (argc == 1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } + } + if (argc & 1) { Tcl_AppendResult(interp, - "too few coordinates for line: must have at least 4", + "odd number of coordinates specified for line", (char *) NULL); return TCL_ERROR; - } else if (argc & 1) { + } else if (argc < 4) { Tcl_AppendResult(interp, - "odd number of coordinates specified for line", + "too few coordinates specified for line", (char *) NULL); return TCL_ERROR; } else { numPoints = argc/2; if (linePtr->numPoints != numPoints) { + coordPtr = (double *) ckalloc((unsigned) + (sizeof(double) * argc)); if (linePtr->coordPtr != NULL) { ckfree((char *) linePtr->coordPtr); } - linePtr->coordPtr = (double *) ckalloc((unsigned) - (sizeof(double) * argc)); + linePtr->coordPtr = coordPtr; linePtr->numPoints = numPoints; } - for (i = argc-1; i >= 0; i--) { - if (Tk_CanvasGetCoord(interp, canvas, argv[i], - &linePtr->coordPtr[i]) != TCL_OK) { - return TCL_ERROR; - } - } + coordPtr = linePtr->coordPtr; + for (i = 0; i <argc; i++) { + if (Tk_CanvasGetCoordFromObj(interp, canvas, argv[i], + coordPtr++) != TCL_OK) { + return TCL_ERROR; + } + } /* * Update arrowheads by throwing away any existing arrow-head @@ -385,7 +453,7 @@ LineCoords(interp, canvas, itemPtr, argc, argv) ckfree((char *) linePtr->lastArrowPtr); linePtr->lastArrowPtr = NULL; } - if (linePtr->arrow != noneUid) { + if (linePtr->arrow != ARROWS_NONE) { ConfigureArrows(canvas, linePtr); } ComputeLineBbox(canvas, linePtr); @@ -403,7 +471,7 @@ LineCoords(interp, canvas, itemPtr, argc, argv) * * Results: * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. + * an error message is left in the interp's result. * * Side effects: * Configuration information, such as colors and stipple @@ -418,7 +486,7 @@ ConfigureLine(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Line item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { LineItem *linePtr = (LineItem *) itemPtr; @@ -426,10 +494,11 @@ ConfigureLine(interp, canvas, itemPtr, argc, argv, flags) GC newGC, arrowGC; unsigned long mask; Tk_Window tkwin; + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) linePtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) linePtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -438,36 +507,42 @@ ConfigureLine(interp, canvas, itemPtr, argc, argv, flags) * graphics contexts. */ - if (linePtr->fg == NULL) { - newGC = arrowGC = None; + state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + if (linePtr->outline.activeWidth > linePtr->outline.width || + linePtr->outline.activeDash.number != 0 || + linePtr->outline.activeColor != NULL || + linePtr->outline.activeStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; } else { - gcValues.foreground = linePtr->fg->pixel; - gcValues.join_style = linePtr->joinStyle; - if (linePtr->width < 0) { - linePtr->width = 1; - } - gcValues.line_width = linePtr->width; - mask = GCForeground|GCJoinStyle|GCLineWidth; - if (linePtr->fillStipple != None) { - gcValues.stipple = linePtr->fillStipple; - gcValues.fill_style = FillStippled; - mask |= GCStipple|GCFillStyle; - } - if (linePtr->arrow == noneUid) { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, + &(linePtr->outline)); + if (mask) { + if (linePtr->arrow == ARROWS_NONE) { gcValues.cap_style = linePtr->capStyle; mask |= GCCapStyle; } - newGC = Tk_GetGCColor(tkwin, mask, &gcValues, linePtr->fg, NULL); + gcValues.join_style = linePtr->joinStyle; + mask |= GCJoinStyle; + newGC = Tk_GetGC(tkwin, mask, &gcValues); gcValues.line_width = 0; - arrowGC = Tk_GetGCColor(tkwin, mask, &gcValues, linePtr->fg, NULL); + arrowGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = arrowGC = None; } - if (linePtr->gc != None) { - Tk_FreeGC(Tk_Display(tkwin), linePtr->gc); + if (linePtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), linePtr->outline.gc); } if (linePtr->arrowGC != None) { Tk_FreeGC(Tk_Display(tkwin), linePtr->arrowGC); } - linePtr->gc = newGC; + linePtr->outline.gc = newGC; linePtr->arrowGC = arrowGC; /* @@ -480,21 +555,26 @@ ConfigureLine(interp, canvas, itemPtr, argc, argv, flags) linePtr->splineSteps = 100; } + if ((!linePtr->numPoints) || (state==TK_STATE_HIDDEN)) { + ComputeLineBbox(canvas, linePtr); + return TCL_OK; + } + /* * Setup arrowheads, if needed. If arrowheads are turned off, * restore the line's endpoints (they were shortened when the * arrowheads were added). */ - if ((linePtr->firstArrowPtr != NULL) && (linePtr->arrow != firstUid) - && (linePtr->arrow != bothUid)) { + if ((linePtr->firstArrowPtr != NULL) && (linePtr->arrow != ARROWS_FIRST) + && (linePtr->arrow != ARROWS_BOTH)) { linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; ckfree((char *) linePtr->firstArrowPtr); linePtr->firstArrowPtr = NULL; } - if ((linePtr->lastArrowPtr != NULL) && (linePtr->arrow != lastUid) - && (linePtr->arrow != bothUid)) { + if ((linePtr->lastArrowPtr != NULL) && (linePtr->arrow != ARROWS_LAST) + && (linePtr->arrow != ARROWS_BOTH)) { int i; i = 2*(linePtr->numPoints-1); @@ -503,15 +583,7 @@ ConfigureLine(interp, canvas, itemPtr, argc, argv, flags) ckfree((char *) linePtr->lastArrowPtr); linePtr->lastArrowPtr = NULL; } - if (linePtr->arrow != noneUid) { - if ((linePtr->arrow != firstUid) && (linePtr->arrow != lastUid) - && (linePtr->arrow != bothUid)) { - Tcl_AppendResult(interp, "bad arrow spec \"", - linePtr->arrow, "\": must be none, first, last, or both", - (char *) NULL); - linePtr->arrow = noneUid; - return TCL_ERROR; - } + if (linePtr->arrow != ARROWS_NONE) { ConfigureArrows(canvas, linePtr); } @@ -550,18 +622,10 @@ DeleteLine(canvas, itemPtr, display) { LineItem *linePtr = (LineItem *) itemPtr; + Tk_DeleteOutline(display, &(linePtr->outline)); if (linePtr->coordPtr != NULL) { ckfree((char *) linePtr->coordPtr); } - if (linePtr->fg != NULL) { - Tk_FreeColor(linePtr->fg); - } - if (linePtr->fillStipple != None) { - Tk_FreeBitmap(display, linePtr->fillStipple); - } - if (linePtr->gc != None) { - Tk_FreeGC(display, linePtr->gc); - } if (linePtr->arrowGC != None) { Tk_FreeGC(display, linePtr->arrowGC); } @@ -598,7 +662,33 @@ ComputeLineBbox(canvas, linePtr) * recomputed. */ { double *coordPtr; - int i, width; + int i, intWidth; + double width; + Tk_State state = linePtr->header.state; + Tk_TSOffset *tsoffset; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + if (!(linePtr->numPoints) || (state==TK_STATE_HIDDEN)) { + linePtr->header.x1 = -1; + linePtr->header.x2 = -1; + linePtr->header.y1 = -1; + linePtr->header.y2 = -1; + return; + } + + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)linePtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } coordPtr = linePtr->coordPtr; linePtr->header.x1 = linePtr->header.x2 = (int) *coordPtr; @@ -618,14 +708,66 @@ ComputeLineBbox(canvas, linePtr) i++, coordPtr += 2) { TkIncludePoint((Tk_Item *) linePtr, coordPtr); } - width = linePtr->width; - if (width < 1) { - width = 1; + width = linePtr->outline.width; + if (width < 1.0) { + width = 1.0; + } + if (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { + TkIncludePoint((Tk_Item *) linePtr, linePtr->firstArrowPtr); + } + if (linePtr->arrow != ARROWS_FIRST) { + TkIncludePoint((Tk_Item *) linePtr, linePtr->lastArrowPtr); + } + } + + tsoffset = &linePtr->outline.tsoffset; + if (tsoffset->flags & TK_OFFSET_INDEX) { + double *coordPtr = linePtr->coordPtr + (tsoffset->flags & ~TK_OFFSET_INDEX); + if (tsoffset->flags <= 0) { + coordPtr = linePtr->coordPtr; + if ((linePtr->arrow == ARROWS_FIRST) || (linePtr->arrow == ARROWS_BOTH)) { + coordPtr = linePtr->firstArrowPtr; + } + } + if (tsoffset->flags > (linePtr->numPoints * 2)) { + coordPtr = linePtr->coordPtr + (linePtr->numPoints * 2); + if ((linePtr->arrow == ARROWS_LAST) || (linePtr->arrow == ARROWS_BOTH)) { + coordPtr = linePtr->lastArrowPtr; + } + } + tsoffset->xoffset = (int) (coordPtr[0] + 0.5); + tsoffset->yoffset = (int) (coordPtr[1] + 0.5); + } else { + if (tsoffset->flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = linePtr->header.x1; + } else if (tsoffset->flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (linePtr->header.x1 + linePtr->header.x2)/2; + } else if (tsoffset->flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = linePtr->header.x2; + } + if (tsoffset->flags & TK_OFFSET_TOP) { + tsoffset->yoffset = linePtr->header.y1; + } else if (tsoffset->flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (linePtr->header.y1 + linePtr->header.y2)/2; + } else if (tsoffset->flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = linePtr->header.y2; + } + } + + intWidth = (int) (width + 0.5); + linePtr->header.x1 -= intWidth; + linePtr->header.x2 += intWidth; + linePtr->header.y1 -= intWidth; + linePtr->header.y2 += intWidth; + + if (linePtr->numPoints==1) { + linePtr->header.x1 -= 1; + linePtr->header.x2 += 1; + linePtr->header.y1 -= 1; + linePtr->header.y2 += 1; + return; } - linePtr->header.x1 -= width; - linePtr->header.x2 += width; - linePtr->header.y1 -= width; - linePtr->header.y2 += width; /* * For mitered lines, make a second pass through all the points. @@ -640,7 +782,7 @@ ComputeLineBbox(canvas, linePtr) int j; if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, - (double) width, miter, miter+2)) { + width, miter, miter+2)) { for (j = 0; j < 4; j += 2) { TkIncludePoint((Tk_Item *) linePtr, miter+j); } @@ -652,14 +794,14 @@ ComputeLineBbox(canvas, linePtr) * Add in the sizes of arrowheads, if any. */ - if (linePtr->arrow != noneUid) { - if (linePtr->arrow != lastUid) { + if (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; i++, coordPtr += 2) { TkIncludePoint((Tk_Item *) linePtr, coordPtr); } } - if (linePtr->arrow != firstUid) { + if (linePtr->arrow != ARROWS_FIRST) { for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; i++, coordPtr += 2) { TkIncludePoint((Tk_Item *) linePtr, coordPtr); @@ -710,13 +852,34 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) XPoint staticPoints[MAX_STATIC_POINTS]; XPoint *pointPtr; XPoint *pPtr; - double *coordPtr; + double *coordPtr, linewidth; int i, numPoints; + Tk_State state = itemPtr->state; + Pixmap stipple = linePtr->outline.stipple; - if (linePtr->gc == None) { + if ((!linePtr->numPoints)||(linePtr->outline.gc==None)) { return; } + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + linewidth = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeStipple!=None) { + stipple = linePtr->outline.activeStipple; + } + if (linePtr->outline.activeWidth>linewidth) { + linewidth = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledStipple!=None) { + stipple = linePtr->outline.disabledStipple; + } + if (linePtr->outline.disabledWidth>linewidth) { + linewidth = linePtr->outline.activeWidth; + } + } /* * Build up an array of points in screen coordinates. Use a * static array unless the line has an enormous number of points; @@ -725,7 +888,9 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) */ if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; + numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL, + linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, + (double *) NULL); } else { numPoints = linePtr->numPoints; } @@ -737,7 +902,7 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) } if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps, pointPtr, (double *) NULL); } else { @@ -755,12 +920,21 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) * GC is supposed to be read-only. */ - if (linePtr->fillStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, linePtr->gc); - Tk_CanvasSetStippleOrigin(canvas, linePtr->arrowGC); + if (Tk_ChangeOutlineGC(canvas, itemPtr, &(linePtr->outline))) { + Tk_CanvasSetOffset(canvas, linePtr->arrowGC, &linePtr->outline.tsoffset); } - XDrawLines(display, drawable, linePtr->gc, pointPtr, numPoints, + if (numPoints>1) { + XDrawLines(display, drawable, linePtr->outline.gc, pointPtr, numPoints, CoordModeOrigin); + } else { + int intwidth = (int) (linewidth + 0.5); + if (intwidth<1) { + intwidth=1; + } + XFillArc(display, drawable, linePtr->outline.gc, + pointPtr->x - intwidth/2, pointPtr->y - intwidth/2, + (unsigned int)intwidth+1, (unsigned int)intwidth+1, 0, 64*360); + } if (pointPtr != staticPoints) { ckfree((char *) pointPtr); } @@ -771,14 +945,13 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) if (linePtr->firstArrowPtr != NULL) { TkFillPolygon(canvas, linePtr->firstArrowPtr, PTS_IN_ARROW, - display, drawable, linePtr->gc, NULL); + display, drawable, linePtr->arrowGC, NULL); } if (linePtr->lastArrowPtr != NULL) { TkFillPolygon(canvas, linePtr->lastArrowPtr, PTS_IN_ARROW, - display, drawable, linePtr->gc, NULL); + display, drawable, linePtr->arrowGC, NULL); } - if (linePtr->fillStipple != None) { - XSetTSOrigin(display, linePtr->gc, 0, 0); + if (Tk_ResetOutlineGC(canvas, itemPtr, &(linePtr->outline))) { XSetTSOrigin(display, linePtr->arrowGC, 0, 0); } } @@ -786,6 +959,325 @@ DisplayLine(canvas, itemPtr, display, drawable, x, y, width, height) /* *-------------------------------------------------------------- * + * LineInsert -- + * + * Insert coords into a line item at a given index. + * + * Results: + * None. + * + * Side effects: + * The coords in the given item is modified. + * + *-------------------------------------------------------------- + */ + +static void +LineInsert(canvas, itemPtr, beforeThis, obj) + Tk_Canvas canvas; /* Canvas containing text item. */ + Tk_Item *itemPtr; /* Line item to be modified. */ + int beforeThis; /* Index before which new coordinates + * are to be inserted. */ + Tcl_Obj *obj; /* New coordinates to be inserted. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + int length, argc, i; + double *new, *coordPtr; + Tk_State state = itemPtr->state; + Tcl_Obj **objv; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + if (!obj || (Tcl_ListObjGetElements((Tcl_Interp *) NULL, obj, &argc, &objv) != TCL_OK) + || !argc || argc&1) { + return; + } + length = 2*linePtr->numPoints; + if (beforeThis < 0) { + beforeThis = 0; + } + if (beforeThis > length) { + beforeThis = length; + } + if (linePtr->firstArrowPtr != NULL) { + linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; + linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; + } + if (linePtr->lastArrowPtr != NULL) { + linePtr->coordPtr[length-2] = linePtr->lastArrowPtr[0]; + linePtr->coordPtr[length-1] = linePtr->lastArrowPtr[1]; + } + new = (double *) ckalloc((unsigned)(sizeof(double) * (length + argc))); + for(i=0; i<beforeThis; i++) { + new[i] = linePtr->coordPtr[i]; + } + for(i=0; i<argc; i++) { + if (Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,objv[i], + new+(i+beforeThis))!=TCL_OK) { + Tcl_ResetResult(((TkCanvas *)canvas)->interp); + ckfree((char *) new); + return; + } + } + + for(i=beforeThis; i<length; i++) { + new[i+argc] = linePtr->coordPtr[i]; + } + if(linePtr->coordPtr) ckfree((char *)linePtr->coordPtr); + linePtr->coordPtr = new; + linePtr->numPoints = (length + argc)/2; + + if ((length>3) && (state != TK_STATE_HIDDEN)) { + /* + * This is some optimizing code that will result that only the part + * of the polygon that changed (and the objects that are overlapping + * with that part) need to be redrawn. A special flag is set that + * instructs the general canvas code not to redraw the whole + * object. If this flag is not set, the canvas will do the redrawing, + * otherwise I have to do it here. + */ + itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW; + + if (beforeThis>0) {beforeThis -= 2; argc+=2; } + if ((beforeThis+argc)<length) argc+=2; + if (linePtr->smooth) { + if(beforeThis>0) { + beforeThis-=2; argc+=2; + } + if((beforeThis+argc+2)<length) { + argc+=2; + } + } + itemPtr->x1 = itemPtr->x2 = (int) linePtr->coordPtr[beforeThis]; + itemPtr->y1 = itemPtr->y2 = (int) linePtr->coordPtr[beforeThis+1]; + if ((linePtr->firstArrowPtr != NULL) && (beforeThis<1)) { + /* include old first arrow */ + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && ((beforeThis+argc)>=length)) { + /* include old last arrow */ + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + coordPtr = linePtr->coordPtr+beforeThis+2; + for(i=2; i<argc; i+=2) { + TkIncludePoint(itemPtr, coordPtr); + coordPtr+=2; + } + } + if (linePtr->firstArrowPtr != NULL) { + ckfree((char *) linePtr->firstArrowPtr); + linePtr->firstArrowPtr = NULL; + } + if (linePtr->lastArrowPtr != NULL) { + ckfree((char *) linePtr->lastArrowPtr); + linePtr->lastArrowPtr = NULL; + } + if (linePtr->arrow != ARROWS_NONE) { + ConfigureArrows(canvas, linePtr); + } + + if(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW) { + double width; + int intWidth; + if ((linePtr->firstArrowPtr != NULL) && (beforeThis>2)) { + /* include new first arrow */ + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && ((beforeThis+argc)<(length-2))) { + /* include new right arrow */ + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + intWidth = (int) (width + 0.5); + if (intWidth < 1) { + intWidth = 1; + } + itemPtr->x1 -= intWidth; itemPtr->y1 -= intWidth; + itemPtr->x2 += intWidth; itemPtr->y2 += intWidth; + Tk_CanvasEventuallyRedraw(canvas, itemPtr->x1, itemPtr->y1, + itemPtr->x2, itemPtr->y2); + } + + ComputeLineBbox(canvas, linePtr); +} + +/* + *-------------------------------------------------------------- + * + * LineDeleteCoords -- + * + * Delete one or more coordinates from a line item. + * + * Results: + * None. + * + * Side effects: + * Characters between "first" and "last", inclusive, get + * deleted from itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +LineDeleteCoords(canvas, itemPtr, first, last) + Tk_Canvas canvas; /* Canvas containing itemPtr. */ + Tk_Item *itemPtr; /* Item in which to delete characters. */ + int first; /* Index of first character to delete. */ + int last; /* Index of last character to delete. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + int count, i, first1, last1; + int length = 2*linePtr->numPoints; + double *coordPtr; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + first &= -2; + last &= -2; + + if (first < 0) { + first = 0; + } + if (last >= length) { + last = length-2; + } + if (first > last) { + return; + } + if (linePtr->firstArrowPtr != NULL) { + linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; + linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; + } + if (linePtr->lastArrowPtr != NULL) { + linePtr->coordPtr[length-2] = linePtr->lastArrowPtr[0]; + linePtr->coordPtr[length-1] = linePtr->lastArrowPtr[1]; + } + first1 = first; last1 = last; + if(first1>0) first1 -= 2; + if(last1<length-2) last1 += 2; + if (linePtr->smooth) { + if(first1>0) first1 -= 2; + if(last1<length-2) last1 += 2; + } + + if((first1<2) && (last1 >= length-2)) { + /* + * This is some optimizing code that will result that only the part + * of the line that changed (and the objects that are overlapping + * with that part) need to be redrawn. A special flag is set that + * instructs the general canvas code not to redraw the whole + * object. If this flag is set, the redrawing has to be done here, + * otherwise the general Canvas code will take care of it. + */ + + itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW; + itemPtr->x1 = itemPtr->x2 = (int) linePtr->coordPtr[first1]; + itemPtr->y1 = itemPtr->y2 = (int) linePtr->coordPtr[first1+1]; + if ((linePtr->firstArrowPtr != NULL) && (first1<2)) { + /* include old first arrow */ + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && (last1>=length-2)) { + /* include old last arrow */ + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + coordPtr = linePtr->coordPtr+first1+2; + for (i=first1+2; i<=last1; i+=2) { + TkIncludePoint(itemPtr, coordPtr); + coordPtr+=2; + } + } + + count = last + 2 - first; + for (i=last+2; i<length; i++) { + linePtr->coordPtr[i-count] = linePtr->coordPtr[i]; + } + linePtr->numPoints -= count/2; + if (linePtr->firstArrowPtr != NULL) { + ckfree((char *) linePtr->firstArrowPtr); + linePtr->firstArrowPtr = NULL; + } + if (linePtr->lastArrowPtr != NULL) { + ckfree((char *) linePtr->lastArrowPtr); + linePtr->lastArrowPtr = NULL; + } + if (linePtr->arrow != ARROWS_NONE) { + ConfigureArrows(canvas, linePtr); + } + if(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW) { + double width; + int intWidth; + if ((linePtr->firstArrowPtr != NULL) && (first1<4)) { + /* include new first arrow */ + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && (last1>(length-4))) { + /* include new right arrow */ + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint(itemPtr, coordPtr); + } + } + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + intWidth = (int) (width + 0.5); + if (intWidth < 1) { + intWidth = 1; + } + itemPtr->x1 -= intWidth; itemPtr->y1 -= intWidth; + itemPtr->x2 += intWidth; itemPtr->y2 += intWidth; + Tk_CanvasEventuallyRedraw(canvas, itemPtr->x1, itemPtr->y1, + itemPtr->x2, itemPtr->y2); + } + ComputeLineBbox(canvas, linePtr); +} + +/* + *-------------------------------------------------------------- + * * LineToPoint -- * * Computes the distance from a given point to a given @@ -810,11 +1302,12 @@ LineToPoint(canvas, itemPtr, pointPtr) Tk_Item *itemPtr; /* Item to check against point. */ double *pointPtr; /* Pointer to x and y coordinates. */ { + Tk_State state = itemPtr->state; LineItem *linePtr = (LineItem *) itemPtr; double *coordPtr, *linePoints; double staticSpace[2*MAX_STATIC_POINTS]; double poly[10]; - double bestDist, dist; + double bestDist, dist, width; int numPoints, count; int changedMiterToBevel; /* Non-zero means that a mitered corner * had to be treated as beveled after all @@ -827,15 +1320,32 @@ LineToPoint(canvas, itemPtr, pointPtr) * against which to do the check. */ + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; + numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL, + linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, + (double *) NULL); if (numPoints <= MAX_STATIC_POINTS) { linePoints = staticSpace; } else { linePoints = (double *) ckalloc((unsigned) (2*numPoints*sizeof(double))); } - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, linePoints); } else { @@ -843,6 +1353,19 @@ LineToPoint(canvas, itemPtr, pointPtr) linePoints = linePtr->coordPtr; } + if (width < 1.0) { + width = 1.0; + } + + if (!numPoints || itemPtr->state==TK_STATE_HIDDEN) { + return bestDist; + } else if (numPoints == 1) { + bestDist = hypot(linePoints[0] - pointPtr[0], linePoints[1] - pointPtr[1]) + - width/2.0; + if (bestDist < 0) bestDist = 0; + return bestDist; + } + /* * The overall idea is to iterate through all of the edges of * the line, computing a polygon for each edge and testing the @@ -863,7 +1386,7 @@ LineToPoint(canvas, itemPtr, pointPtr) || ((linePtr->joinStyle == JoinRound) && (count != numPoints))) { dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) - - linePtr->width/2.0; + - width/2.0; if (dist <= 0.0) { bestDist = 0.0; goto done; @@ -879,7 +1402,7 @@ LineToPoint(canvas, itemPtr, pointPtr) */ if (count == numPoints) { - TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width, + TkGetButtPoints(coordPtr+2, coordPtr, width, linePtr->capStyle == CapProjecting, poly, poly+2); } else if ((linePtr->joinStyle == JoinMiter) && !changedMiterToBevel) { poly[0] = poly[6]; @@ -887,7 +1410,7 @@ LineToPoint(canvas, itemPtr, pointPtr) poly[2] = poly[4]; poly[3] = poly[5]; } else { - TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width, 0, + TkGetButtPoints(coordPtr+2, coordPtr, width, 0, poly, poly+2); /* @@ -911,17 +1434,17 @@ LineToPoint(canvas, itemPtr, pointPtr) } } if (count == 2) { - TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, + TkGetButtPoints(coordPtr, coordPtr+2, width, linePtr->capStyle == CapProjecting, poly+4, poly+6); } else if (linePtr->joinStyle == JoinMiter) { if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, - (double) linePtr->width, poly+4, poly+6) == 0) { + width, poly+4, poly+6) == 0) { changedMiterToBevel = 1; - TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, + TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4, poly+6); } } else { - TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, 0, + TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4, poly+6); } poly[8] = poly[0]; @@ -942,7 +1465,7 @@ LineToPoint(canvas, itemPtr, pointPtr) if (linePtr->capStyle == CapRound) { dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) - - linePtr->width/2.0; + - width/2.0; if (dist <= 0.0) { bestDist = 0.0; goto done; @@ -955,8 +1478,8 @@ LineToPoint(canvas, itemPtr, pointPtr) * If there are arrowheads, check the distance to the arrowheads. */ - if (linePtr->arrow != noneUid) { - if (linePtr->arrow != lastUid) { + if (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { dist = TkPolygonToPoint(linePtr->firstArrowPtr, PTS_IN_ARROW, pointPtr); if (dist <= 0.0) { @@ -966,7 +1489,7 @@ LineToPoint(canvas, itemPtr, pointPtr) bestDist = dist; } } - if (linePtr->arrow != firstUid) { + if (linePtr->arrow != ARROWS_FIRST) { dist = TkPolygonToPoint(linePtr->lastArrowPtr, PTS_IN_ARROW, pointPtr); if (dist <= 0.0) { @@ -1016,6 +1539,35 @@ LineToArea(canvas, itemPtr, rectPtr) double staticSpace[2*MAX_STATIC_POINTS]; double *linePoints; int numPoints, result; + double radius, width; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + + radius = (width+1.0)/2.0; + + if ((state==TK_STATE_HIDDEN) || !linePtr->numPoints) { + return -1; + } else if (linePtr->numPoints == 1) { + double oval[4]; + oval[0] = linePtr->coordPtr[0]-radius; + oval[1] = linePtr->coordPtr[1]-radius; + oval[2] = linePtr->coordPtr[0]+radius; + oval[3] = linePtr->coordPtr[1]+radius; + return TkOvalToArea(oval, rectPtr); + } /* * Handle smoothed lines by generating an expanded set of points @@ -1023,14 +1575,16 @@ LineToArea(canvas, itemPtr, rectPtr) */ if ((linePtr->smooth) && (linePtr->numPoints > 2)) { - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; + numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL, + linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, + (double *) NULL); if (numPoints <= MAX_STATIC_POINTS) { linePoints = staticSpace; } else { linePoints = (double *) ckalloc((unsigned) (2*numPoints*sizeof(double))); } - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, linePoints); } else { @@ -1042,8 +1596,12 @@ LineToArea(canvas, itemPtr, rectPtr) * Check the segments of the line. */ + if (width < 1.0) { + width = 1.0; + } + result = TkThickPolyLineToArea(linePoints, numPoints, - (double) linePtr->width, linePtr->capStyle, linePtr->joinStyle, + width, linePtr->capStyle, linePtr->joinStyle, rectPtr); if (result == 0) { goto done; @@ -1053,15 +1611,15 @@ LineToArea(canvas, itemPtr, rectPtr) * Check arrowheads, if any. */ - if (linePtr->arrow != noneUid) { - if (linePtr->arrow != lastUid) { + if (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { if (TkPolygonToArea(linePtr->firstArrowPtr, PTS_IN_ARROW, rectPtr) != result) { result = 0; goto done; } } - if (linePtr->arrow != firstUid) { + if (linePtr->arrow != ARROWS_FIRST) { if (TkPolygonToArea(linePtr->lastArrowPtr, PTS_IN_ARROW, rectPtr) != result) { result = 0; @@ -1134,7 +1692,7 @@ ScaleLine(canvas, itemPtr, originX, originY, scaleX, scaleY) coordPtr[0] = originX + scaleX*(*coordPtr - originX); coordPtr[1] = originY + scaleY*(coordPtr[1] - originY); } - if (linePtr->arrow != noneUid) { + if (linePtr->arrow != ARROWS_NONE) { ConfigureArrows(canvas, linePtr); } ComputeLineBbox(canvas, linePtr); @@ -1143,6 +1701,96 @@ ScaleLine(canvas, itemPtr, originX, originY, scaleX, scaleY) /* *-------------------------------------------------------------- * + * GetLineIndex -- + * + * Parse an index into a line item and return either its value + * or an error. + * + * Results: + * A standard Tcl result. If all went well, then *indexPtr is + * filled in with the index (into itemPtr) corresponding to + * string. Otherwise an error message is left in + * interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetLineIndex(interp, canvas, itemPtr, obj, indexPtr) + Tcl_Interp *interp; /* Used for error reporting. */ + Tk_Canvas canvas; /* Canvas containing item. */ + Tk_Item *itemPtr; /* Item for which the index is being + * specified. */ + Tcl_Obj *obj; /* Specification of a particular coord + * in itemPtr's line. */ + int *indexPtr; /* Where to store converted index. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + size_t length; + char *string = Tcl_GetStringFromObj(obj, (int *) &length); + + if (string[0] == 'e') { + if (strncmp(string, "end", length) == 0) { + *indexPtr = 2*linePtr->numPoints; + } else { + badIndex: + + /* + * Some of the paths here leave messages in interp->result, + * so we have to clear it out before storing our own message. + */ + + Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); + Tcl_AppendResult(interp, "bad index \"", string, "\"", + (char *) NULL); + return TCL_ERROR; + } + } else if (string[0] == '@') { + int i; + double x ,y, bestDist, dist, *coordPtr; + char *end, *p; + + p = string+1; + x = strtod(p, &end); + if ((end == p) || (*end != ',')) { + goto badIndex; + } + p = end+1; + y = strtod(p, &end); + if ((end == p) || (*end != 0)) { + goto badIndex; + } + bestDist = 1.0e36; + coordPtr = linePtr->coordPtr; + *indexPtr = 0; + for(i=0; i<linePtr->numPoints; i++) { + dist = hypot(coordPtr[0] - x, coordPtr[1] - y); + if (dist<bestDist) { + bestDist = dist; + *indexPtr = 2*i; + } + coordPtr += 2; + } + } else { + if (Tcl_GetIntFromObj(interp, obj, indexPtr) != TCL_OK) { + goto badIndex; + } + *indexPtr &= -2; /* if index is odd, make it even */ + if (*indexPtr < 0){ + *indexPtr = 0; + } else if (*indexPtr > (2*linePtr->numPoints)) { + *indexPtr = (2*linePtr->numPoints); + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * * TranslateLine -- * * This procedure is called to move a line by a given amount. @@ -1216,7 +1864,7 @@ ParseArrowShape(clientData, interp, tkwin, value, recordPtr, offset) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Used for error reporting. */ Tk_Window tkwin; /* Not used. */ - char *value; /* Textual specification of arrow shape. */ + CONST char *value; /* Textual specification of arrow shape. */ char *recordPtr; /* Pointer to item record in which to * store arrow information. */ int offset; /* Offset of shape information in widget @@ -1231,7 +1879,7 @@ ParseArrowShape(clientData, interp, tkwin, value, recordPtr, offset) panic("ParseArrowShape received bogus offset"); } - if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) { + if (Tcl_SplitList(interp, (char *) value, &argc, &argv) != TCL_OK) { syntaxError: Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad arrow shape \"", value, @@ -1296,6 +1944,117 @@ PrintArrowShape(clientData, tkwin, recordPtr, offset, freeProcPtr) return buffer; } + +/* + *-------------------------------------------------------------- + * + * ArrowParseProc -- + * + * This procedure is invoked during option processing to handle + * the "-arrow" option. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The arrow for a given item gets replaced by the arrow + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +static int +ArrowParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + int c; + size_t length; + + register Arrows *arrowPtr = (Arrows *) (widgRec + offset); + + if(value == NULL || *value == 0) { + *arrowPtr = ARROWS_NONE; + return TCL_OK; + } + + c = value[0]; + length = strlen(value); + + if ((c == 'n') && (strncmp(value, "none", length) == 0)) { + *arrowPtr = ARROWS_NONE; + return TCL_OK; + } + if ((c == 'f') && (strncmp(value, "first", length) == 0)) { + *arrowPtr = ARROWS_FIRST; + return TCL_OK; + } + if ((c == 'l') && (strncmp(value, "last", length) == 0)) { + *arrowPtr = ARROWS_LAST; + return TCL_OK; + } + if ((c == 'b') && (strncmp(value, "both", length) == 0)) { + *arrowPtr = ARROWS_BOTH; + return TCL_OK; + } + + Tcl_AppendResult(interp, "bad arrow spec \"", value, + "\": must be none, first, last, or both", + (char *) NULL); + *arrowPtr = ARROWS_NONE; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * ArrowPrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-arrow" + * configuration option. + * + * Results: + * The return value is a string describing the arrows for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static char * +ArrowPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register Arrows *arrowPtr = (Arrows *) (widgRec + offset); + + switch (*arrowPtr) { + case ARROWS_FIRST: + return "first"; + case ARROWS_LAST: + return "last"; + case ARROWS_BOTH: + return "both"; + default: + return "none"; + } +} + /* *-------------------------------------------------------------- * @@ -1335,6 +2094,27 @@ ConfigureArrows(canvas, linePtr) double vertX, vertY; /* Position of arrowhead vertex. */ double shapeA, shapeB, shapeC; /* Adjusted coordinates (see * explanation below). */ + double width; + Tk_State state = linePtr->header.state; + + if (linePtr->numPoints <2) { + return TCL_OK; + } + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = linePtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)linePtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } /* * The code below makes a tiny increase in the shape parameters @@ -1345,7 +2125,7 @@ ConfigureArrows(canvas, linePtr) shapeA = linePtr->arrowShapeA + 0.001; shapeB = linePtr->arrowShapeB + 0.001; - shapeC = linePtr->arrowShapeC + linePtr->width/2.0 + 0.001; + shapeC = linePtr->arrowShapeC + width/2.0 + 0.001; /* * If there's an arrowhead on the first point of the line, compute @@ -1353,9 +2133,9 @@ ConfigureArrows(canvas, linePtr) * line doesn't stick out past the leading edge of the arrowhead. */ - fracHeight = (linePtr->width/2.0)/shapeC; + fracHeight = (width/2.0)/shapeC; backup = fracHeight*shapeB + shapeA*(1.0 - fracHeight)/2.0; - if (linePtr->arrow != lastUid) { + if (linePtr->arrow != ARROWS_LAST) { poly = linePtr->firstArrowPtr; if (poly == NULL) { poly = (double *) ckalloc((unsigned) @@ -1400,7 +2180,7 @@ ConfigureArrows(canvas, linePtr) * Similar arrowhead calculation for the last point of the line. */ - if (linePtr->arrow != firstUid) { + if (linePtr->arrow != ARROWS_FIRST) { coordPtr = linePtr->coordPtr + 2*(linePtr->numPoints-2); poly = linePtr->lastArrowPtr; if (poly == NULL) { @@ -1449,7 +2229,7 @@ ConfigureArrows(canvas, linePtr) * Results: * The return value is a standard Tcl result. If an error * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used + * left in the interp's result, replacing whatever used * to be there. If no error occurs, then Postscript for the * item is appended to the result. * @@ -1471,24 +2251,78 @@ LineToPostscript(interp, canvas, itemPtr, prepass) * final Postscript is being created. */ { LineItem *linePtr = (LineItem *) itemPtr; - char buffer[200]; + char buffer[64 + TCL_INTEGER_SPACE]; char *style; - if (linePtr->fg == NULL) { + double width; + XColor *color; + Pixmap stipple; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = linePtr->outline.width; + color = linePtr->outline.color; + stipple = linePtr->outline.stipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + if (linePtr->outline.activeColor!=NULL) { + color = linePtr->outline.activeColor; + } + if (linePtr->outline.activeStipple!=None) { + stipple = linePtr->outline.activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + if (linePtr->outline.disabledColor!=NULL) { + color = linePtr->outline.disabledColor; + } + if (linePtr->outline.disabledStipple!=None) { + stipple = linePtr->outline.disabledStipple; + } + } + + if (color == NULL || linePtr->numPoints<1 || linePtr->coordPtr==NULL) { return TCL_OK; } + if (linePtr->numPoints==1) { + sprintf(buffer, "%.15g %.15g translate %.15g %.15g", + linePtr->coordPtr[0], Tk_CanvasPsY(canvas, linePtr->coordPtr[1]), + width/2.0, width/2.0); + Tcl_AppendResult(interp, "matrix currentmatrix\n",buffer, + " scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n", (char *) NULL); + if (Tk_CanvasPsColor(interp, canvas, color) + != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "clip ", (char *) NULL); + if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "fill\n", (char *) NULL); + } + return TCL_OK; + } /* * Generate a path for the line's center-line (do this differently * for straight lines and smoothed lines). */ - if ((!linePtr->smooth) || (linePtr->numPoints <= 2)) { + if ((!linePtr->smooth) || (linePtr->numPoints < 3)) { Tk_CanvasPsPath(interp, canvas, linePtr->coordPtr, linePtr->numPoints); } else { - if (linePtr->fillStipple == None) { - TkMakeBezierPostscript(interp, canvas, linePtr->coordPtr, - linePtr->numPoints); + if ((stipple == None) && linePtr->smooth->postscriptProc) { + linePtr->smooth->postscriptProc(interp, canvas, + linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps); } else { /* * Special hack: Postscript printers don't appear to be able @@ -1503,13 +2337,15 @@ LineToPostscript(interp, canvas, itemPtr, prepass) double *pointPtr; int numPoints; - numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; + numPoints = linePtr->smooth->coordProc(canvas, (double *) NULL, + linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, + (double *) NULL); pointPtr = staticPoints; if (numPoints > MAX_STATIC_POINTS) { pointPtr = (double *) ckalloc((unsigned) (numPoints * 2 * sizeof(double))); } - numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, pointPtr); Tk_CanvasPsPath(interp, canvas, pointPtr, numPoints); @@ -1523,8 +2359,6 @@ LineToPostscript(interp, canvas, itemPtr, prepass) * Set other line-drawing parameters and stroke out the line. */ - sprintf(buffer, "%d setlinewidth\n", linePtr->width); - Tcl_AppendResult(interp, buffer, (char *) NULL); style = "0 setlinecap\n"; if (linePtr->capStyle == CapRound) { style = "1 setlinecap\n"; @@ -1539,17 +2373,10 @@ LineToPostscript(interp, canvas, itemPtr, prepass) style = "2 setlinejoin\n"; } Tcl_AppendResult(interp, style, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, linePtr->fg) != TCL_OK) { + + if (Tk_CanvasPsOutline(canvas, itemPtr, + &(linePtr->outline)) != TCL_OK) { return TCL_ERROR; - }; - if (linePtr->fillStipple != None) { - Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, linePtr->fillStipple) - != TCL_OK) { - return TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); } /* @@ -1557,7 +2384,7 @@ LineToPostscript(interp, canvas, itemPtr, prepass) */ if (linePtr->firstArrowPtr != NULL) { - if (linePtr->fillStipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } @@ -1567,7 +2394,7 @@ LineToPostscript(interp, canvas, itemPtr, prepass) } } if (linePtr->lastArrowPtr != NULL) { - if (linePtr->fillStipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } if (ArrowheadPostscript(interp, canvas, linePtr, @@ -1589,7 +2416,7 @@ LineToPostscript(interp, canvas, itemPtr, prepass) * Results: * The return value is a standard Tcl result. If an error * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used + * left in the interp's result, replacing whatever used * to be there. If no error occurs, then Postscript for the * arrowhead is appended to the result. * @@ -1609,10 +2436,28 @@ ArrowheadPostscript(interp, canvas, linePtr, arrowPtr) double *arrowPtr; /* Pointer to first of five points * describing arrowhead polygon. */ { + Pixmap stipple; + Tk_State state = linePtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + stipple = linePtr->outline.stipple; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)linePtr) { + if (linePtr->outline.activeStipple!=None) { + stipple = linePtr->outline.activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (linePtr->outline.activeStipple!=None) { + stipple = linePtr->outline.disabledStipple; + } + } + Tk_CanvasPsPath(interp, canvas, arrowPtr, PTS_IN_ARROW); - if (linePtr->fillStipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "clip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, linePtr->fillStipple) + if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) { return TCL_ERROR; } @@ -1621,3 +2466,4 @@ ArrowheadPostscript(interp, canvas, linePtr, arrowPtr) } return TCL_OK; } + diff --git a/tk/generic/tkCanvPoly.c b/tk/generic/tkCanvPoly.c index 79c7b6c50b4..60616e173b9 100644 --- a/tk/generic/tkCanvPoly.c +++ b/tk/generic/tkCanvPoly.c @@ -5,6 +5,7 @@ * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-2000 Ajuba Solutions. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -15,6 +16,7 @@ #include <stdio.h> #include "tkInt.h" #include "tkPort.h" +#include "tkCanvas.h" /* * The structure below defines the record for each polygon item. @@ -23,7 +25,8 @@ typedef struct PolygonItem { Tk_Item header; /* Generic stuff that's the same for all * types. MUST BE FIRST IN STRUCTURE. */ - int numPoints; /* Number of points in polygon (always >= 3). + Tk_Outline outline; /* Outline structure */ + int numPoints; /* Number of points in polygon. * Polygon is always closed. */ int pointsAllocated; /* Number of points for which space is * allocated at *coordPtr. */ @@ -31,13 +34,16 @@ typedef struct PolygonItem { * x- and y-coords of all points in polygon. * X-coords are even-valued indices, y-coords * are corresponding odd-valued indices. */ - int width; /* Width of outline. */ - XColor *outlineColor; /* Color for outline. */ - GC outlineGC; /* Graphics context for drawing outline. */ + int joinStyle; /* Join style for outline */ + Tk_TSOffset tsoffset; XColor *fillColor; /* Foreground color for polygon. */ + XColor *activeFillColor; /* Foreground color for polygon if state is active. */ + XColor *disabledFillColor; /* Foreground color for polygon if state is disabled. */ Pixmap fillStipple; /* Stipple bitmap for filling polygon. */ + Pixmap activeFillStipple; /* Stipple bitmap for filling polygon if state is active. */ + Pixmap disabledFillStipple; /* Stipple bitmap for filling polygon if state is disabled. */ GC fillGC; /* Graphics context for filling polygon. */ - int smooth; /* Non-zero means draw shape smoothed (i.e. + Tk_SmoothMethod *smooth; /* Non-zero means draw shape smoothed (i.e. * with Bezier splines). */ int splineSteps; /* Number of steps in each spline segment. */ int autoClosed; /* Zero means the given polygon was closed, @@ -48,25 +54,106 @@ typedef struct PolygonItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption smoothOption = { + (Tk_OptionParseProc *) TkSmoothParseProc, + TkSmoothPrintProc, (ClientData) NULL +}; +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; +static Tk_CustomOption dashOption = { + (Tk_OptionParseProc *) TkCanvasDashParseProc, + TkCanvasDashPrintProc, (ClientData) NULL +}; +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, + (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX) +}; +static Tk_CustomOption pixelOption = { + (Tk_OptionParseProc *) TkPixelParseProc, + TkPixelPrintProc, (ClientData) NULL +}; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_CUSTOM, "-activedash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.activeDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, activeFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-activeoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.activeColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activeoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.activeStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, activeFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-activewidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(PolygonItem, outline.activeWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, + {TK_CONFIG_CUSTOM, "-dash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.dash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_PIXELS, "-dashoffset", (char *) NULL, (char *) NULL, + "0", Tk_Offset(PolygonItem, outline.offset), + TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-disableddash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.disabledDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, disabledFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-disabledoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.disabledColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.disabledStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, disabledFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-disabledwidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(PolygonItem, outline.disabledWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, "black", Tk_Offset(PolygonItem, fillColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_JOIN_STYLE, "-joinstyle", (char *) NULL, (char *) NULL, + "round", Tk_Offset(PolygonItem, joinStyle), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(PolygonItem, tsoffset), + TK_CONFIG_NULL_OK, &offsetOption}, {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(PolygonItem, outlineColor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL, - "0", Tk_Offset(PolygonItem, smooth), TK_CONFIG_DONT_SET_DEFAULT}, + (char *) NULL, Tk_Offset(PolygonItem, outline.color), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-outlineoffset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(PolygonItem, outline.tsoffset), + TK_CONFIG_NULL_OK, &offsetOption}, + {TK_CONFIG_BITMAP, "-outlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(PolygonItem, outline.stipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-smooth", (char *) NULL, (char *) NULL, + "0", Tk_Offset(PolygonItem, smooth), + TK_CONFIG_DONT_SET_DEFAULT, &smoothOption}, {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL, "12", Tk_Offset(PolygonItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(PolygonItem, fillStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(PolygonItem, width), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-width", (char *) NULL, (char *) NULL, + "1.0", Tk_Offset(PolygonItem, outline.width), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; @@ -79,18 +166,25 @@ static void ComputePolygonBbox _ANSI_ARGS_((Tk_Canvas canvas, PolygonItem *polyPtr)); static int ConfigurePolygon _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreatePolygon _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeletePolygon _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayPolygon _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display, Drawable dst, int x, int y, int width, int height)); +static int GetPolygonIndex _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, + Tcl_Obj *obj, int *indexPtr)); static int PolygonCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); +static void PolygonDeleteCoords _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, int first, int last)); +static void PolygonInsert _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, int beforeThis, Tcl_Obj *obj)); static int PolygonToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); static double PolygonToPoint _ANSI_ARGS_((Tk_Canvas canvas, @@ -117,18 +211,18 @@ Tk_ItemType tkPolygonType = { PolygonCoords, /* coordProc */ DeletePolygon, /* deleteProc */ DisplayPolygon, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ PolygonToPoint, /* pointProc */ PolygonToArea, /* areaProc */ PolygonToPostscript, /* postscriptProc */ ScalePolygon, /* scaleProc */ TranslatePolygon, /* translateProc */ - (Tk_ItemIndexProc *) NULL, /* indexProc */ + (Tk_ItemIndexProc *) GetPolygonIndex,/* indexProc */ (Tk_ItemCursorProc *) NULL, /* icursorProc */ (Tk_ItemSelectionProc *) NULL, /* selectionProc */ - (Tk_ItemInsertProc *) NULL, /* insertProc */ - (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemInsertProc *) PolygonInsert,/* insertProc */ + PolygonDeleteCoords, /* dTextProc */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* @@ -150,7 +244,7 @@ Tk_ItemType tkPolygonType = { * Results: * A standard Tcl return value. If an error occurred in * creating the item, then an error message is left in - * interp->result; in this case itemPtr is + * the interp's result; in this case itemPtr is * left uninitialized, so it can be safely freed by the * caller. * @@ -167,34 +261,32 @@ CreatePolygon(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing polygon. */ + Tcl_Obj *CONST argv[]; /* Arguments describing polygon. */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; int i; - if (argc < 6) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", - itemPtr->typePtr->name, - " x1 y1 x2 y2 x3 y3 ?x4 y4 ...? ?options?\"", (char *) NULL); - return TCL_ERROR; - } - /* * Carry out initialization that is needed in order to clean * up after errors during the the remainder of this procedure. */ + Tk_CreateOutline(&(polyPtr->outline)); polyPtr->numPoints = 0; polyPtr->pointsAllocated = 0; polyPtr->coordPtr = NULL; - polyPtr->width = 1; - polyPtr->outlineColor = NULL; - polyPtr->outlineGC = None; + polyPtr->joinStyle = JoinRound; + polyPtr->tsoffset.flags = 0; + polyPtr->tsoffset.xoffset = 0; + polyPtr->tsoffset.yoffset = 0; polyPtr->fillColor = NULL; + polyPtr->activeFillColor = NULL; + polyPtr->disabledFillColor = NULL; polyPtr->fillStipple = None; + polyPtr->activeFillStipple = None; + polyPtr->disabledFillStipple = None; polyPtr->fillGC = None; - polyPtr->smooth = 0; + polyPtr->smooth = (Tk_SmoothMethod *) NULL; polyPtr->splineSteps = 12; polyPtr->autoClosed = 0; @@ -204,13 +296,14 @@ CreatePolygon(interp, canvas, itemPtr, argc, argv) * start with a digit or a minus sign followed by a digit. */ - for (i = 4; i < (argc-1); i+=2) { - if ((!isdigit(UCHAR(argv[i][0]))) && - ((argv[i][0] != '-') || (!isdigit(UCHAR(argv[i][1]))))) { + for (i = 0; i < argc; i++) { + char *arg = Tcl_GetStringFromObj((Tcl_Obj *) argv[i], NULL); + if ((arg[0] == '-') && (arg[1] >= 'a') + && (arg[1] <= 'z')) { break; } } - if (PolygonCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) { + if (i && PolygonCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) { goto error; } @@ -234,7 +327,7 @@ CreatePolygon(interp, canvas, itemPtr, argc, argv) * on what it does. * * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. * * Side effects: * The coordinates for the given item may be changed. @@ -250,11 +343,10 @@ PolygonCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; - char buffer[TCL_DOUBLE_SPACE]; int i, numPoints; if (argc == 0) { @@ -262,16 +354,21 @@ PolygonCoords(interp, canvas, itemPtr, argc, argv) * Print the coords used to create the polygon. If we auto * closed the polygon then we don't report the last point. */ + Tcl_Obj *subobj, *obj = Tcl_NewObj(); for (i = 0; i < 2*(polyPtr->numPoints - polyPtr->autoClosed); i++) { - Tcl_PrintDouble(interp, polyPtr->coordPtr[i], buffer); - Tcl_AppendElement(interp, buffer); + subobj = Tcl_NewDoubleObj(polyPtr->coordPtr[i]); + Tcl_ListObjAppendElement(interp, obj, subobj); } - } else if (argc < 6) { - Tcl_AppendResult(interp, - "too few coordinates for polygon: must have at least 6", - (char *) NULL); - return TCL_ERROR; - } else if (argc & 1) { + Tcl_SetObjResult(interp, obj); + return TCL_OK; + } + if (argc == 1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } + } + if (argc & 1) { Tcl_AppendResult(interp, "odd number of coordinates specified for polygon", (char *) NULL); @@ -284,8 +381,8 @@ PolygonCoords(interp, canvas, itemPtr, argc, argv) } /* - * One extra point gets allocated here, just in case we have - * to add another point to close the polygon. + * One extra point gets allocated here, because we always + * add another point to close the polygon. */ polyPtr->coordPtr = (double *) ckalloc((unsigned) @@ -293,20 +390,20 @@ PolygonCoords(interp, canvas, itemPtr, argc, argv) polyPtr->pointsAllocated = numPoints+1; } for (i = argc-1; i >= 0; i--) { - if (Tk_CanvasGetCoord(interp, canvas, argv[i], + if (Tk_CanvasGetCoordFromObj(interp, canvas, argv[i], &polyPtr->coordPtr[i]) != TCL_OK) { return TCL_ERROR; } } polyPtr->numPoints = numPoints; polyPtr->autoClosed = 0; - + /* * Close the polygon if it isn't already closed. */ - if ((polyPtr->coordPtr[argc-2] != polyPtr->coordPtr[0]) - || (polyPtr->coordPtr[argc-1] != polyPtr->coordPtr[1])) { + if (argc>2 && ((polyPtr->coordPtr[argc-2] != polyPtr->coordPtr[0]) + || (polyPtr->coordPtr[argc-1] != polyPtr->coordPtr[1]))) { polyPtr->autoClosed = 1; polyPtr->numPoints++; polyPtr->coordPtr[argc] = polyPtr->coordPtr[0]; @@ -327,7 +424,7 @@ PolygonCoords(interp, canvas, itemPtr, argc, argv) * * Results: * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. + * an error message is left in the interp's result. * * Side effects: * Configuration information, such as colors and stipple @@ -342,7 +439,7 @@ ConfigurePolygon(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Polygon item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; @@ -350,10 +447,13 @@ ConfigurePolygon(interp, canvas, itemPtr, argc, argv, flags) GC newGC; unsigned long mask; Tk_Window tkwin; + XColor *color; + Pixmap stipple; + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) polyPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) polyPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -362,37 +462,70 @@ ConfigurePolygon(interp, canvas, itemPtr, argc, argv, flags) * graphics contexts. */ - if (polyPtr->width < 1) { - polyPtr->width = 1; - } - if (polyPtr->outlineColor == NULL) { - newGC = None; + state = itemPtr->state; + + if (polyPtr->outline.activeWidth > polyPtr->outline.width || + polyPtr->outline.activeDash.number != 0 || + polyPtr->outline.activeColor != NULL || + polyPtr->outline.activeStipple != None || + polyPtr->activeFillColor != NULL || + polyPtr->activeFillStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; } else { - gcValues.foreground = polyPtr->outlineColor->pixel; - gcValues.line_width = polyPtr->width; + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (state==TK_STATE_HIDDEN) { + ComputePolygonBbox(canvas, polyPtr); + return TCL_OK; + } + + mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, &(polyPtr->outline)); + if (mask) { gcValues.cap_style = CapRound; - gcValues.join_style = JoinRound; - mask = GCForeground|GCLineWidth|GCCapStyle|GCJoinStyle; - newGC = Tk_GetGCColor(tkwin, mask, &gcValues, polyPtr->outlineColor, - NULL); + gcValues.join_style = polyPtr->joinStyle; + mask |= GCCapStyle|GCJoinStyle; + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = None; + } + if (polyPtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), polyPtr->outline.gc); } - if (polyPtr->outlineGC != None) { - Tk_FreeGC(Tk_Display(tkwin), polyPtr->outlineGC); + polyPtr->outline.gc = newGC; + + color = polyPtr->fillColor; + stipple = polyPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->activeFillColor!=NULL) { + color = polyPtr->activeFillColor; + } + if (polyPtr->activeFillStipple!=None) { + stipple = polyPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->disabledFillColor!=NULL) { + color = polyPtr->disabledFillColor; + } + if (polyPtr->disabledFillStipple!=None) { + stipple = polyPtr->disabledFillStipple; + } } - polyPtr->outlineGC = newGC; - if (polyPtr->fillColor == NULL) { + if (color == NULL) { newGC = None; } else { - gcValues.foreground = polyPtr->fillColor->pixel; + gcValues.foreground = color->pixel; mask = GCForeground; - if (polyPtr->fillStipple != None) { - gcValues.stipple = polyPtr->fillStipple; + if (stipple != None) { + gcValues.stipple = stipple; gcValues.fill_style = FillStippled; mask |= GCStipple|GCFillStyle; } - newGC = Tk_GetGCColor(tkwin, mask, &gcValues, polyPtr->fillColor, - NULL); + newGC = Tk_GetGC(tkwin, mask, &gcValues); } if (polyPtr->fillGC != None) { Tk_FreeGC(Tk_Display(tkwin), polyPtr->fillGC); @@ -439,20 +572,27 @@ DeletePolygon(canvas, itemPtr, display) { PolygonItem *polyPtr = (PolygonItem *) itemPtr; + Tk_DeleteOutline(display,&(polyPtr->outline)); if (polyPtr->coordPtr != NULL) { ckfree((char *) polyPtr->coordPtr); } if (polyPtr->fillColor != NULL) { Tk_FreeColor(polyPtr->fillColor); } + if (polyPtr->activeFillColor != NULL) { + Tk_FreeColor(polyPtr->activeFillColor); + } + if (polyPtr->disabledFillColor != NULL) { + Tk_FreeColor(polyPtr->disabledFillColor); + } if (polyPtr->fillStipple != None) { Tk_FreeBitmap(display, polyPtr->fillStipple); } - if (polyPtr->outlineColor != NULL) { - Tk_FreeColor(polyPtr->outlineColor); + if (polyPtr->activeFillStipple != None) { + Tk_FreeBitmap(display, polyPtr->activeFillStipple); } - if (polyPtr->outlineGC != None) { - Tk_FreeGC(display, polyPtr->outlineGC); + if (polyPtr->disabledFillStipple != None) { + Tk_FreeBitmap(display, polyPtr->disabledFillStipple); } if (polyPtr->fillGC != None) { Tk_FreeGC(display, polyPtr->fillGC); @@ -485,27 +625,159 @@ ComputePolygonBbox(canvas, polyPtr) { double *coordPtr; int i; + double width; + Tk_State state = polyPtr->header.state; + Tk_TSOffset *tsoffset; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = polyPtr->outline.width; + if (polyPtr->coordPtr == NULL || (polyPtr->numPoints < 1) || (state==TK_STATE_HIDDEN)) { + polyPtr->header.x1 = polyPtr->header.x2 = + polyPtr->header.y1 = polyPtr->header.y2 = -1; + return; + } + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)polyPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + } coordPtr = polyPtr->coordPtr; polyPtr->header.x1 = polyPtr->header.x2 = (int) *coordPtr; polyPtr->header.y1 = polyPtr->header.y2 = (int) coordPtr[1]; - for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints; + /* + * Compute the bounding box of all the points in the polygon, + * then expand in all directions by the outline's width to take + * care of butting or rounded corners and projecting or + * rounded caps. This expansion is an overestimate (worst-case + * is square root of two over two) but it's simple. Don't do + * anything special for curves. This causes an additional + * overestimate in the bounding box, but is faster. + */ + + for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints-1; i++, coordPtr += 2) { TkIncludePoint((Tk_Item *) polyPtr, coordPtr); } + tsoffset = &polyPtr->tsoffset; + if (tsoffset->flags & TK_OFFSET_INDEX) { + int index = tsoffset->flags & ~TK_OFFSET_INDEX; + if (tsoffset->flags == INT_MAX) { + index = (polyPtr->numPoints - polyPtr->autoClosed) * 2; + if (index < 0) { + index = 0; + } + } + index %= (polyPtr->numPoints - polyPtr->autoClosed) * 2; + if (index <0) { + index += (polyPtr->numPoints - polyPtr->autoClosed) * 2; + } + tsoffset->xoffset = (int) (polyPtr->coordPtr[index] + 0.5); + tsoffset->yoffset = (int) (polyPtr->coordPtr[index+1] + 0.5); + } else { + if (tsoffset->flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = polyPtr->header.x1; + } else if (tsoffset->flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (polyPtr->header.x1 + polyPtr->header.x2)/2; + } else if (tsoffset->flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = polyPtr->header.x2; + } + if (tsoffset->flags & TK_OFFSET_TOP) { + tsoffset->yoffset = polyPtr->header.y1; + } else if (tsoffset->flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (polyPtr->header.y1 + polyPtr->header.y2)/2; + } else if (tsoffset->flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = polyPtr->header.y2; + } + } + + if (polyPtr->outline.gc != None) { + tsoffset = &polyPtr->outline.tsoffset; + if (tsoffset) { + if (tsoffset->flags & TK_OFFSET_INDEX) { + int index = tsoffset->flags & ~TK_OFFSET_INDEX; + if (tsoffset->flags == INT_MAX) { + index = (polyPtr->numPoints - 1) * 2; + } + index %= (polyPtr->numPoints - 1) * 2; + if (index <0) { + index += (polyPtr->numPoints - 1) * 2; + } + tsoffset->xoffset = (int) (polyPtr->coordPtr[index] + 0.5); + tsoffset->yoffset = (int) (polyPtr->coordPtr[index+1] + 0.5); + } else { + if (tsoffset->flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = polyPtr->header.x1; + } else if (tsoffset->flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (polyPtr->header.x1 + polyPtr->header.x2)/2; + } else if (tsoffset->flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = polyPtr->header.x2; + } + if (tsoffset->flags & TK_OFFSET_TOP) { + tsoffset->yoffset = polyPtr->header.y1; + } else if (tsoffset->flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (polyPtr->header.y1 + polyPtr->header.y2)/2; + } else if (tsoffset->flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = polyPtr->header.y2; + } + } + } + + i = (int) ((width+1.5)/2.0); + polyPtr->header.x1 -= i; + polyPtr->header.x2 += i; + polyPtr->header.y1 -= i; + polyPtr->header.y2 += i; + + /* + * For mitered lines, make a second pass through all the points. + * Compute the locations of the two miter vertex points and add + * those into the bounding box. + */ + + if (polyPtr->joinStyle == JoinMiter) { + double miter[4]; + int j; + coordPtr = polyPtr->coordPtr; + if (polyPtr->numPoints>3) { + if (TkGetMiterPoints(coordPtr+2*(polyPtr->numPoints-2), + coordPtr, coordPtr+2, width, + miter, miter+2)) { + for (j = 0; j < 4; j += 2) { + TkIncludePoint((Tk_Item *) polyPtr, miter+j); + } + } + } + for (i = polyPtr->numPoints ; i >= 3; + i--, coordPtr += 2) { + + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + width, miter, miter+2)) { + for (j = 0; j < 4; j += 2) { + TkIncludePoint((Tk_Item *) polyPtr, miter+j); + } + } + } + } + } + /* - * Expand bounding box in all directions to account for the outline, - * which can stick out beyond the polygon. Add one extra pixel of - * fudge, just in case X rounds differently than we do. + * Add one more pixel of fudge factor just to be safe (e.g. + * X may round differently than we do). */ - i = (polyPtr->width+1)/2 + 1; - polyPtr->header.x1 -= i; - polyPtr->header.x2 += i; - polyPtr->header.y1 -= i; - polyPtr->header.y2 += i; + polyPtr->header.x1 -= 1; + polyPtr->header.x2 += 1; + polyPtr->header.y1 -= 1; + polyPtr->header.y2 += 1; } /* @@ -569,7 +841,7 @@ TkFillPolygon(canvas, coordPtr, numPoints, display, drawable, gc, outlineGC) * allocated. */ - if (gc != None) { + if (gc != None && numPoints>3) { XFillPolygon(display, drawable, gc, pointPtr, numPoints, Complex, CoordModeOrigin); } @@ -611,24 +883,80 @@ DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height) * must be redisplayed (not used). */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; + Tk_State state = itemPtr->state; + Pixmap stipple = polyPtr->fillStipple; + double linewidth = polyPtr->outline.width; - if ((polyPtr->fillGC == None) && (polyPtr->outlineGC == None)) { + if (((polyPtr->fillGC == None) && (polyPtr->outline.gc == None)) || + (polyPtr->numPoints < 1) || + (polyPtr->numPoints < 3 && polyPtr->outline.gc == None)) { return; } + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>linewidth) { + linewidth = polyPtr->outline.activeWidth; + } + if (polyPtr->activeFillStipple != None) { + stipple = polyPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + linewidth = polyPtr->outline.disabledWidth; + } + if (polyPtr->disabledFillStipple != None) { + stipple = polyPtr->disabledFillStipple; + } + } /* * If we're stippling then modify the stipple offset in the GC. Be * sure to reset the offset when done, since the GC is supposed to be * read-only. */ - if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) { - Tk_CanvasSetStippleOrigin(canvas, polyPtr->fillGC); + if ((stipple != None) && (polyPtr->fillGC != None)) { + Tk_TSOffset *tsoffset = &polyPtr->tsoffset; + int w=0; int h=0; + int flags = tsoffset->flags; + if (!(flags & TK_OFFSET_INDEX) && (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) { + Tk_SizeOfBitmap(display, stipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset->xoffset -= w; + tsoffset->yoffset -= h; + Tk_CanvasSetOffset(canvas, polyPtr->fillGC, tsoffset); + tsoffset->xoffset += w; + tsoffset->yoffset += h; } + Tk_ChangeOutlineGC(canvas, itemPtr, &(polyPtr->outline)); - if (!polyPtr->smooth) { + if(polyPtr->numPoints < 3) { + short x,y; + int intLineWidth = (int) (linewidth + 0.5); + if (intLineWidth < 1) { + intLineWidth = 1; + } + Tk_CanvasDrawableCoords(canvas, polyPtr->coordPtr[0], + polyPtr->coordPtr[1], &x,&y); + XFillArc(display, drawable, polyPtr->outline.gc, + x - intLineWidth/2, y - intLineWidth/2, + (unsigned int)intLineWidth+1, (unsigned int)intLineWidth+1, + 0, 64*360); + } else if (!polyPtr->smooth || polyPtr->numPoints < 4) { TkFillPolygon(canvas, polyPtr->coordPtr, polyPtr->numPoints, - display, drawable, polyPtr->fillGC, polyPtr->outlineGC); + display, drawable, polyPtr->fillGC, polyPtr->outline.gc); } else { int numPoints; XPoint staticPoints[MAX_STATIC_POINTS]; @@ -639,29 +967,32 @@ DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height) * spline points rather than the original points. */ - numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps; + numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL, + polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, + (double *) NULL); if (numPoints <= MAX_STATIC_POINTS) { pointPtr = staticPoints; } else { pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint))); } - numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr, + numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, polyPtr->numPoints, polyPtr->splineSteps, pointPtr, (double *) NULL); if (polyPtr->fillGC != None) { XFillPolygon(display, drawable, polyPtr->fillGC, pointPtr, numPoints, Complex, CoordModeOrigin); } - if (polyPtr->outlineGC != None) { - XDrawLines(display, drawable, polyPtr->outlineGC, pointPtr, + if (polyPtr->outline.gc != None) { + XDrawLines(display, drawable, polyPtr->outline.gc, pointPtr, numPoints, CoordModeOrigin); } if (pointPtr != staticPoints) { ckfree((char *) pointPtr); } } - if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) { + Tk_ResetOutlineGC(canvas, itemPtr, &(polyPtr->outline)); + if ((stipple != None) && (polyPtr->fillGC != None)) { XSetTSOrigin(display, polyPtr->fillGC, 0, 0); } } @@ -669,6 +1000,203 @@ DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height) /* *-------------------------------------------------------------- * + * PolygonInsert -- + * + * Insert coords into a polugon item at a given index. + * + * Results: + * None. + * + * Side effects: + * The coords in the given item is modified. + * + *-------------------------------------------------------------- + */ + +static void +PolygonInsert(canvas, itemPtr, beforeThis, obj) + Tk_Canvas canvas; /* Canvas containing text item. */ + Tk_Item *itemPtr; /* Line item to be modified. */ + int beforeThis; /* Index before which new coordinates + * are to be inserted. */ + Tcl_Obj *obj; /* New coordinates to be inserted. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + int length, argc, i; + Tcl_Obj **objv; + double *new; + Tk_State state = itemPtr->state; + + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + if (!obj || (Tcl_ListObjGetElements((Tcl_Interp *) NULL, obj, &argc, &objv) != TCL_OK) + || !argc || argc&1) { + return; + } + length = 2*(polyPtr->numPoints - polyPtr->autoClosed); + while(beforeThis>length) beforeThis-=length; + while(beforeThis<0) beforeThis+=length; + new = (double *) ckalloc((unsigned)(sizeof(double) * (length + 2 + argc))); + for (i=0; i<beforeThis; i++) { + new[i] = polyPtr->coordPtr[i]; + } + for (i=0; i<argc; i++) { + if (Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,objv[i], + new+(i+beforeThis))!=TCL_OK) { + ckfree((char *) new); + return; + } + } + + for(i=beforeThis; i<length; i++) { + new[i+argc] = polyPtr->coordPtr[i]; + } + if(polyPtr->coordPtr) ckfree((char *) polyPtr->coordPtr); + length+=argc; + polyPtr->coordPtr = new; + polyPtr->numPoints = (length/2) + polyPtr->autoClosed; + + /* + * Close the polygon if it isn't already closed, or remove autoclosing + * if the user's coordinates are now closed. + */ + + if (polyPtr->autoClosed) { + if ((new[length-2] == new[0]) && (new[length-1] == new[1])) { + polyPtr->autoClosed = 0; + polyPtr->numPoints--; + } + } + else { + if ((new[length-2] != new[0]) || (new[length-1] != new[1])) { + polyPtr->autoClosed = 1; + polyPtr->numPoints++; + } + } + + new[length] = new[0]; + new[length+1] = new[1]; + if (((length-argc)>3) && (state != TK_STATE_HIDDEN)) { + /* + * This is some optimizing code that will result that only the part + * of the polygon that changed (and the objects that are overlapping + * with that part) need to be redrawn. A special flag is set that + * instructs the general canvas code not to redraw the whole + * object. If this flag is not set, the canvas will do the redrawing, + * otherwise I have to do it here. + */ + double width; + int j; + itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW; + + /* + * The header elements that normally are used for the + * bounding box, are now used to calculate the bounding + * box for only the part that has to be redrawn. That + * doesn't matter, because afterwards the bounding + * box has to be re-calculated anyway. + */ + + itemPtr->x1 = itemPtr->x2 = (int) polyPtr->coordPtr[beforeThis]; + itemPtr->y1 = itemPtr->y2 = (int) polyPtr->coordPtr[beforeThis+1]; + beforeThis-=2; argc+=4; + if(polyPtr->smooth) { + beforeThis-=2; argc+=4; + } /* be carefull; beforeThis could now be negative */ + for(i=beforeThis; i<beforeThis+argc; i+=2) { + j=i; + if(j<0) j+=length; + if(j>=length) j-=length; + TkIncludePoint(itemPtr, polyPtr->coordPtr+j); + } + width = polyPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + } + itemPtr->x1 -= (int) width; itemPtr->y1 -= (int) width; + itemPtr->x2 += (int) width; itemPtr->y2 += (int) width; + Tk_CanvasEventuallyRedraw(canvas, + itemPtr->x1, itemPtr->y1, + itemPtr->x2, itemPtr->y2); + } + + ComputePolygonBbox(canvas, polyPtr); +} + +/* + *-------------------------------------------------------------- + * + * PolygonDeleteCoords -- + * + * Delete one or more coordinates from a polygon item. + * + * Results: + * None. + * + * Side effects: + * Characters between "first" and "last", inclusive, get + * deleted from itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +PolygonDeleteCoords(canvas, itemPtr, first, last) + Tk_Canvas canvas; /* Canvas containing itemPtr. */ + Tk_Item *itemPtr; /* Item in which to delete characters. */ + int first; /* Index of first character to delete. */ + int last; /* Index of last character to delete. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + int count, i; + int length = 2*(polyPtr->numPoints - polyPtr->autoClosed); + + while(first>=length) first-=length; + while(first<0) first+=length; + while(last>=length) last-=length; + while(last<0) last+=length; + + first &= -2; + last &= -2; + + count = last + 2 - first; + if(count<=0) count +=length; + + if(count >= length) { + polyPtr->numPoints = 0; + if(polyPtr->coordPtr != NULL) { + ckfree((char *) polyPtr->coordPtr); + } + ComputePolygonBbox(canvas, polyPtr); + return; + } + + if(last>=first) { + for(i=last+2; i<length; i++) { + polyPtr->coordPtr[i-count] = polyPtr->coordPtr[i]; + } + } else { + for(i=last; i<=first; i++) { + polyPtr->coordPtr[i-last] = polyPtr->coordPtr[i]; + } + } + polyPtr->coordPtr[length-count] = polyPtr->coordPtr[0]; + polyPtr->coordPtr[length-count+1] = polyPtr->coordPtr[1]; + polyPtr->numPoints -= count/2; + ComputePolygonBbox(canvas, polyPtr); +} + +/* + *-------------------------------------------------------------- + * * PolygonToPoint -- * * Computes the distance from a given point to a given @@ -694,41 +1222,169 @@ PolygonToPoint(canvas, itemPtr, pointPtr) double *pointPtr; /* Pointer to x and y coordinates. */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; - double *coordPtr, distance; + double *coordPtr, *polyPoints; double staticSpace[2*MAX_STATIC_POINTS]; - int numPoints; + double poly[10]; + double radius; + double bestDist, dist; + int numPoints, count; + int changedMiterToBevel; /* Non-zero means that a mitered corner + * had to be treated as beveled after all + * because the angle was < 11 degrees. */ + double width; + Tk_State state = itemPtr->state; + + bestDist = 1.0e36; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = polyPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + } + radius = width/2.0; - if (!polyPtr->smooth) { - distance = TkPolygonToPoint(polyPtr->coordPtr, polyPtr->numPoints, - pointPtr); - } else { - /* - * Smoothed polygon. Generate a new set of points and use them - * for comparison. - */ - - numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps; + /* + * Handle smoothed polygons by generating an expanded set of points + * against which to do the check. + */ + + if ((polyPtr->smooth) && (polyPtr->numPoints>2)) { + numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL, + polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, + (double *) NULL); if (numPoints <= MAX_STATIC_POINTS) { - coordPtr = staticSpace; + polyPoints = staticSpace; } else { - coordPtr = (double *) ckalloc((unsigned) + polyPoints = (double *) ckalloc((unsigned) (2*numPoints*sizeof(double))); } - numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr, + numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, - coordPtr); - distance = TkPolygonToPoint(coordPtr, numPoints, pointPtr); - if (coordPtr != staticSpace) { - ckfree((char *) coordPtr); + polyPoints); + } else { + numPoints = polyPtr->numPoints; + polyPoints = polyPtr->coordPtr; + } + + bestDist = TkPolygonToPoint(polyPoints, numPoints, pointPtr); + if (bestDist<=0.0) { + goto donepoint; + } + if ((polyPtr->outline.gc != None) && (polyPtr->joinStyle == JoinRound)) { + dist = bestDist - radius; + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else { + bestDist = dist; } } - if (polyPtr->outlineColor != NULL) { - distance -= polyPtr->width/2.0; - if (distance < 0) { - distance = 0; + + if ((polyPtr->outline.gc == None) || (width <= 1)) goto donepoint; + + /* + * The overall idea is to iterate through all of the edges of + * the line, computing a polygon for each edge and testing the + * point against that polygon. In addition, there are additional + * tests to deal with rounded joints and caps. + */ + + changedMiterToBevel = 0; + for (count = numPoints, coordPtr = polyPoints; count >= 2; + count--, coordPtr += 2) { + + /* + * If rounding is done around the first point then compute + * the distance between the point and the point. + */ + + if (polyPtr->joinStyle == JoinRound) { + dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) + - radius; + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else if (dist < bestDist) { + bestDist = dist; + } } + + /* + * Compute the polygonal shape corresponding to this edge, + * consisting of two points for the first point of the edge + * and two points for the last point of the edge. + */ + + if (count == numPoints) { + TkGetButtPoints(coordPtr+2, coordPtr, (double) width, + 0, poly, poly+2); + } else if ((polyPtr->joinStyle == JoinMiter) && !changedMiterToBevel) { + poly[0] = poly[6]; + poly[1] = poly[7]; + poly[2] = poly[4]; + poly[3] = poly[5]; + } else { + TkGetButtPoints(coordPtr+2, coordPtr, (double) width, 0, + poly, poly+2); + + /* + * If this line uses beveled joints, then check the distance + * to a polygon comprising the last two points of the previous + * polygon and the first two from this polygon; this checks + * the wedges that fill the mitered joint. + */ + + if ((polyPtr->joinStyle == JoinBevel) || changedMiterToBevel) { + poly[8] = poly[0]; + poly[9] = poly[1]; + dist = TkPolygonToPoint(poly, 5, pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else if (dist < bestDist) { + bestDist = dist; + } + changedMiterToBevel = 0; + } + } + if (count == 2) { + TkGetButtPoints(coordPtr, coordPtr+2, (double) width, + 0, poly+4, poly+6); + } else if (polyPtr->joinStyle == JoinMiter) { + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + (double) width, poly+4, poly+6) == 0) { + changedMiterToBevel = 1; + TkGetButtPoints(coordPtr, coordPtr+2, (double) width, + 0, poly+4, poly+6); + } + } else { + TkGetButtPoints(coordPtr, coordPtr+2, (double) width, 0, + poly+4, poly+6); + } + poly[8] = poly[0]; + poly[9] = poly[1]; + dist = TkPolygonToPoint(poly, 5, pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else if (dist < bestDist) { + bestDist = dist; + } + } + + donepoint: + if ((polyPoints != staticSpace) && polyPoints != polyPtr->coordPtr) { + ckfree((char *) polyPoints); } - return distance; + return bestDist; } /* @@ -761,75 +1417,179 @@ PolygonToArea(canvas, itemPtr, rectPtr) * area. */ { PolygonItem *polyPtr = (PolygonItem *) itemPtr; - double *coordPtr, rect2[4], halfWidth; + double *coordPtr; double staticSpace[2*MAX_STATIC_POINTS]; - int numPoints, result; + double *polyPoints, poly[10]; + double radius; + int numPoints, count; + int changedMiterToBevel; /* Non-zero means that a mitered corner + * had to be treated as beveled after all + * because the angle was < 11 degrees. */ + int inside; /* Tentative guess about what to return, + * based on all points seen so far: one + * means everything seen so far was + * inside the area; -1 means everything + * was outside the area. 0 means overlap + * has been found. */ + double width; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = polyPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + } + + radius = width/2.0; + inside = -1; + + if ((state==TK_STATE_HIDDEN) || polyPtr->numPoints<2) { + return -1; + } else if (polyPtr->numPoints <3) { + double oval[4]; + oval[0] = polyPtr->coordPtr[0]-radius; + oval[1] = polyPtr->coordPtr[1]-radius; + oval[2] = polyPtr->coordPtr[0]+radius; + oval[3] = polyPtr->coordPtr[1]+radius; + return TkOvalToArea(oval, rectPtr); + } /* * Handle smoothed polygons by generating an expanded set of points * against which to do the check. */ if (polyPtr->smooth) { - numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps; + numPoints = polyPtr->smooth->coordProc(canvas, (double *) NULL, + polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, + (double *) NULL); if (numPoints <= MAX_STATIC_POINTS) { - coordPtr = staticSpace; + polyPoints = staticSpace; } else { - coordPtr = (double *) ckalloc((unsigned) + polyPoints = (double *) ckalloc((unsigned) (2*numPoints*sizeof(double))); } - numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr, + numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL, - coordPtr); + polyPoints); } else { numPoints = polyPtr->numPoints; - coordPtr = polyPtr->coordPtr; + polyPoints = polyPtr->coordPtr; } - if (polyPtr->width <= 1) { - /* - * The outline of the polygon doesn't stick out, so we can - * do a simple check. - */ - - result = TkPolygonToArea(coordPtr, numPoints, rectPtr); + if (polyPtr->fillGC != None) { + inside = TkPolygonToArea(polyPoints, numPoints, rectPtr); + if (inside==0) goto donearea; } else { + if ((polyPoints[0] >= rectPtr[0]) + && (polyPoints[0] <= rectPtr[2]) + && (polyPoints[1] >= rectPtr[1]) + && (polyPoints[1] <= rectPtr[3])) { + inside = 1; + } + } + + if (polyPtr->outline.gc == None) goto donearea ; + + + /* + * Iterate through all of the edges of the line, computing a polygon + * for each edge and testing the area against that polygon. In + * addition, there are additional tests to deal with rounded joints + * and caps. + */ + + changedMiterToBevel = 0; + for (count = numPoints, coordPtr = polyPoints; count >= 2; + count--, coordPtr += 2) { + /* - * The polygon has a wide outline, so the check is more complicated. - * First, check the line segments to see if they overlap the area. + * If rounding is done around the first point of the edge + * then test a circular region around the point with the + * area. */ - result = TkThickPolyLineToArea(coordPtr, numPoints, - (double) polyPtr->width, CapRound, JoinRound, rectPtr); - if (result >= 0) { - goto done; + if (polyPtr->joinStyle == JoinRound) { + poly[0] = coordPtr[0] - radius; + poly[1] = coordPtr[1] - radius; + poly[2] = coordPtr[0] + radius; + poly[3] = coordPtr[1] + radius; + if (TkOvalToArea(poly, rectPtr) != inside) { + inside = 0; + goto donearea; + } } /* - * There is no overlap between the polygon's outline and the - * rectangle. This means either the rectangle is entirely outside - * the polygon or entirely inside. To tell the difference, - * see whether the polygon (with 0 outline width) overlaps the - * rectangle bloated by half the outline width. + * Compute the polygonal shape corresponding to this edge, + * consisting of two points for the first point of the edge + * and two points for the last point of the edge. */ - halfWidth = polyPtr->width/2.0; - rect2[0] = rectPtr[0] - halfWidth; - rect2[1] = rectPtr[1] - halfWidth; - rect2[2] = rectPtr[2] + halfWidth; - rect2[3] = rectPtr[3] + halfWidth; - if (TkPolygonToArea(coordPtr, numPoints, rect2) == -1) { - result = -1; + if (count == numPoints) { + TkGetButtPoints(coordPtr+2, coordPtr, width, + 0, poly, poly+2); + } else if ((polyPtr->joinStyle == JoinMiter) && !changedMiterToBevel) { + poly[0] = poly[6]; + poly[1] = poly[7]; + poly[2] = poly[4]; + poly[3] = poly[5]; + } else { + TkGetButtPoints(coordPtr+2, coordPtr, width, 0, + poly, poly+2); + + /* + * If the last joint was beveled, then also check a + * polygon comprising the last two points of the previous + * polygon and the first two from this polygon; this checks + * the wedges that fill the beveled joint. + */ + + if ((polyPtr->joinStyle == JoinBevel) || changedMiterToBevel) { + poly[8] = poly[0]; + poly[9] = poly[1]; + if (TkPolygonToArea(poly, 5, rectPtr) != inside) { + inside = 0; + goto donearea; + } + changedMiterToBevel = 0; + } + } + if (count == 2) { + TkGetButtPoints(coordPtr, coordPtr+2, width, + 0, poly+4, poly+6); + } else if (polyPtr->joinStyle == JoinMiter) { + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + width, poly+4, poly+6) == 0) { + changedMiterToBevel = 1; + TkGetButtPoints(coordPtr, coordPtr+2, width, + 0, poly+4, poly+6); + } } else { - result = 0; + TkGetButtPoints(coordPtr, coordPtr+2, width, 0, + poly+4, poly+6); + } + poly[8] = poly[0]; + poly[9] = poly[1]; + if (TkPolygonToArea(poly, 5, rectPtr) != inside) { + inside = 0; + goto donearea; } } - done: - if ((coordPtr != staticSpace) && (coordPtr != polyPtr->coordPtr)) { - ckfree((char *) coordPtr); + donearea: + if ((polyPoints != staticSpace) && (polyPoints != polyPtr->coordPtr)) { + ckfree((char *) polyPoints); } - return result; + return inside; } /* @@ -875,6 +1635,101 @@ ScalePolygon(canvas, itemPtr, originX, originY, scaleX, scaleY) /* *-------------------------------------------------------------- * + * GetPolygonIndex -- + * + * Parse an index into a polygon item and return either its value + * or an error. + * + * Results: + * A standard Tcl result. If all went well, then *indexPtr is + * filled in with the index (into itemPtr) corresponding to + * string. Otherwise an error message is left in + * interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetPolygonIndex(interp, canvas, itemPtr, obj, indexPtr) + Tcl_Interp *interp; /* Used for error reporting. */ + Tk_Canvas canvas; /* Canvas containing item. */ + Tk_Item *itemPtr; /* Item for which the index is being + * specified. */ + Tcl_Obj *obj; /* Specification of a particular coord + * in itemPtr's line. */ + int *indexPtr; /* Where to store converted index. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + size_t length; + char *string = Tcl_GetStringFromObj(obj, (int *) &length); + + if (string[0] == 'e') { + if (strncmp(string, "end", length) == 0) { + *indexPtr = 2*(polyPtr->numPoints - polyPtr->autoClosed); + } else { + badIndex: + + /* + * Some of the paths here leave messages in interp->result, + * so we have to clear it out before storing our own message. + */ + + Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); + Tcl_AppendResult(interp, "bad index \"", string, "\"", + (char *) NULL); + return TCL_ERROR; + } + } else if (string[0] == '@') { + int i; + double x ,y, bestDist, dist, *coordPtr; + char *end, *p; + + p = string+1; + x = strtod(p, &end); + if ((end == p) || (*end != ',')) { + goto badIndex; + } + p = end+1; + y = strtod(p, &end); + if ((end == p) || (*end != 0)) { + goto badIndex; + } + bestDist = 1.0e36; + coordPtr = polyPtr->coordPtr; + *indexPtr = 0; + for(i=0; i<(polyPtr->numPoints-1); i++) { + dist = hypot(coordPtr[0] - x, coordPtr[1] - y); + if (dist<bestDist) { + bestDist = dist; + *indexPtr = 2*i; + } + coordPtr += 2; + } + } else { + int count = 2*(polyPtr->numPoints - polyPtr->autoClosed); + if (Tcl_GetIntFromObj(interp, obj, indexPtr) != TCL_OK) { + goto badIndex; + } + *indexPtr &= -2; /* if odd, make it even */ + if (count) { + if (*indexPtr > 0) { + *indexPtr = ((*indexPtr - 2) % count) + 2; + } else { + *indexPtr = -((-(*indexPtr)) % count); + } + } else { + *indexPtr = 0; + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * * TranslatePolygon -- * * This procedure is called to move a polygon by a given @@ -921,7 +1776,7 @@ TranslatePolygon(canvas, itemPtr, deltaX, deltaY) * Results: * The return value is a standard Tcl result. If an error * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used + * left in the interp's result, replacing whatever used * to be there. If no error occurs, then Postscript for the * item is appended to the result. * @@ -942,31 +1797,104 @@ PolygonToPostscript(interp, canvas, itemPtr, prepass) * collect font information; 0 means * final Postscript is being created. */ { - char string[100]; PolygonItem *polyPtr = (PolygonItem *) itemPtr; + char *style; + XColor *color; + XColor *fillColor; + Pixmap stipple; + Pixmap fillStipple; + Tk_State state = itemPtr->state; + double width; + + if (polyPtr->numPoints<2 || polyPtr->coordPtr==NULL) { + return TCL_OK; + } + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + width = polyPtr->outline.width; + color = polyPtr->outline.color; + stipple = polyPtr->fillStipple; + fillColor = polyPtr->fillColor; + fillStipple = polyPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + if (polyPtr->outline.activeColor!=NULL) { + color = polyPtr->outline.activeColor; + } + if (polyPtr->outline.activeStipple!=None) { + stipple = polyPtr->outline.activeStipple; + } + if (polyPtr->activeFillColor!=NULL) { + fillColor = polyPtr->activeFillColor; + } + if (polyPtr->activeFillStipple!=None) { + fillStipple = polyPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + if (polyPtr->outline.disabledColor!=NULL) { + color = polyPtr->outline.disabledColor; + } + if (polyPtr->outline.disabledStipple!=None) { + stipple = polyPtr->outline.disabledStipple; + } + if (polyPtr->disabledFillColor!=NULL) { + fillColor = polyPtr->disabledFillColor; + } + if (polyPtr->disabledFillStipple!=None) { + fillStipple = polyPtr->disabledFillStipple; + } + } + if (polyPtr->numPoints==2) { + char string[128]; + sprintf(string, "%.15g %.15g translate %.15g %.15g", + polyPtr->coordPtr[0], Tk_CanvasPsY(canvas, polyPtr->coordPtr[1]), + width/2.0, width/2.0); + Tcl_AppendResult(interp, "matrix currentmatrix\n",string, + " scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n", (char *) NULL); + if (Tk_CanvasPsColor(interp, canvas, color) + != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "clip ", (char *) NULL); + if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "fill\n", (char *) NULL); + } + return TCL_OK; + } /* * Fill the area of the polygon. */ - if (polyPtr->fillColor != NULL) { - if (!polyPtr->smooth) { + if (fillColor != NULL && polyPtr->numPoints>3) { + if (!polyPtr->smooth || !polyPtr->smooth->postscriptProc) { Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr, polyPtr->numPoints); } else { - TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr, - polyPtr->numPoints); + polyPtr->smooth->postscriptProc(interp, canvas, polyPtr->coordPtr, + polyPtr->numPoints, polyPtr->splineSteps); } - if (Tk_CanvasPsColor(interp, canvas, polyPtr->fillColor) != TCL_OK) { + if (Tk_CanvasPsColor(interp, canvas, fillColor) != TCL_OK) { return TCL_ERROR; } - if (polyPtr->fillStipple != None) { + if (fillStipple != None) { Tcl_AppendResult(interp, "eoclip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, polyPtr->fillStipple) + if (Tk_CanvasPsStipple(interp, canvas, fillStipple) != TCL_OK) { return TCL_ERROR; } - if (polyPtr->outlineColor != NULL) { + if (color != NULL) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } } else { @@ -978,23 +1906,31 @@ PolygonToPostscript(interp, canvas, itemPtr, prepass) * Now draw the outline, if there is one. */ - if (polyPtr->outlineColor != NULL) { - if (!polyPtr->smooth) { + if (color != NULL) { + + if (!polyPtr->smooth || !polyPtr->smooth->postscriptProc) { Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr, polyPtr->numPoints); } else { - TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr, - polyPtr->numPoints); + polyPtr->smooth->postscriptProc(interp, canvas, polyPtr->coordPtr, + polyPtr->numPoints, polyPtr->splineSteps); } - sprintf(string, "%d setlinewidth\n", polyPtr->width); - Tcl_AppendResult(interp, string, - "1 setlinecap\n1 setlinejoin\n", (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, polyPtr->outlineColor) - != TCL_OK) { + if (polyPtr->joinStyle == JoinRound) { + style = "1"; + } else if (polyPtr->joinStyle == JoinBevel) { + style = "2"; + } else { + style = "0"; + } + Tcl_AppendResult(interp, style," setlinejoin 1 setlinecap\n", + (char *) NULL); + if (Tk_CanvasPsOutline(canvas, itemPtr, + &(polyPtr->outline)) != TCL_OK) { return TCL_ERROR; } - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); } return TCL_OK; } + + diff --git a/tk/generic/tkCanvPs.c b/tk/generic/tkCanvPs.c index eb45f87b80b..66b1cc9d7df 100644 --- a/tk/generic/tkCanvPs.c +++ b/tk/generic/tkCanvPs.c @@ -6,7 +6,7 @@ * procedures used for generating Postscript. * * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -68,6 +68,8 @@ typedef struct TkPostscriptInfo { * the pre-pass that collects font information, * so the Postscript generated isn't * relevant. */ + int prolog; /* Non-zero means output should contain + the file prolog.ps in the header. */ } TkPostscriptInfo; /* @@ -99,6 +101,8 @@ static Tk_ConfigSpec configSpecs[] = { "", Tk_Offset(TkPostscriptInfo, pageXString), 0}, {TK_CONFIG_STRING, "-pagey", (char *) NULL, (char *) NULL, "", Tk_Offset(TkPostscriptInfo, pageYString), 0}, + {TK_CONFIG_BOOLEAN, "-prolog", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, prolog), 0}, {TK_CONFIG_BOOLEAN, "-rotate", (char *) NULL, (char *) NULL, "", Tk_Offset(TkPostscriptInfo, rotate), 0}, {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, @@ -115,6 +119,7 @@ static Tk_ConfigSpec configSpecs[] = { * The prolog data. Generated by str2c from prolog.ps * This was split in small chunks by str2c because * some C compiler have limitations on the size of static strings. + * (str2c is a small tcl script in tcl's tool directory (source release)) */ static CONST char * CONST prolog[]= { /* Start of part 1 (2000 characters) */ @@ -460,13 +465,15 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) * to know that argv[1] is * "postscript". */ { - TkPostscriptInfo psInfo, *oldInfoPtr; + TkPostscriptInfo psInfo; + Tk_PostscriptInfo oldInfoPtr; int result; Tk_Item *itemPtr; #define STRING_LENGTH 400 char string[STRING_LENGTH+1], *p; time_t now; size_t length; + Tk_Window tkwin = canvasPtr->tkwin; int deltaX = 0, deltaY = 0; /* Offset of lower-left corner of * area to be marked up, measured * in canvas units from the positioning @@ -486,8 +493,8 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) *---------------------------------------------------------------- */ - oldInfoPtr = canvasPtr->psInfoPtr; - canvasPtr->psInfoPtr = &psInfo; + oldInfoPtr = canvasPtr->psInfo; + canvasPtr->psInfo = (Tk_PostscriptInfo) &psInfo; psInfo.x = canvasPtr->xOrigin; psInfo.y = canvasPtr->yOrigin; psInfo.width = -1; @@ -509,8 +516,9 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) psInfo.channelName = NULL; psInfo.chan = NULL; psInfo.prepass = 0; + psInfo.prolog = 1; Tcl_InitHashTable(&psInfo.fontTable, TCL_STRING_KEYS); - result = Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin, + result = Tk_ConfigureWidget(interp, tkwin, configSpecs, argc-2, argv+2, (char *) &psInfo, TK_CONFIG_ARGV_ONLY); if (result != TCL_OK) { @@ -518,41 +526,41 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) } if (psInfo.width == -1) { - psInfo.width = Tk_Width(canvasPtr->tkwin); + psInfo.width = Tk_Width(tkwin); } if (psInfo.height == -1) { - psInfo.height = Tk_Height(canvasPtr->tkwin); + psInfo.height = Tk_Height(tkwin); } psInfo.x2 = psInfo.x + psInfo.width; psInfo.y2 = psInfo.y + psInfo.height; if (psInfo.pageXString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageXString, + if (GetPostscriptPoints(interp, psInfo.pageXString, &psInfo.pageX) != TCL_OK) { goto cleanup; } } if (psInfo.pageYString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageYString, + if (GetPostscriptPoints(interp, psInfo.pageYString, &psInfo.pageY) != TCL_OK) { goto cleanup; } } if (psInfo.pageWidthString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageWidthString, + if (GetPostscriptPoints(interp, psInfo.pageWidthString, &psInfo.scale) != TCL_OK) { goto cleanup; } psInfo.scale /= psInfo.width; } else if (psInfo.pageHeightString != NULL) { - if (GetPostscriptPoints(canvasPtr->interp, psInfo.pageHeightString, + if (GetPostscriptPoints(interp, psInfo.pageHeightString, &psInfo.scale) != TCL_OK) { goto cleanup; } psInfo.scale /= psInfo.height; } else { - psInfo.scale = (72.0/25.4)*WidthMMOfScreen(Tk_Screen(canvasPtr->tkwin)); - psInfo.scale /= WidthOfScreen(Tk_Screen(canvasPtr->tkwin)); + psInfo.scale = (72.0/25.4)*WidthMMOfScreen(Tk_Screen(tkwin)); + psInfo.scale /= WidthOfScreen(Tk_Screen(tkwin)); } switch (psInfo.pageAnchor) { case TK_ANCHOR_NW: @@ -600,7 +608,7 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) } else if (strncmp(psInfo.colorMode, "color", length) == 0) { psInfo.colorLevel = 2; } else { - Tcl_AppendResult(canvasPtr->interp, "bad color mode \"", + Tcl_AppendResult(interp, "bad color mode \"", psInfo.colorMode, "\": must be monochrome, ", "gray, or color", (char *) NULL); goto cleanup; @@ -614,7 +622,7 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) */ if (psInfo.channelName != NULL) { - Tcl_AppendResult(canvasPtr->interp, "can't specify both -file", + Tcl_AppendResult(interp, "can't specify both -file", " and -channel", (char *) NULL); result = TCL_ERROR; goto cleanup; @@ -625,18 +633,18 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) * the -file specification. */ - if (Tcl_IsSafe(canvasPtr->interp)) { - Tcl_AppendResult(canvasPtr->interp, "can't specify -file in a", + if (Tcl_IsSafe(interp)) { + Tcl_AppendResult(interp, "can't specify -file in a", " safe interpreter", (char *) NULL); result = TCL_ERROR; goto cleanup; } - p = Tcl_TranslateFileName(canvasPtr->interp, psInfo.fileName, &buffer); + p = Tcl_TranslateFileName(interp, psInfo.fileName, &buffer); if (p == NULL) { goto cleanup; } - psInfo.chan = Tcl_OpenFileChannel(canvasPtr->interp, p, "w", 0666); + psInfo.chan = Tcl_OpenFileChannel(interp, p, "w", 0666); Tcl_DStringFree(&buffer); if (psInfo.chan == NULL) { goto cleanup; @@ -651,14 +659,14 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) * is open for writing. */ - psInfo.chan = Tcl_GetChannel(canvasPtr->interp, psInfo.channelName, + psInfo.chan = Tcl_GetChannel(interp, psInfo.channelName, &mode); if (psInfo.chan == (Tcl_Channel) NULL) { result = TCL_ERROR; goto cleanup; } if ((mode & TCL_WRITABLE) == 0) { - Tcl_AppendResult(canvasPtr->interp, "channel \"", + Tcl_AppendResult(interp, "channel \"", psInfo.channelName, "\" wasn't opened for writing", (char *) NULL); result = TCL_ERROR; @@ -686,9 +694,9 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) if (itemPtr->typePtr->postscriptProc == NULL) { continue; } - result = (*itemPtr->typePtr->postscriptProc)(canvasPtr->interp, + result = (*itemPtr->typePtr->postscriptProc)(interp, (Tk_Canvas) canvasPtr, itemPtr, 1); - Tcl_ResetResult(canvasPtr->interp); + Tcl_ResetResult(interp); if (result != TCL_OK) { /* * An error just occurred. Just skip out of this loop. @@ -708,22 +716,23 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) *-------------------------------------------------------- */ - Tcl_AppendResult(canvasPtr->interp, "%!PS-Adobe-3.0 EPSF-3.0\n", + if (psInfo.prolog) { + Tcl_AppendResult(interp, "%!PS-Adobe-3.0 EPSF-3.0\n", "%%Creator: Tk Canvas Widget\n", (char *) NULL); -#if !(defined(__WIN32__) || defined(MAC_TCL)) +#ifdef HAVE_PW_GECOS if (!Tcl_IsSafe(interp)) { - struct passwd *pwPtr = getpwuid(getuid()); - Tcl_AppendResult(canvasPtr->interp, "%%For: ", + struct passwd *pwPtr = getpwuid(getuid()); /* INTL: Native. */ + Tcl_AppendResult(interp, "%%For: ", (pwPtr != NULL) ? pwPtr->pw_gecos : "Unknown", "\n", (char *) NULL); endpwent(); } -#endif /* __WIN32__ || MAC_TCL */ - Tcl_AppendResult(canvasPtr->interp, "%%Title: Window ", - Tk_PathName(canvasPtr->tkwin), "\n", (char *) NULL); +#endif /* HAVE_PW_GECOS */ + Tcl_AppendResult(interp, "%%Title: Window ", + Tk_PathName(tkwin), "\n", (char *) NULL); time(&now); - Tcl_AppendResult(canvasPtr->interp, "%%CreationDate: ", - ctime(&now), (char *) NULL); + Tcl_AppendResult(interp, "%%CreationDate: ", + ctime(&now), (char *) NULL); /* INTL: Native. */ if (!psInfo.rotate) { sprintf(string, "%d %d %d %d", (int) (psInfo.pageX + psInfo.scale*deltaX), @@ -740,21 +749,21 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) (int) (psInfo.pageY + psInfo.scale*(deltaX + psInfo.width) + 1.0)); } - Tcl_AppendResult(canvasPtr->interp, "%%BoundingBox: ", string, + Tcl_AppendResult(interp, "%%BoundingBox: ", string, "\n", (char *) NULL); - Tcl_AppendResult(canvasPtr->interp, "%%Pages: 1\n", + Tcl_AppendResult(interp, "%%Pages: 1\n", "%%DocumentData: Clean7Bit\n", (char *) NULL); - Tcl_AppendResult(canvasPtr->interp, "%%Orientation: ", + Tcl_AppendResult(interp, "%%Orientation: ", psInfo.rotate ? "Landscape\n" : "Portrait\n", (char *) NULL); p = "%%DocumentNeededResources: font "; for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendResult(canvasPtr->interp, p, + Tcl_AppendResult(interp, p, Tcl_GetHashKey(&psInfo.fontTable, hPtr), "\n", (char *) NULL); p = "%%+ font "; } - Tcl_AppendResult(canvasPtr->interp, "%%EndComments\n\n", (char *) NULL); + Tcl_AppendResult(interp, "%%EndComments\n\n", (char *) NULL); /* * Insert the prolog @@ -764,7 +773,7 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) } if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, canvasPtr->interp->result, -1); + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); Tcl_ResetResult(canvasPtr->interp); } @@ -775,14 +784,14 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) */ sprintf(string, "/CL %d def\n", psInfo.colorLevel); - Tcl_AppendResult(canvasPtr->interp, "%%BeginSetup\n", string, + Tcl_AppendResult(interp, "%%BeginSetup\n", string, (char *) NULL); for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendResult(canvasPtr->interp, "%%IncludeResource: font ", + Tcl_AppendResult(interp, "%%IncludeResource: font ", Tcl_GetHashKey(&psInfo.fontTable, hPtr), "\n", (char *) NULL); } - Tcl_AppendResult(canvasPtr->interp, "%%EndSetup\n\n", (char *) NULL); + Tcl_AppendResult(interp, "%%EndSetup\n\n", (char *) NULL); /* *----------------------------------------------------------- @@ -792,26 +801,31 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) *----------------------------------------------------------- */ - Tcl_AppendResult(canvasPtr->interp, "%%Page: 1 1\n", "save\n", + Tcl_AppendResult(interp, "%%Page: 1 1\n", "save\n", (char *) NULL); sprintf(string, "%.1f %.1f translate\n", psInfo.pageX, psInfo.pageY); - Tcl_AppendResult(canvasPtr->interp, string, (char *) NULL); + Tcl_AppendResult(interp, string, (char *) NULL); if (psInfo.rotate) { - Tcl_AppendResult(canvasPtr->interp, "90 rotate\n", (char *) NULL); + Tcl_AppendResult(interp, "90 rotate\n", (char *) NULL); } sprintf(string, "%.4g %.4g scale\n", psInfo.scale, psInfo.scale); - Tcl_AppendResult(canvasPtr->interp, string, (char *) NULL); + Tcl_AppendResult(interp, string, (char *) NULL); sprintf(string, "%d %d translate\n", deltaX - psInfo.x, deltaY); - Tcl_AppendResult(canvasPtr->interp, string, (char *) NULL); + Tcl_AppendResult(interp, string, (char *) NULL); sprintf(string, "%d %.15g moveto %d %.15g lineto %d %.15g lineto %d %.15g", - psInfo.x, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y), - psInfo.x2, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y), - psInfo.x2, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y2), - psInfo.x, Tk_CanvasPsY((Tk_Canvas) canvasPtr, (double) psInfo.y2)); - Tcl_AppendResult(canvasPtr->interp, string, + psInfo.x, + Tk_PostscriptY((double) psInfo.y, (Tk_PostscriptInfo) &psInfo), + psInfo.x2, + Tk_PostscriptY((double) psInfo.y, (Tk_PostscriptInfo) &psInfo), + psInfo.x2, + Tk_PostscriptY((double) psInfo.y2, (Tk_PostscriptInfo) &psInfo), + psInfo.x, + Tk_PostscriptY((double) psInfo.y2, (Tk_PostscriptInfo) &psInfo)); + Tcl_AppendResult(interp, string, " lineto closepath clip newpath\n", (char *) NULL); + } if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, canvasPtr->interp->result, -1); + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); Tcl_ResetResult(canvasPtr->interp); } @@ -832,21 +846,24 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) if (itemPtr->typePtr->postscriptProc == NULL) { continue; } - Tcl_AppendResult(canvasPtr->interp, "gsave\n", (char *) NULL); - result = (*itemPtr->typePtr->postscriptProc)(canvasPtr->interp, + if (itemPtr->state == TK_STATE_HIDDEN) { + continue; + } + Tcl_AppendResult(interp, "gsave\n", (char *) NULL); + result = (*itemPtr->typePtr->postscriptProc)(interp, (Tk_Canvas) canvasPtr, itemPtr, 0); if (result != TCL_OK) { - char msg[100]; + char msg[64 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (generating Postscript for item %d)", itemPtr->id); - Tcl_AddErrorInfo(canvasPtr->interp, msg); + Tcl_AddErrorInfo(interp, msg); goto cleanup; } - Tcl_AppendResult(canvasPtr->interp, "grestore\n", (char *) NULL); + Tcl_AppendResult(interp, "grestore\n", (char *) NULL); if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, canvasPtr->interp->result, -1); - Tcl_ResetResult(canvasPtr->interp); + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); + Tcl_ResetResult(interp); } } @@ -857,10 +874,12 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) *--------------------------------------------------------------------- */ - Tcl_AppendResult(canvasPtr->interp, "restore showpage\n\n", + if (psInfo.prolog) { + Tcl_AppendResult(interp, "restore showpage\n\n", "%%Trailer\nend\n%%EOF\n", (char *) NULL); + } if (psInfo.chan != NULL) { - Tcl_Write(psInfo.chan, canvasPtr->interp->result, -1); + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); Tcl_ResetResult(canvasPtr->interp); } @@ -894,20 +913,20 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) ckfree(psInfo.fileName); } if ((psInfo.chan != NULL) && (psInfo.channelName == NULL)) { - Tcl_Close(canvasPtr->interp, psInfo.chan); + Tcl_Close(interp, psInfo.chan); } if (psInfo.channelName != NULL) { ckfree(psInfo.channelName); } Tcl_DeleteHashTable(&psInfo.fontTable); - canvasPtr->psInfoPtr = oldInfoPtr; + canvasPtr->psInfo = (Tk_PostscriptInfo) oldInfoPtr; return result; } /* *-------------------------------------------------------------- * - * Tk_CanvasPsColor -- + * Tk_PostscriptColor -- * * This procedure is called by individual canvas items when * they want to set a color value for output. Given information @@ -916,9 +935,9 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) * * Results: * Returns a standard Tcl return value. If an error occurs - * then an error message will be left in interp->result. + * then an error message will be left in the interp's result. * If no error occurs, then additional Postscript will be - * appended to interp->result. + * appended to the interp's result. * * Side effects: * None. @@ -927,14 +946,12 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) */ int -Tk_CanvasPsColor(interp, canvas, colorPtr) - Tcl_Interp *interp; /* Interpreter for returning Postscript - * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ +Tk_PostscriptColor(interp, psInfo, colorPtr) + Tcl_Interp *interp; + Tk_PostscriptInfo psInfo; /* Postscript info. */ XColor *colorPtr; /* Information about color. */ { - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; int tmp; double red, green, blue; char string[200]; @@ -988,7 +1005,7 @@ Tk_CanvasPsColor(interp, canvas, colorPtr) /* *-------------------------------------------------------------- * - * Tk_CanvasPsFont -- + * Tk_PostscriptFont -- * * This procedure is called by individual canvas items when * they want to output text. Given information about an X @@ -997,9 +1014,9 @@ Tk_CanvasPsColor(interp, canvas, colorPtr) * * Results: * Returns a standard Tcl return value. If an error occurs - * then an error message will be left in interp->result. + * then an error message will be left in the interp's result. * If no error occurs, then additional Postscript will be - * appended to the interp->result. + * appended to the interp's result. * * Side effects: * The Postscript font name is entered into psInfoPtr->fontTable @@ -1009,17 +1026,15 @@ Tk_CanvasPsColor(interp, canvas, colorPtr) */ int -Tk_CanvasPsFont(interp, canvas, tkfont) - Tcl_Interp *interp; /* Interpreter for returning Postscript - * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ +Tk_PostscriptFont(interp, psInfo, tkfont) + Tcl_Interp *interp; + Tk_PostscriptInfo psInfo; /* Postscript Info. */ Tk_Font tkfont; /* Information about font in which text * is to be printed. */ { - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; char *end; - char pointString[20]; + char pointString[TCL_INTEGER_SPACE]; Tcl_DString ds; int i, points; @@ -1082,7 +1097,7 @@ Tk_CanvasPsFont(interp, canvas, tkfont) /* *-------------------------------------------------------------- * - * Tk_CanvasPsBitmap -- + * Tk_PostscriptBitmap -- * * This procedure is called to output the contents of a * sub-region of a bitmap in proper image data format for @@ -1091,9 +1106,9 @@ Tk_CanvasPsFont(interp, canvas, tkfont) * * Results: * Returns a standard Tcl return value. If an error occurs - * then an error message will be left in interp->result. + * then an error message will be left in the interp's result. * If no error occurs, then additional Postscript will be - * appended to interp->result. + * appended to the interp's result. * * Side effects: * None. @@ -1102,18 +1117,18 @@ Tk_CanvasPsFont(interp, canvas, tkfont) */ int -Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) - Tcl_Interp *interp; /* Interpreter for returning Postscript - * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ +Tk_PostscriptBitmap(interp, tkwin, psInfo, bitmap, startX, startY, width, + height) + Tcl_Interp *interp; + Tk_Window tkwin; + Tk_PostscriptInfo psInfo; /* Postscript info. */ Pixmap bitmap; /* Bitmap for which to generate * Postscript. */ int startX, startY; /* Coordinates of upper-left corner * of rectangular region to output. */ int width, height; /* Height of rectangular region. */ { - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; XImage *imagePtr; int charsInLine, x, y, lastX, lastY, value, mask; unsigned int totalWidth, totalHeight; @@ -1134,10 +1149,10 @@ Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) * it shouldn't matter here. */ - XGetGeometry(Tk_Display(Tk_CanvasTkwin(canvas)), bitmap, &dummyRoot, + XGetGeometry(Tk_Display(tkwin), bitmap, &dummyRoot, (int *) &dummyX, (int *) &dummyY, (unsigned int *) &totalWidth, (unsigned int *) &totalHeight, &dummyBorderwidth, &dummyDepth); - imagePtr = XGetImage(Tk_Display(canvasPtr->tkwin), bitmap, 0, 0, + imagePtr = XGetImage(Tk_Display(tkwin), bitmap, 0, 0, totalWidth, totalHeight, 1, XYPixmap); Tcl_AppendResult(interp, "<", (char *) NULL); mask = 0x80; @@ -1179,7 +1194,7 @@ Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) /* *-------------------------------------------------------------- * - * Tk_CanvasPsStipple -- + * Tk_PostscriptStipple -- * * This procedure is called by individual canvas items when * they have created a path that they'd like to be filled with @@ -1190,9 +1205,9 @@ Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) * * Results: * Returns a standard Tcl return value. If an error occurs - * then an error message will be left in interp->result. + * then an error message will be left in the interp's result. * If no error occurs, then additional Postscript will be - * appended to interp->result. + * appended to the interp's result. * * Side effects: * None. @@ -1201,16 +1216,16 @@ Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) */ int -Tk_CanvasPsStipple(interp, canvas, bitmap) - Tcl_Interp *interp; /* Interpreter for returning Postscript +Tk_PostscriptStipple(interp, tkwin, psInfo, bitmap) + Tcl_Interp *interp; + Tk_Window tkwin; + Tk_PostscriptInfo psInfo; /* Interpreter for returning Postscript * or error message. */ - Tk_Canvas canvas; /* Information about canvas. */ Pixmap bitmap; /* Bitmap to use for stippling. */ { - TkCanvas *canvasPtr = (TkCanvas *) canvas; - TkPostscriptInfo *psInfoPtr = canvasPtr->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; int width, height; - char string[100]; + char string[TCL_INTEGER_SPACE * 2]; Window dummyRoot; int dummyX, dummyY; unsigned dummyBorderwidth, dummyDepth; @@ -1227,12 +1242,12 @@ Tk_CanvasPsStipple(interp, canvas, bitmap) * it shouldn't matter here. */ - XGetGeometry(Tk_Display(Tk_CanvasTkwin(canvas)), bitmap, &dummyRoot, + XGetGeometry(Tk_Display(tkwin), bitmap, &dummyRoot, (int *) &dummyX, (int *) &dummyY, (unsigned *) &width, (unsigned *) &height, &dummyBorderwidth, &dummyDepth); sprintf(string, "%d %d ", width, height); Tcl_AppendResult(interp, string, (char *) NULL); - if (Tk_CanvasPsBitmap(interp, (Tk_Canvas) canvasPtr, bitmap, 0, 0, + if (Tk_PostscriptBitmap(interp, tkwin, psInfo, bitmap, 0, 0, width, height) != TCL_OK) { return TCL_ERROR; } @@ -1243,9 +1258,9 @@ Tk_CanvasPsStipple(interp, canvas, bitmap) /* *-------------------------------------------------------------- * - * Tk_CanvasPsY -- + * Tk_PostscriptY -- * - * Given a y-coordinate in canvas coordinates, this procedure + * Given a y-coordinate in local coordinates, this procedure * returns a y-coordinate to use for Postscript output. * * Results: @@ -1259,12 +1274,11 @@ Tk_CanvasPsStipple(interp, canvas, bitmap) */ double -Tk_CanvasPsY(canvas, y) - Tk_Canvas canvas; /* Token for canvas on whose behalf - * Postscript is being generated. */ +Tk_PostscriptY(y, psInfo) double y; /* Y-coordinate in canvas coords. */ + Tk_PostscriptInfo psInfo; /* Postscript info */ { - TkPostscriptInfo *psInfoPtr = ((TkCanvas *) canvas)->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; return psInfoPtr->y2 - y; } @@ -1272,13 +1286,13 @@ Tk_CanvasPsY(canvas, y) /* *-------------------------------------------------------------- * - * Tk_CanvasPsPath -- + * Tk_PostscriptPath -- * * Given an array of points for a path, generate Postscript * commands to create the path. * * Results: - * Postscript commands get appended to what's in interp->result. + * Postscript commands get appended to what's in the interp's result. * * Side effects: * None. @@ -1287,29 +1301,28 @@ Tk_CanvasPsY(canvas, y) */ void -Tk_CanvasPsPath(interp, canvas, coordPtr, numPoints) - Tcl_Interp *interp; /* Put generated Postscript in this - * interpreter's result field. */ - Tk_Canvas canvas; /* Canvas on whose behalf Postscript +Tk_PostscriptPath(interp, psInfo, coordPtr, numPoints) + Tcl_Interp *interp; + Tk_PostscriptInfo psInfo; /* Canvas on whose behalf Postscript * is being generated. */ double *coordPtr; /* Pointer to first in array of * 2*numPoints coordinates giving * points for path. */ int numPoints; /* Number of points at *coordPtr. */ { - TkPostscriptInfo *psInfoPtr = ((TkCanvas *) canvas)->psInfoPtr; + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; char buffer[200]; if (psInfoPtr->prepass) { return; } sprintf(buffer, "%.15g %.15g moveto\n", coordPtr[0], - Tk_CanvasPsY(canvas, coordPtr[1])); + Tk_PostscriptY(coordPtr[1], psInfo)); Tcl_AppendResult(interp, buffer, (char *) NULL); for (numPoints--, coordPtr += 2; numPoints > 0; numPoints--, coordPtr += 2) { sprintf(buffer, "%.15g %.15g lineto\n", coordPtr[0], - Tk_CanvasPsY(canvas, coordPtr[1])); + Tk_PostscriptY(coordPtr[1], psInfo)); Tcl_AppendResult(interp, buffer, (char *) NULL); } } @@ -1327,7 +1340,7 @@ Tk_CanvasPsPath(interp, canvas, coordPtr, numPoints) * TCL_OK is returned, then everything went well and the * screen distance is stored at *doublePtr; otherwise * TCL_ERROR is returned and an error message is left in - * interp->result. + * the interp's result. * * Side effects: * None. @@ -1384,3 +1397,750 @@ GetPostscriptPoints(interp, string, doublePtr) *doublePtr = d; return TCL_OK; } + +/* + *-------------------------------------------------------------- + * + * TkImageGetColor -- + * + * This procedure converts a pixel value to three floating + * point numbers, representing the amount of red, green, and + * blue in that pixel on the screen. It makes use of colormap + * data passed as an argument, and should work for all Visual + * types. + * + * Results: + * Returns red, green, and blue color values in the range + * 0 to 1. There are no error returns. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static void +TkImageGetColor(cdata, pixel, red, green, blue) + TkColormapData *cdata; /* Colormap data */ + unsigned long pixel; /* Pixel value to look up */ + double *red, *green, *blue; /* Color data to return */ +{ + if (cdata->separated) { + int r = (pixel & cdata->red_mask) >> cdata->red_shift; + int g = (pixel & cdata->green_mask) >> cdata->green_shift; + int b = (pixel & cdata->blue_mask) >> cdata->blue_shift; + *red = cdata->colors[r].red / 65535.0; + *green = cdata->colors[g].green / 65535.0; + *blue = cdata->colors[b].blue / 65535.0; + } else { + *red = cdata->colors[pixel].red / 65535.0; + *green = cdata->colors[pixel].green / 65535.0; + *blue = cdata->colors[pixel].blue / 65535.0; + } +} + +/* + *-------------------------------------------------------------- + * + * TkPostscriptImage -- + * + * This procedure is called to output the contents of an + * image in Postscript, using a format appropriate for the + * current color mode (i.e. one bit per pixel in monochrome, + * one byte per pixel in gray, and three bytes per pixel in + * color). + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkPostscriptImage(interp, tkwin, psInfo, ximage, x, y, width, height) + Tcl_Interp *interp; + Tk_Window tkwin; + Tk_PostscriptInfo psInfo; /* postscript info */ + XImage *ximage; /* Image to draw */ + int x, y; /* First pixel to output */ + int width, height; /* Width and height of area */ +{ + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; + char buffer[256]; + int xx, yy, band, maxRows; + double red, green, blue; + int bytesPerLine=0, maxWidth=0; + int level = psInfoPtr->colorLevel; + Colormap cmap; + int i, depth, ncolors; + Visual *visual; + TkColormapData cdata; + + if (psInfoPtr->prepass) { + return TCL_OK; + } + + cmap = Tk_Colormap(tkwin); + depth = Tk_Depth(tkwin); + visual = Tk_Visual(tkwin); + + /* + * Obtain information about the colormap, ie the mapping between + * pixel values and RGB values. The code below should work + * for all Visual types. + */ + + ncolors = visual->map_entries; + cdata.colors = (XColor *) ckalloc(sizeof(XColor) * ncolors); + cdata.ncolors = ncolors; + + if (visual->class == DirectColor || visual->class == TrueColor) { + cdata.separated = 1; + cdata.red_mask = visual->red_mask; + cdata.green_mask = visual->green_mask; + cdata.blue_mask = visual->blue_mask; + cdata.red_shift = 0; + cdata.green_shift = 0; + cdata.blue_shift = 0; + while ((0x0001 & (cdata.red_mask >> cdata.red_shift)) == 0) + cdata.red_shift ++; + while ((0x0001 & (cdata.green_mask >> cdata.green_shift)) == 0) + cdata.green_shift ++; + while ((0x0001 & (cdata.blue_mask >> cdata.blue_shift)) == 0) + cdata.blue_shift ++; + for (i = 0; i < ncolors; i ++) + cdata.colors[i].pixel = + ((i << cdata.red_shift) & cdata.red_mask) | + ((i << cdata.green_shift) & cdata.green_mask) | + ((i << cdata.blue_shift) & cdata.blue_mask); + } else { + cdata.separated=0; + for (i = 0; i < ncolors; i ++) + cdata.colors[i].pixel = i; + } + if (visual->class == StaticGray || visual->class == GrayScale) + cdata.color = 0; + else + cdata.color = 1; + + + XQueryColors(Tk_Display(tkwin), cmap, cdata.colors, ncolors); + + /* + * Figure out which color level to use (possibly lower than the + * one specified by the user). For example, if the user specifies + * color with monochrome screen, use gray or monochrome mode instead. + */ + + if (!cdata.color && level == 2) { + level = 1; + } + + if (!cdata.color && cdata.ncolors == 2) { + level = 0; + } + + /* + * Check that at least one row of the image can be represented + * with a string less than 64 KB long (this is a limit in the + * Postscript interpreter). + */ + + switch (level) + { + case 0: bytesPerLine = (width + 7) / 8; maxWidth = 240000; break; + case 1: bytesPerLine = width; maxWidth = 60000; break; + case 2: bytesPerLine = 3 * width; maxWidth = 20000; break; + } + + if (bytesPerLine > 60000) { + Tcl_ResetResult(interp); + sprintf(buffer, + "Can't generate Postscript for images more than %d pixels wide", + maxWidth); + Tcl_AppendResult(interp, buffer, (char *) NULL); + ckfree((char *) cdata.colors); + return TCL_ERROR; + } + + maxRows = 60000 / bytesPerLine; + + for (band = height-1; band >= 0; band -= maxRows) { + int rows = (band >= maxRows) ? maxRows : band + 1; + int lineLen = 0; + switch (level) { + case 0: + sprintf(buffer, "%d %d 1 matrix {\n<", width, rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + break; + case 1: + sprintf(buffer, "%d %d 8 matrix {\n<", width, rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + break; + case 2: + sprintf(buffer, "%d %d 8 matrix {\n<", + width, rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + break; + } + for (yy = band; yy > band - rows; yy--) { + switch (level) { + case 0: { + /* + * Generate data for image in monochrome mode. + * No attempt at dithering is made--instead, just + * set a threshold. + */ + unsigned char mask=0x80; + unsigned char data=0x00; + for (xx = x; xx< x+width; xx++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + if (0.30 * red + 0.59 * green + 0.11 * blue > 0.5) + data |= mask; + mask >>= 1; + if (mask == 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + mask=0x80; + data=0x00; + } + } + if ((width % 8) != 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + mask=0x80; + data=0x00; + } + break; + } + case 1: { + /* + * Generate data in gray mode--in this case, take a + * weighted sum of the red, green, and blue values. + */ + for (xx = x; xx < x+width; xx ++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + sprintf(buffer, "%02X", (int) floor(0.5 + 255.0 * + (0.30 * red + + 0.59 * green + + 0.11 * blue))); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + case 2: { + /* + * Finally, color mode. Here, just output the red, green, + * and blue values directly. + */ + for (xx = x; xx < x+width; xx++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + sprintf(buffer, "%02X%02X%02X", + (int) floor(0.5 + 255.0 * red), + (int) floor(0.5 + 255.0 * green), + (int) floor(0.5 + 255.0 * blue)); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 6; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + } + } + switch (level) { + case 0: sprintf(buffer, ">\n} image\n"); break; + case 1: sprintf(buffer, ">\n} image\n"); break; + case 2: sprintf(buffer, ">\n} false 3 colorimage\n"); break; + } + Tcl_AppendResult(interp, buffer, (char *) NULL); + sprintf(buffer, "0 %d translate\n", rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + ckfree((char *) cdata.colors); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Tk_PostscriptPhoto -- + * + * This procedure is called to output the contents of a + * photo image in Postscript, using a format appropriate for + * the requested postscript color mode (i.e. one byte per pixel + * in gray, and three bytes per pixel in color). + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to the interpreter's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +int +Tk_PostscriptPhoto(interp, blockPtr, psInfo, width, height) + Tcl_Interp *interp; + Tk_PhotoImageBlock *blockPtr; + Tk_PostscriptInfo psInfo; + int width, height; +{ + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; + int colorLevel = psInfoPtr->colorLevel; + static int codeIncluded = 0; + + unsigned char *pixelPtr; + char buffer[256], cspace[40], decode[40]; + int bpc; + int xx, yy, lineLen; + float red, green, blue; + int alpha; + int bytesPerLine=0, maxWidth=0; + + unsigned char opaque = 255; + unsigned char *alphaPtr; + int alphaOffset, alphaPitch, alphaIncr; + + if (psInfoPtr->prepass) { + codeIncluded = 0; + return TCL_OK; + } + + /* + * Define the "TkPhoto" function, which is a modified version + * of the original "transparentimage" function posted + * by ian@five-d.com (Ian Kemmish) to comp.lang.postscript. + * For a monochrome colorLevel this is a slightly different + * version that uses the imagemask command instead of image. + */ + + if( !codeIncluded && (colorLevel != 0) ) { + /* + * Color and gray-scale code. + */ + + codeIncluded = !0; + Tcl_AppendResult( interp, + "/TkPhoto { \n", + " gsave \n", + " 32 dict begin \n", + " /tinteger exch def \n", + " /transparent 1 string def \n", + " transparent 0 tinteger put \n", + " /olddict exch def \n", + " olddict /DataSource get dup type /filetype ne { \n", + " olddict /DataSource 3 -1 roll \n", + " 0 () /SubFileDecode filter put \n", + " } { \n", + " pop \n", + " } ifelse \n", + " /newdict olddict maxlength dict def \n", + " olddict newdict copy pop \n", + " /w newdict /Width get def \n", + " /crpp newdict /Decode get length 2 idiv def \n", + " /str w string def \n", + " /pix w crpp mul string def \n", + " /substrlen 2 w log 2 log div floor exp cvi def \n", + " /substrs [ \n", + " { \n", + " substrlen string \n", + " 0 1 substrlen 1 sub { \n", + " 1 index exch tinteger put \n", + " } for \n", + " /substrlen substrlen 2 idiv def \n", + " substrlen 0 eq {exit} if \n", + " } loop \n", + " ] def \n", + " /h newdict /Height get def \n", + " 1 w div 1 h div matrix scale \n", + " olddict /ImageMatrix get exch matrix concatmatrix \n", + " matrix invertmatrix concat \n", + " newdict /Height 1 put \n", + " newdict /DataSource pix put \n", + " /mat [w 0 0 h 0 0] def \n", + " newdict /ImageMatrix mat put \n", + " 0 1 h 1 sub { \n", + " mat 5 3 -1 roll neg put \n", + " olddict /DataSource get str readstring pop pop \n", + " /tail str def \n", + " /x 0 def \n", + " olddict /DataSource get pix readstring pop pop \n", + " { \n", + " tail transparent search dup /done exch not def \n", + " {exch pop exch pop} if \n", + " /w1 exch length def \n", + " w1 0 ne { \n", + " newdict /DataSource ", + " pix x crpp mul w1 crpp mul getinterval put \n", + " newdict /Width w1 put \n", + " mat 4 x neg put \n", + " /x x w1 add def \n", + " newdict image \n", + " /tail tail w1 tail length w1 sub getinterval def \n", + " } if \n", + " done {exit} if \n", + " tail substrs { \n", + " anchorsearch {pop} if \n", + " } forall \n", + " /tail exch def \n", + " tail length 0 eq {exit} if \n", + " /x w tail length sub def \n", + " } loop \n", + " } for \n", + " end \n", + " grestore \n", + "} bind def \n\n\n", (char *) NULL); + } else if( !codeIncluded && (colorLevel == 0) ) { + /* + * Monochrome-only code + */ + + codeIncluded = !0; + Tcl_AppendResult( interp, + "/TkPhoto { \n", + " gsave \n", + " 32 dict begin \n", + " /dummyInteger exch def \n", + " /olddict exch def \n", + " olddict /DataSource get dup type /filetype ne { \n", + " olddict /DataSource 3 -1 roll \n", + " 0 () /SubFileDecode filter put \n", + " } { \n", + " pop \n", + " } ifelse \n", + " /newdict olddict maxlength dict def \n", + " olddict newdict copy pop \n", + " /w newdict /Width get def \n", + " /pix w 7 add 8 idiv string def \n", + " /h newdict /Height get def \n", + " 1 w div 1 h div matrix scale \n", + " olddict /ImageMatrix get exch matrix concatmatrix \n", + " matrix invertmatrix concat \n", + " newdict /Height 1 put \n", + " newdict /DataSource pix put \n", + " /mat [w 0 0 h 0 0] def \n", + " newdict /ImageMatrix mat put \n", + " 0 1 h 1 sub { \n", + " mat 5 3 -1 roll neg put \n", + " 0.000 0.000 0.000 setrgbcolor \n", + " olddict /DataSource get pix readstring pop pop \n", + " newdict /DataSource pix put \n", + " newdict imagemask \n", + " 1.000 1.000 1.000 setrgbcolor \n", + " olddict /DataSource get pix readstring pop pop \n", + " newdict /DataSource pix put \n", + " newdict imagemask \n", + " } for \n", + " end \n", + " grestore \n", + "} bind def \n\n\n", (char *) NULL); + } + + /* + * Check that at least one row of the image can be represented + * with a string less than 64 KB long (this is a limit in the + * Postscript interpreter). + */ + + switch (colorLevel) + { + case 0: bytesPerLine = (width + 7) / 8; maxWidth = 240000; break; + case 1: bytesPerLine = width; maxWidth = 60000; break; + case 2: bytesPerLine = 3 * width; maxWidth = 20000; break; + } + if (bytesPerLine > 60000) { + Tcl_ResetResult(interp); + sprintf(buffer, + "Can't generate Postscript for images more than %d pixels wide", + maxWidth); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return TCL_ERROR; + } + + /* + * Set up the postscript code except for the image-data stream. + */ + + switch (colorLevel) { + case 0: + strcpy( cspace, "/DeviceGray"); + strcpy( decode, "[1 0]"); + bpc = 1; + break; + case 1: + strcpy( cspace, "/DeviceGray"); + strcpy( decode, "[0 1]"); + bpc = 8; + break; + default: + strcpy( cspace, "/DeviceRGB"); + strcpy( decode, "[0 1 0 1 0 1]"); + bpc = 8; + break; + } + + + Tcl_AppendResult(interp, + cspace, " setcolorspace\n\n", (char *) NULL); + + sprintf(buffer, + " /Width %d\n /Height %d\n /BitsPerComponent %d\n", + width, height, bpc); + Tcl_AppendResult(interp, + "<<\n /ImageType 1\n", buffer, + " /DataSource currentfile", + " /ASCIIHexDecode filter\n", (char *) NULL); + + + sprintf(buffer, + " /ImageMatrix [1 0 0 -1 0 %d]\n", height); + Tcl_AppendResult(interp, buffer, + " /Decode ", decode, "\n>>\n1 TkPhoto\n", (char *) NULL); + + + /* + * Check the PhotoImageBlock information. + * We assume that: + * if pixelSize is 1,2 or 4, the image is R,G,B,A; + * if pixelSize is 3, the image is R,G,B and offset[3] is bogus. + */ + + if (blockPtr->pixelSize == 3) { + /* + * No alpha information: the whole image is opaque. + */ + + alphaPtr = &opaque; + alphaPitch = alphaIncr = alphaOffset = 0; + } else { + /* + * Set up alpha handling. + */ + + alphaPtr = blockPtr->pixelPtr; + alphaPitch = blockPtr->pitch; + alphaIncr = blockPtr->pixelSize; + alphaOffset = blockPtr->offset[3]; + } + + + for (yy = 0, lineLen=0; yy < height; yy++) { + switch (colorLevel) { + case 0: { + /* + * Generate data for image in monochrome mode. + * No attempt at dithering is made--instead, just + * set a threshold. + * To handle transparecies we need to output two lines: + * one for the black pixels, one for the white ones. + */ + + unsigned char mask=0x80; + unsigned char data=0x00; + for (xx = 0; xx< width; xx ++) { + pixelPtr = blockPtr->pixelPtr + + (yy * blockPtr->pitch) + + (xx *blockPtr->pixelSize); + + red = pixelPtr[blockPtr->offset[0]]; + green = pixelPtr[blockPtr->offset[1]]; + blue = pixelPtr[blockPtr->offset[2]]; + + alpha = *(alphaPtr + (yy * alphaPitch) + + (xx * alphaIncr) + alphaOffset); + + /* + * If pixel is less than threshold, then it is black. + */ + + if ((alpha != 0) && + ( 0.3086 * red + + 0.6094 * green + + 0.082 * blue < 128)) { + data |= mask; + } + mask >>= 1; + if (mask == 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + mask=0x80; + data=0x00; + } + } + if ((width % 8) != 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + mask=0x80; + data=0x00; + } + + mask=0x80; + data=0x00; + for (xx = 0; xx< width; xx ++) { + pixelPtr = blockPtr->pixelPtr + + (yy * blockPtr->pitch) + + (xx *blockPtr->pixelSize); + + red = pixelPtr[blockPtr->offset[0]]; + green = pixelPtr[blockPtr->offset[1]]; + blue = pixelPtr[blockPtr->offset[2]]; + + alpha = *(alphaPtr + (yy * alphaPitch) + + (xx * alphaIncr) + alphaOffset); + + /* + * If pixel is greater than threshold, then it is white. + */ + + if ((alpha != 0) && + ( 0.3086 * red + + 0.6094 * green + + 0.082 * blue >= 128)) { + data |= mask; + } + mask >>= 1; + if (mask == 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + mask=0x80; + data=0x00; + } + } + if ((width % 8) != 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + mask=0x80; + data=0x00; + } + break; + } + case 1: { + /* + * Generate transparency data. + * We must prevent a transparent value of 0 + * because of a bug in some HP printers. + */ + + for (xx = 0; xx < width; xx ++) { + alpha = *(alphaPtr + (yy * alphaPitch) + + (xx * alphaIncr) + alphaOffset); + sprintf(buffer, "%02X", alpha | 0x01); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + + + /* + * Generate data in gray mode--in this case, take a + * weighted sum of the red, green, and blue values. + */ + + for (xx = 0; xx < width; xx ++) { + pixelPtr = blockPtr->pixelPtr + + (yy * blockPtr->pitch) + + (xx *blockPtr->pixelSize); + + red = pixelPtr[blockPtr->offset[0]]; + green = pixelPtr[blockPtr->offset[1]]; + blue = pixelPtr[blockPtr->offset[2]]; + + sprintf(buffer, "%02X", (int) floor(0.5 + + ( 0.3086 * red + 0.6094 * green + 0.0820 * blue))); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + default: { + /* + * Generate transparency data. + * We must prevent a transparent value of 0 + * because of a bug in some HP printers. + */ + + for (xx = 0; xx < width; xx ++) { + alpha = *(alphaPtr + (yy * alphaPitch) + + (xx * alphaIncr) + alphaOffset); + sprintf(buffer, "%02X", alpha | 0x01); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + + + /* + * Finally, color mode. Here, just output the red, green, + * and blue values directly. + */ + + for (xx = 0; xx < width; xx ++) { + pixelPtr = blockPtr->pixelPtr + + (yy * blockPtr->pitch) + + (xx *blockPtr->pixelSize); + + sprintf(buffer, "%02X%02X%02X", + pixelPtr[blockPtr->offset[0]], + pixelPtr[blockPtr->offset[1]], + pixelPtr[blockPtr->offset[2]]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 6; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + } + } + + Tcl_AppendResult(interp, ">\n", (char *) NULL); + return TCL_OK; +} + diff --git a/tk/generic/tkCanvText.c b/tk/generic/tkCanvText.c index fc1dc4c0190..688d86b6b05 100644 --- a/tk/generic/tkCanvText.c +++ b/tk/generic/tkCanvText.c @@ -4,7 +4,7 @@ * This file implements text items for canvas widgets. * * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -36,18 +36,23 @@ typedef struct TextItem { */ double x, y; /* Positioning point for text. */ - int insertPos; /* Insertion cursor is displayed just to left - * of character with this index. */ + int insertPos; /* Character index of character just before + * which the insertion cursor is displayed. */ /* * Configuration settings that are updated by Tk_ConfigureWidget. */ Tk_Anchor anchor; /* Where to anchor text relative to (x,y). */ + Tk_TSOffset tsoffset; XColor *color; /* Color for text. */ + XColor *activeColor; /* Color for text. */ + XColor *disabledColor; /* Color for text. */ Tk_Font tkfont; /* Font for drawing text. */ Tk_Justify justify; /* Justification mode for text. */ Pixmap stipple; /* Stipple bitmap for text, or None. */ + Pixmap activeStipple; /* Stipple bitmap for text, or None. */ + Pixmap disabledStipple; /* Stipple bitmap for text, or None. */ char *text; /* Text for item (malloc-ed). */ int width; /* Width of lines for word-wrap, pixels. * Zero means no word-wrap. */ @@ -57,7 +62,8 @@ typedef struct TextItem { * configuration settings above. */ - int numChars; /* Number of non-NULL characters in text. */ + int numChars; /* Length of text in characters. */ + int numBytes; /* Length of text in bytes. */ Tk_TextLayout textLayout; /* Cached text layout information. */ int leftEdge; /* Pixel location of the left edge of the * text item; where the left border of the @@ -77,14 +83,31 @@ typedef struct TextItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, (ClientData) (TK_OFFSET_RELATIVE) +}; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(TextItem, activeColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(TextItem, activeStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL, "center", Tk_Offset(TextItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(TextItem, disabledColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(TextItem, disabledStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, "black", Tk_Offset(TextItem, color), TK_CONFIG_NULL_OK}, {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL, @@ -92,6 +115,12 @@ static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_JUSTIFY, "-justify", (char *) NULL, (char *) NULL, "left", Tk_Offset(TextItem, justify), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(TextItem, tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TextItem, stipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, @@ -112,10 +141,10 @@ static void ComputeTextBbox _ANSI_ARGS_((Tk_Canvas canvas, TextItem *textPtr)); static int ConfigureText _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateText _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteText _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayCanvText _ANSI_ARGS_((Tk_Canvas canvas, @@ -126,7 +155,7 @@ static int GetSelText _ANSI_ARGS_((Tk_Canvas canvas, int maxBytes)); static int GetTextIndex _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, - char *indexString, int *indexPtr)); + Tcl_Obj *obj, int *indexPtr)); static void ScaleText _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double originX, double originY, double scaleX, double scaleY)); @@ -134,7 +163,7 @@ static void SetTextCursor _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, int index)); static int TextCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void TextDeleteChars _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, int first, int last)); static void TextInsert _ANSI_ARGS_((Tk_Canvas canvas, @@ -154,26 +183,26 @@ static void TranslateText _ANSI_ARGS_((Tk_Canvas canvas, */ Tk_ItemType tkTextType = { - "text", /* name */ - sizeof(TextItem), /* itemSize */ - CreateText, /* createProc */ - configSpecs, /* configSpecs */ - ConfigureText, /* configureProc */ - TextCoords, /* coordProc */ - DeleteText, /* deleteProc */ - DisplayCanvText, /* displayProc */ - 0, /* alwaysRedraw */ - TextToPoint, /* pointProc */ - TextToArea, /* areaProc */ - TextToPostscript, /* postscriptProc */ - ScaleText, /* scaleProc */ - TranslateText, /* translateProc */ - GetTextIndex, /* indexProc */ - SetTextCursor, /* icursorProc */ - GetSelText, /* selectionProc */ - TextInsert, /* insertProc */ - TextDeleteChars, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + "text", /* name */ + sizeof(TextItem), /* itemSize */ + CreateText, /* createProc */ + configSpecs, /* configSpecs */ + ConfigureText, /* configureProc */ + TextCoords, /* coordProc */ + DeleteText, /* deleteProc */ + DisplayCanvText, /* displayProc */ + TK_CONFIG_OBJS, /* flags */ + TextToPoint, /* pointProc */ + TextToArea, /* areaProc */ + TextToPostscript, /* postscriptProc */ + ScaleText, /* scaleProc */ + TranslateText, /* translateProc */ + (Tk_ItemIndexProc *) GetTextIndex,/* indexProc */ + SetTextCursor, /* icursorProc */ + GetSelText, /* selectionProc */ + TextInsert, /* insertProc */ + TextDeleteChars, /* dTextProc */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* @@ -187,7 +216,7 @@ Tk_ItemType tkTextType = { * Results: * A standard Tcl return value. If an error occurred in * creating the item then an error message is left in - * interp->result; in this case itemPtr is left uninitialized + * the interp's result; in this case itemPtr is left uninitialized * so it can be safely freed by the caller. * * Side effects: @@ -198,16 +227,29 @@ Tk_ItemType tkTextType = { static int CreateText(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Canvas canvas; /* Canvas to hold new item. */ - Tk_Item *itemPtr; /* Record to hold new item; header - * has been initialized by caller. */ - int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ + Tcl_Interp *interp; /* Interpreter for error reporting. */ + Tk_Canvas canvas; /* Canvas to hold new item. */ + Tk_Item *itemPtr; /* Record to hold new item; header has been + * initialized by caller. */ + int argc; /* Number of arguments in argv. */ + Tcl_Obj *CONST argv[]; /* Arguments describing rectangle. */ { TextItem *textPtr = (TextItem *) itemPtr; + int i; + + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj(argv[1], NULL); + if ((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z')) { + i = 1; + } else { + i = 2; + } + } - if (argc < 2) { + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x y ?options?\"", (char *) NULL); @@ -215,8 +257,8 @@ CreateText(interp, canvas, itemPtr, argc, argv) } /* - * Carry out initialization that is needed in order to clean - * up after errors during the the remainder of this procedure. + * Carry out initialization that is needed in order to clean up after + * errors during the the remainder of this procedure. */ textPtr->textInfoPtr = Tk_CanvasGetTextInfo(canvas); @@ -224,14 +266,22 @@ CreateText(interp, canvas, itemPtr, argc, argv) textPtr->insertPos = 0; textPtr->anchor = TK_ANCHOR_CENTER; + textPtr->tsoffset.flags = 0; + textPtr->tsoffset.xoffset = 0; + textPtr->tsoffset.yoffset = 0; textPtr->color = NULL; + textPtr->activeColor = NULL; + textPtr->disabledColor = NULL; textPtr->tkfont = NULL; textPtr->justify = TK_JUSTIFY_LEFT; textPtr->stipple = None; + textPtr->activeStipple = None; + textPtr->disabledStipple = None; textPtr->text = NULL; textPtr->width = 0; textPtr->numChars = 0; + textPtr->numBytes = 0; textPtr->textLayout = NULL; textPtr->leftEdge = 0; textPtr->rightEdge = 0; @@ -243,17 +293,16 @@ CreateText(interp, canvas, itemPtr, argc, argv) * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &textPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], &textPtr->y) - != TCL_OK)) { - return TCL_ERROR; + if ((TextCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureText(interp, canvas, itemPtr, argc-2, argv+2, 0) != TCL_OK) { - DeleteText(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureText(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { + return TCL_OK; } - return TCL_OK; + + error: + DeleteText(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -266,7 +315,7 @@ CreateText(interp, canvas, itemPtr, argc, argv) * details on what it does. * * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. * * Side effects: * The coordinates for the given item may be changed. @@ -276,32 +325,46 @@ CreateText(interp, canvas, itemPtr, argc, argv) static int TextCoords(interp, canvas, itemPtr, argc, argv) - Tcl_Interp *interp; /* Used for error reporting. */ - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item whose coordinates are to be - * read or modified. */ - int argc; /* Number of coordinates supplied in - * argv. */ - char **argv; /* Array of coordinates: x1, y1, - * x2, y2, ... */ + Tcl_Interp *interp; /* Used for error reporting. */ + Tk_Canvas canvas; /* Canvas containing item. */ + Tk_Item *itemPtr; /* Item whose coordinates are to be read or + * modified. */ + int argc; /* Number of coordinates supplied in argv. */ + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, x2, y2, ... */ { TextItem *textPtr = (TextItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, textPtr->x, x); - Tcl_PrintDouble(interp, textPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &textPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &textPtr->y) != TCL_OK)) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(textPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(textPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (argc < 3) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 2) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], &textPtr->x) != TCL_OK) + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], + &textPtr->y) != TCL_OK)) { return TCL_ERROR; } ComputeTextBbox(canvas, textPtr); } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 2, got %d", argc); + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; @@ -317,7 +380,7 @@ TextCoords(interp, canvas, itemPtr, argc, argv) * * Results: * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. + * an error message is left in the interp's result. * * Side effects: * Configuration information, such as colors and stipple @@ -332,7 +395,7 @@ ConfigureText(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Rectangle item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { TextItem *textPtr = (TextItem *) itemPtr; @@ -342,10 +405,13 @@ ConfigureText(interp, canvas, itemPtr, argc, argv, flags) Tk_Window tkwin; Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; XColor *selBgColorPtr; + XColor *color; + Pixmap stipple; + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) textPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) textPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -354,20 +420,59 @@ ConfigureText(interp, canvas, itemPtr, argc, argv, flags) * graphics contexts. */ + state = itemPtr->state; + + if (textPtr->activeColor != NULL || + textPtr->activeStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + color = textPtr->color; + stipple = textPtr->stipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (textPtr->activeColor!=NULL) { + color = textPtr->activeColor; + } + if (textPtr->activeStipple!=None) { + stipple = textPtr->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (textPtr->disabledColor!=NULL) { + color = textPtr->disabledColor; + } + if (textPtr->disabledStipple!=None) { + stipple = textPtr->disabledStipple; + } + } + newGC = newSelGC = None; - if ((textPtr->color != NULL) && (textPtr->tkfont != NULL)) { - gcValues.foreground = textPtr->color->pixel; + if (textPtr->tkfont != NULL) { gcValues.font = Tk_FontId(textPtr->tkfont); - mask = GCForeground|GCFont; - if (textPtr->stipple != None) { - gcValues.stipple = textPtr->stipple; + mask = GCFont; + if (color != NULL) { + gcValues.foreground = color->pixel; + mask |= GCForeground; + if (stipple != None) { + gcValues.stipple = stipple; + gcValues.fill_style = FillStippled; + mask |= GCStipple|GCFillStyle; + } + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } + mask &= ~(GCTile|GCFillStyle|GCStipple); + if (stipple != None) { + gcValues.stipple = stipple; gcValues.fill_style = FillStippled; - mask |= GCForeground|GCStipple|GCFillStyle; + mask |= GCStipple|GCFillStyle; } - newGC = Tk_GetGCColor(tkwin, mask, &gcValues, textPtr->color, NULL); gcValues.foreground = textInfoPtr->selFgColorPtr->pixel; - newSelGC = Tk_GetGCColor(tkwin, mask, &gcValues, - textInfoPtr->selFgColorPtr, NULL); + newSelGC = Tk_GetGC(tkwin, mask|GCForeground, &gcValues); } if (textPtr->gc != None) { Tk_FreeGC(Tk_Display(tkwin), textPtr->gc); @@ -401,17 +506,19 @@ ConfigureText(interp, canvas, itemPtr, argc, argv, flags) * to keep them inside the item. */ - textPtr->numChars = strlen(textPtr->text); + textPtr->numBytes = strlen(textPtr->text); + textPtr->numChars = Tcl_NumUtfChars(textPtr->text, textPtr->numBytes); if (textInfoPtr->selItemPtr == itemPtr) { + if (textInfoPtr->selectFirst >= textPtr->numChars) { textInfoPtr->selItemPtr = NULL; } else { if (textInfoPtr->selectLast >= textPtr->numChars) { - textInfoPtr->selectLast = textPtr->numChars-1; + textInfoPtr->selectLast = textPtr->numChars - 1; } if ((textInfoPtr->anchorItemPtr == itemPtr) && (textInfoPtr->selectAnchor >= textPtr->numChars)) { - textInfoPtr->selectAnchor = textPtr->numChars-1; + textInfoPtr->selectAnchor = textPtr->numChars - 1; } } } @@ -442,20 +549,31 @@ ConfigureText(interp, canvas, itemPtr, argc, argv, flags) static void DeleteText(canvas, itemPtr, display) - Tk_Canvas canvas; /* Info about overall canvas widget. */ - Tk_Item *itemPtr; /* Item that is being deleted. */ - Display *display; /* Display containing window for - * canvas. */ + Tk_Canvas canvas; /* Info about overall canvas widget. */ + Tk_Item *itemPtr; /* Item that is being deleted. */ + Display *display; /* Display containing window for canvas. */ { TextItem *textPtr = (TextItem *) itemPtr; if (textPtr->color != NULL) { Tk_FreeColor(textPtr->color); } + if (textPtr->activeColor != NULL) { + Tk_FreeColor(textPtr->activeColor); + } + if (textPtr->disabledColor != NULL) { + Tk_FreeColor(textPtr->disabledColor); + } Tk_FreeFont(textPtr->tkfont); if (textPtr->stipple != None) { Tk_FreeBitmap(display, textPtr->stipple); } + if (textPtr->activeStipple != None) { + Tk_FreeBitmap(display, textPtr->activeStipple); + } + if (textPtr->disabledStipple != None) { + Tk_FreeBitmap(display, textPtr->disabledStipple); + } if (textPtr->text != NULL) { ckfree(textPtr->text); } @@ -495,18 +613,26 @@ DeleteText(canvas, itemPtr, display) static void ComputeTextBbox(canvas, textPtr) - Tk_Canvas canvas; /* Canvas that contains item. */ - TextItem *textPtr; /* Item whose bbos is to be - * recomputed. */ + Tk_Canvas canvas; /* Canvas that contains item. */ + TextItem *textPtr; /* Item whose bbox is to be recomputed. */ { Tk_CanvasTextInfo *textInfoPtr; int leftX, topY, width, height, fudge; + Tk_State state = textPtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } Tk_FreeTextLayout(textPtr->textLayout); textPtr->textLayout = Tk_ComputeTextLayout(textPtr->tkfont, textPtr->text, textPtr->numChars, textPtr->width, textPtr->justify, 0, &width, &height); + if (state == TK_STATE_HIDDEN || textPtr->color == NULL) { + width = height = 0; + } + /* * Use overall geometry information to compute the top-left corner * of the bounding box for the text item. @@ -592,22 +718,37 @@ ComputeTextBbox(canvas, textPtr) static void DisplayCanvText(canvas, itemPtr, display, drawable, x, y, width, height) - Tk_Canvas canvas; /* Canvas that contains item. */ - Tk_Item *itemPtr; /* Item to be displayed. */ - Display *display; /* Display on which to draw item. */ - Drawable drawable; /* Pixmap or window in which to draw - * item. */ - int x, y, width, height; /* Describes region of canvas that - * must be redisplayed (not used). */ + Tk_Canvas canvas; /* Canvas that contains item. */ + Tk_Item *itemPtr; /* Item to be displayed. */ + Display *display; /* Display on which to draw item. */ + Drawable drawable; /* Pixmap or window in which to draw item. */ + int x, y, width, height; /* Describes region of canvas that must be + * redisplayed (not used). */ { TextItem *textPtr; Tk_CanvasTextInfo *textInfoPtr; - int selFirst, selLast; + int selFirstChar, selLastChar; short drawableX, drawableY; + Pixmap stipple; + Tk_State state = itemPtr->state; textPtr = (TextItem *) itemPtr; textInfoPtr = textPtr->textInfoPtr; + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + stipple = textPtr->stipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (textPtr->activeStipple!=None) { + stipple = textPtr->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (textPtr->disabledStipple!=None) { + stipple = textPtr->disabledStipple; + } + } + if (textPtr->gc == None) { return; } @@ -618,30 +759,31 @@ DisplayCanvText(canvas, itemPtr, display, drawable, x, y, width, height) * read-only. */ - if (textPtr->stipple != None) { - Tk_CanvasSetStippleOrigin(canvas, textPtr->gc); + if (stipple != None) { + Tk_CanvasSetOffset(canvas, textPtr->gc, &textPtr->tsoffset); } - selFirst = -1; - selLast = 0; /* lint. */ + selFirstChar = -1; + selLastChar = 0; /* lint. */ + if (textInfoPtr->selItemPtr == itemPtr) { - selFirst = textInfoPtr->selectFirst; - selLast = textInfoPtr->selectLast; - if (selLast >= textPtr->numChars) { - selLast = textPtr->numChars - 1; + selFirstChar = textInfoPtr->selectFirst; + selLastChar = textInfoPtr->selectLast; + if (selLastChar > textPtr->numChars) { + selLastChar = textPtr->numChars - 1; } - if ((selFirst >= 0) && (selFirst <= selLast)) { + if ((selFirstChar >= 0) && (selFirstChar <= selLastChar)) { + int xFirst, yFirst, hFirst; + int xLast, yLast; + /* * Draw a special background under the selection. */ - int xFirst, yFirst, hFirst; - int xLast, yLast, wLast; - - Tk_CharBbox(textPtr->textLayout, selFirst, - &xFirst, &yFirst, NULL, &hFirst); - Tk_CharBbox(textPtr->textLayout, selLast, - &xLast, &yLast, &wLast, NULL); + Tk_CharBbox(textPtr->textLayout, selFirstChar, &xFirst, &yFirst, + NULL, &hFirst); + Tk_CharBbox(textPtr->textLayout, selLastChar, &xLast, &yLast, + NULL, NULL); /* * If the selection spans the end of this line, then display @@ -654,7 +796,7 @@ DisplayCanvText(canvas, itemPtr, display, drawable, x, y, width, height) height = hFirst; for (y = yFirst ; y <= yLast; y += height) { if (y == yLast) { - width = (xLast + wLast) - x; + width = xLast - x; } else { width = textPtr->rightEdge - textPtr->leftEdge - x; } @@ -725,13 +867,13 @@ DisplayCanvText(canvas, itemPtr, display, drawable, x, y, width, height) Tk_DrawTextLayout(display, drawable, textPtr->gc, textPtr->textLayout, drawableX, drawableY, 0, -1); - if ((selFirst >= 0) && (textPtr->selTextGC != textPtr->gc)) { + if ((selFirstChar >= 0) && (textPtr->selTextGC != textPtr->gc)) { Tk_DrawTextLayout(display, drawable, textPtr->selTextGC, - textPtr->textLayout, drawableX, drawableY, selFirst, - selLast + 1); + textPtr->textLayout, drawableX, drawableY, selFirstChar, + selLastChar + 1); } - if (textPtr->stipple != None) { + if (stipple != None) { XSetTSOrigin(display, textPtr->gc, 0, 0); } } @@ -755,36 +897,44 @@ DisplayCanvText(canvas, itemPtr, display, drawable, x, y, width, height) */ static void -TextInsert(canvas, itemPtr, beforeThis, string) +TextInsert(canvas, itemPtr, index, string) Tk_Canvas canvas; /* Canvas containing text item. */ Tk_Item *itemPtr; /* Text item to be modified. */ - int beforeThis; /* Index of character before which text is + int index; /* Character index before which string is * to be inserted. */ char *string; /* New characters to be inserted. */ { TextItem *textPtr = (TextItem *) itemPtr; - int length; - char *new; + int byteIndex, byteCount, charsAdded; + char *new, *text; Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; - length = strlen(string); - if (length == 0) { - return; + string = Tcl_GetStringFromObj((Tcl_Obj *) string, &byteCount); + + text = textPtr->text; + + if (index < 0) { + index = 0; } - if (beforeThis < 0) { - beforeThis = 0; + if (index > textPtr->numChars) { + index = textPtr->numChars; } - if (beforeThis > textPtr->numChars) { - beforeThis = textPtr->numChars; + byteIndex = Tcl_UtfAtIndex(text, index) - text; + byteCount = strlen(string); + if (byteCount == 0) { + return; } - new = (char *) ckalloc((unsigned) (textPtr->numChars + length + 1)); - strncpy(new, textPtr->text, (size_t) beforeThis); - strcpy(new+beforeThis, string); - strcpy(new+beforeThis+length, textPtr->text+beforeThis); - ckfree(textPtr->text); + new = (char *) ckalloc((unsigned) textPtr->numBytes + byteCount + 1); + memcpy(new, text, (size_t) byteIndex); + strcpy(new + byteIndex, string); + strcpy(new + byteIndex + byteCount, text + byteIndex); + + ckfree(text); textPtr->text = new; - textPtr->numChars += length; + charsAdded = Tcl_NumUtfChars(string, byteCount); + textPtr->numChars += charsAdded; + textPtr->numBytes += byteCount; /* * Inserting characters invalidates indices such as those for the @@ -792,19 +942,19 @@ TextInsert(canvas, itemPtr, beforeThis, string) */ if (textInfoPtr->selItemPtr == itemPtr) { - if (textInfoPtr->selectFirst >= beforeThis) { - textInfoPtr->selectFirst += length; + if (textInfoPtr->selectFirst >= index) { + textInfoPtr->selectFirst += charsAdded; } - if (textInfoPtr->selectLast >= beforeThis) { - textInfoPtr->selectLast += length; + if (textInfoPtr->selectLast >= index) { + textInfoPtr->selectLast += charsAdded; } if ((textInfoPtr->anchorItemPtr == itemPtr) - && (textInfoPtr->selectAnchor >= beforeThis)) { - textInfoPtr->selectAnchor += length; + && (textInfoPtr->selectAnchor >= index)) { + textInfoPtr->selectAnchor += charsAdded; } } - if (textPtr->insertPos >= beforeThis) { - textPtr->insertPos += length; + if (textPtr->insertPos >= index) { + textPtr->insertPos += charsAdded; } ComputeTextBbox(canvas, textPtr); } @@ -831,31 +981,40 @@ static void TextDeleteChars(canvas, itemPtr, first, last) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Item in which to delete characters. */ - int first; /* Index of first character to delete. */ - int last; /* Index of last character to delete. */ + int first; /* Character index of first character to + * delete. */ + int last; /* Character index of last character to + * delete (inclusive). */ { TextItem *textPtr = (TextItem *) itemPtr; - int count; - char *new; + int byteIndex, byteCount, charsRemoved; + char *new, *text; Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; + text = textPtr->text; if (first < 0) { first = 0; } if (last >= textPtr->numChars) { - last = textPtr->numChars-1; + last = textPtr->numChars - 1; } if (first > last) { return; } - count = last + 1 - first; + charsRemoved = last + 1 - first; - new = (char *) ckalloc((unsigned) (textPtr->numChars + 1 - count)); - strncpy(new, textPtr->text, (size_t) first); - strcpy(new+first, textPtr->text+last+1); - ckfree(textPtr->text); + byteIndex = Tcl_UtfAtIndex(text, first) - text; + byteCount = Tcl_UtfAtIndex(text + byteIndex, charsRemoved) + - (text + byteIndex); + + new = (char *) ckalloc((unsigned) (textPtr->numBytes + 1 - byteCount)); + memcpy(new, text, (size_t) byteIndex); + strcpy(new + byteIndex, text + byteIndex + byteCount); + + ckfree(text); textPtr->text = new; - textPtr->numChars -= count; + textPtr->numChars -= charsRemoved; + textPtr->numBytes -= byteCount; /* * Update indexes for the selection and cursor to reflect the @@ -864,15 +1023,15 @@ TextDeleteChars(canvas, itemPtr, first, last) if (textInfoPtr->selItemPtr == itemPtr) { if (textInfoPtr->selectFirst > first) { - textInfoPtr->selectFirst -= count; + textInfoPtr->selectFirst -= charsRemoved; if (textInfoPtr->selectFirst < first) { textInfoPtr->selectFirst = first; } } if (textInfoPtr->selectLast >= first) { - textInfoPtr->selectLast -= count; - if (textInfoPtr->selectLast < (first-1)) { - textInfoPtr->selectLast = (first-1); + textInfoPtr->selectLast -= charsRemoved; + if (textInfoPtr->selectLast < first - 1) { + textInfoPtr->selectLast = first - 1; } } if (textInfoPtr->selectFirst > textInfoPtr->selectLast) { @@ -880,14 +1039,14 @@ TextDeleteChars(canvas, itemPtr, first, last) } if ((textInfoPtr->anchorItemPtr == itemPtr) && (textInfoPtr->selectAnchor > first)) { - textInfoPtr->selectAnchor -= count; + textInfoPtr->selectAnchor -= charsRemoved; if (textInfoPtr->selectAnchor < first) { textInfoPtr->selectAnchor = first; } } } if (textPtr->insertPos > first) { - textPtr->insertPos -= count; + textPtr->insertPos -= charsRemoved; if (textPtr->insertPos < first) { textPtr->insertPos = first; } @@ -923,11 +1082,22 @@ TextToPoint(canvas, itemPtr, pointPtr) double *pointPtr; /* Pointer to x and y coordinates. */ { TextItem *textPtr; + Tk_State state = itemPtr->state; + double value; + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } textPtr = (TextItem *) itemPtr; - return (double) Tk_DistanceToTextLayout(textPtr->textLayout, + value = (double) Tk_DistanceToTextLayout(textPtr->textLayout, (int) pointPtr[0] - textPtr->leftEdge, (int) pointPtr[1] - textPtr->header.y1); + + if ((state == TK_STATE_HIDDEN) || (textPtr->color == NULL) || + (textPtr->text == NULL) || (*textPtr->text == 0)) { + value = 1.0e36; + } + return value; } /* @@ -959,6 +1129,11 @@ TextToArea(canvas, itemPtr, rectPtr) * area. */ { TextItem *textPtr; + Tk_State state = itemPtr->state; + + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } textPtr = (TextItem *) itemPtr; return Tk_IntersectTextLayout(textPtr->textLayout, @@ -988,11 +1163,11 @@ TextToArea(canvas, itemPtr, rectPtr) /* ARGSUSED */ static void ScaleText(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing rectangle. */ - Tk_Item *itemPtr; /* Rectangle to be scaled. */ - double originX, originY; /* Origin about which to scale rect. */ - double scaleX; /* Amount to scale in X direction. */ - double scaleY; /* Amount to scale in Y direction. */ + Tk_Canvas canvas; /* Canvas containing rectangle. */ + Tk_Item *itemPtr; /* Rectangle to be scaled. */ + double originX, originY; /* Origin about which to scale rect. */ + double scaleX; /* Amount to scale in X direction. */ + double scaleY; /* Amount to scale in Y direction. */ { TextItem *textPtr = (TextItem *) itemPtr; @@ -1023,10 +1198,9 @@ ScaleText(canvas, itemPtr, originX, originY, scaleX, scaleY) static void TranslateText(canvas, itemPtr, deltaX, deltaY) - Tk_Canvas canvas; /* Canvas containing item. */ - Tk_Item *itemPtr; /* Item that is being moved. */ - double deltaX, deltaY; /* Amount by which item is to be - * moved. */ + Tk_Canvas canvas; /* Canvas containing item. */ + Tk_Item *itemPtr; /* Item that is being moved. */ + double deltaX, deltaY; /* Amount by which item is to be moved. */ { TextItem *textPtr = (TextItem *) itemPtr; @@ -1047,7 +1221,7 @@ TranslateText(canvas, itemPtr, deltaX, deltaY) * A standard Tcl result. If all went well, then *indexPtr is * filled in with the index (into itemPtr) corresponding to * string. Otherwise an error message is left in - * interp->result. + * the interp's result. * * Side effects: * None. @@ -1056,20 +1230,22 @@ TranslateText(canvas, itemPtr, deltaX, deltaY) */ static int -GetTextIndex(interp, canvas, itemPtr, string, indexPtr) +GetTextIndex(interp, canvas, itemPtr, obj, indexPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tk_Canvas canvas; /* Canvas containing item. */ Tk_Item *itemPtr; /* Item for which the index is being * specified. */ - char *string; /* Specification of a particular character + Tcl_Obj *obj; /* Specification of a particular character * in itemPtr's text. */ - int *indexPtr; /* Where to store converted index. */ + int *indexPtr; /* Where to store converted character + * index. */ { TextItem *textPtr = (TextItem *) itemPtr; size_t length; int c; TkCanvas *canvasPtr = (TkCanvas *) canvas; Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; + char *string = Tcl_GetStringFromObj(obj, (int *) &length); c = string[0]; length = strlen(string); @@ -1081,14 +1257,14 @@ GetTextIndex(interp, canvas, itemPtr, string, indexPtr) } else if ((c == 's') && (strncmp(string, "sel.first", length) == 0) && (length >= 5)) { if (textInfoPtr->selItemPtr != itemPtr) { - interp->result = "selection isn't in item"; + Tcl_SetResult(interp, "selection isn't in item", TCL_STATIC); return TCL_ERROR; } *indexPtr = textInfoPtr->selectFirst; } else if ((c == 's') && (strncmp(string, "sel.last", length) == 0) && (length >= 5)) { if (textInfoPtr->selItemPtr != itemPtr) { - interp->result = "selection isn't in item"; + Tcl_SetResult(interp, "selection isn't in item", TCL_STATIC); return TCL_ERROR; } *indexPtr = textInfoPtr->selectLast; @@ -1112,7 +1288,7 @@ GetTextIndex(interp, canvas, itemPtr, string, indexPtr) *indexPtr = Tk_PointToChar(textPtr->textLayout, x + canvasPtr->scrollX1 - textPtr->leftEdge, y + canvasPtr->scrollY1 - textPtr->header.y1); - } else if (Tcl_GetInt(interp, string, indexPtr) == TCL_OK) { + } else if (Tcl_GetIntFromObj((Tcl_Interp *)NULL, obj, indexPtr) == TCL_OK) { if (*indexPtr < 0){ *indexPtr = 0; } else if (*indexPtr > textPtr->numChars) { @@ -1120,7 +1296,7 @@ GetTextIndex(interp, canvas, itemPtr, string, indexPtr) } } else { /* - * Some of the paths here leave messages in interp->result, + * Some of the paths here leave messages in the interp's result, * so we have to clear it out before storing our own message. */ @@ -1152,11 +1328,11 @@ GetTextIndex(interp, canvas, itemPtr, string, indexPtr) /* ARGSUSED */ static void SetTextCursor(canvas, itemPtr, index) - Tk_Canvas canvas; /* Record describing canvas widget. */ - Tk_Item *itemPtr; /* Text item in which cursor position - * is to be set. */ - int index; /* Index of character just before which - * cursor is to be positioned. */ + Tk_Canvas canvas; /* Record describing canvas widget. */ + Tk_Item *itemPtr; /* Text item in which cursor position is to + * be set. */ + int index; /* Character index of character just before + * which cursor is to be positioned. */ { TextItem *textPtr = (TextItem *) itemPtr; @@ -1192,34 +1368,38 @@ SetTextCursor(canvas, itemPtr, index) static int GetSelText(canvas, itemPtr, offset, buffer, maxBytes) - Tk_Canvas canvas; /* Canvas containing selection. */ - Tk_Item *itemPtr; /* Text item containing selection. */ - int offset; /* Offset within selection of first - * character to be returned. */ - char *buffer; /* Location in which to place - * selection. */ - int maxBytes; /* Maximum number of bytes to place - * at buffer, not including terminating - * NULL character. */ + Tk_Canvas canvas; /* Canvas containing selection. */ + Tk_Item *itemPtr; /* Text item containing selection. */ + int offset; /* Byte offset within selection of first + * character to be returned. */ + char *buffer; /* Location in which to place selection. */ + int maxBytes; /* Maximum number of bytes to place at + * buffer, not including terminating NULL + * character. */ { TextItem *textPtr = (TextItem *) itemPtr; - int count; + int byteCount; + char *text, *selStart, *selEnd; Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; - count = textInfoPtr->selectLast + 1 - textInfoPtr->selectFirst - offset; - if (textInfoPtr->selectLast == textPtr->numChars) { - count -= 1; + if ((textInfoPtr->selectFirst < 0) || + (textInfoPtr->selectFirst > textInfoPtr->selectLast)) { + return 0; } - if (count > maxBytes) { - count = maxBytes; + text = textPtr->text; + selStart = Tcl_UtfAtIndex(text, textInfoPtr->selectFirst); + selEnd = Tcl_UtfAtIndex(selStart, + textInfoPtr->selectLast + 1 - textInfoPtr->selectFirst); + byteCount = selEnd - selStart - offset; + if (byteCount > maxBytes) { + byteCount = maxBytes; } - if (count <= 0) { + if (byteCount <= 0) { return 0; } - strncpy(buffer, textPtr->text + textInfoPtr->selectFirst + offset, - (size_t) count); - buffer[count] = '\0'; - return count; + memcpy(buffer, selStart + offset, (size_t) byteCount); + buffer[byteCount] = '\0'; + return byteCount; } /* @@ -1233,7 +1413,7 @@ GetSelText(canvas, itemPtr, offset, buffer, maxBytes) * Results: * The return value is a standard Tcl result. If an error * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used + * left in the interp's result, replacing whatever used * to be there. If no error occurs, then Postscript for the * item is appended to the result. * @@ -1245,23 +1425,44 @@ GetSelText(canvas, itemPtr, offset, buffer, maxBytes) static int TextToPostscript(interp, canvas, itemPtr, prepass) - Tcl_Interp *interp; /* Leave Postscript or error message - * here. */ - Tk_Canvas canvas; /* Information about overall canvas. */ - Tk_Item *itemPtr; /* Item for which Postscript is - * wanted. */ - int prepass; /* 1 means this is a prepass to - * collect font information; 0 means - * final Postscript is being created. */ + Tcl_Interp *interp; /* Leave Postscript or error message here. */ + Tk_Canvas canvas; /* Information about overall canvas. */ + Tk_Item *itemPtr; /* Item for which Postscript is wanted. */ + int prepass; /* 1 means this is a prepass to collect + * font information; 0 means final Postscript + * is being created. */ { TextItem *textPtr = (TextItem *) itemPtr; int x, y; Tk_FontMetrics fm; char *justify; char buffer[500]; + XColor *color; + Pixmap stipple; + Tk_State state = itemPtr->state; - if (textPtr->color == NULL) { + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + color = textPtr->color; + stipple = textPtr->stipple; + if (state == TK_STATE_HIDDEN || textPtr->color == NULL || + textPtr->text == NULL || *textPtr->text == 0) { return TCL_OK; + } else if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (textPtr->activeColor!=NULL) { + color = textPtr->activeColor; + } + if (textPtr->activeStipple!=None) { + stipple = textPtr->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (textPtr->disabledColor!=NULL) { + color = textPtr->disabledColor; + } + if (textPtr->disabledStipple!=None) { + stipple = textPtr->disabledStipple; + } } if (Tk_CanvasPsFont(interp, canvas, textPtr->tkfont) != TCL_OK) { @@ -1270,13 +1471,13 @@ TextToPostscript(interp, canvas, itemPtr, prepass) if (prepass != 0) { return TCL_OK; } - if (Tk_CanvasPsColor(interp, canvas, textPtr->color) != TCL_OK) { + if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) { return TCL_ERROR; } - if (textPtr->stipple != None) { + if (stipple != None) { Tcl_AppendResult(interp, "/StippleText {\n ", (char *) NULL); - Tk_CanvasPsStipple(interp, canvas, textPtr->stipple); + Tk_CanvasPsStipple(interp, canvas, stipple); Tcl_AppendResult(interp, "} bind def\n", (char *) NULL); } @@ -1307,8 +1508,9 @@ TextToPostscript(interp, canvas, itemPtr, prepass) Tk_GetFontMetrics(textPtr->tkfont, &fm); sprintf(buffer, "] %d %g %g %s %s DrawText\n", fm.linespace, x / -2.0, y / 2.0, justify, - ((textPtr->stipple == None) ? "false" : "true")); + ((stipple == None) ? "false" : "true")); Tcl_AppendResult(interp, buffer, (char *) NULL); return TCL_OK; } + diff --git a/tk/generic/tkCanvUtil.c b/tk/generic/tkCanvUtil.c index a78ae194ec0..0abf9665574 100644 --- a/tk/generic/tkCanvUtil.c +++ b/tk/generic/tkCanvUtil.c @@ -13,7 +13,7 @@ * RCS: @(#) $Id$ */ -#include "tk.h" +#include "tkInt.h" #include "tkCanvas.h" #include "tkPort.h" @@ -177,7 +177,7 @@ Tk_CanvasWindowCoords(canvas, x, y, screenXPtr, screenYPtr) * TCL_OK is returned, then everything went well and the * canvas coordinate is stored at *doublePtr; otherwise * TCL_ERROR is returned and an error message is left in - * interp->result. + * the interp's result. * * Side effects: * None. @@ -201,6 +201,44 @@ Tk_CanvasGetCoord(interp, canvas, string, doublePtr) *doublePtr *= canvasPtr->pixelsPerMM; return TCL_OK; } + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasGetCoordFromObj -- + * + * Given a string, returns a floating-point canvas coordinate + * corresponding to that string. + * + * Results: + * The return value is a standard Tcl return result. If + * TCL_OK is returned, then everything went well and the + * canvas coordinate is stored at *doublePtr; otherwise + * TCL_ERROR is returned and an error message is left in + * interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasGetCoordFromObj(interp, canvas, obj, doublePtr) + Tcl_Interp *interp; /* Interpreter for error reporting. */ + Tk_Canvas canvas; /* Canvas to which coordinate applies. */ + Tcl_Obj *obj; /* Describes coordinate (any screen + * coordinate form may be used here). */ + double *doublePtr; /* Place to store converted coordinate. */ +{ + TkCanvas *canvasPtr = (TkCanvas *) canvas; + if (Tk_GetMMFromObj(canvasPtr->interp, canvasPtr->tkwin, obj, + doublePtr) != TCL_OK) { + return TCL_ERROR; + } + *doublePtr *= canvasPtr->pixelsPerMM; + return TCL_OK; +} /* *---------------------------------------------------------------------- @@ -237,6 +275,50 @@ Tk_CanvasSetStippleOrigin(canvas, gc) /* *---------------------------------------------------------------------- * + * Tk_CanvasSetOffset-- + * + * This procedure sets the stipple offset in a graphics + * context so that stipples drawn with the GC will + * line up with other stipples with the same offset. + * + * Results: + * None. + * + * Side effects: + * The graphics context is modified. + * + *---------------------------------------------------------------------- + */ + +void +Tk_CanvasSetOffset(canvas, gc, offset) + Tk_Canvas canvas; /* Token for a canvas. */ + GC gc; /* Graphics context that is about to be + * used to draw a stippled pattern as + * part of redisplaying the canvas. */ + Tk_TSOffset *offset; /* offset (may be NULL pointer)*/ +{ + TkCanvas *canvasPtr = (TkCanvas *) canvas; + int flags = 0; + int x = - canvasPtr->drawableXOrigin; + int y = - canvasPtr->drawableYOrigin; + + if (offset != NULL) { + flags = offset->flags; + x += offset->xoffset; + y += offset->yoffset; + } + if ((flags & TK_OFFSET_RELATIVE) && !(flags & TK_OFFSET_INDEX)) { + Tk_SetTSOrigin(canvasPtr->tkwin, gc, x - canvasPtr->xOrigin, + y - canvasPtr->yOrigin); + } else { + XSetTSOrigin(canvasPtr->display, gc, x, y); + } +} + +/* + *---------------------------------------------------------------------- + * * Tk_CanvasGetTextInfo -- * * This procedure returns a pointer to a structure containing @@ -374,3 +456,1020 @@ Tk_CanvasTagsPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) *freeProcPtr = TCL_DYNAMIC; return Tcl_Merge(itemPtr->numTags, (char **) itemPtr->tagPtr); } + + +static int DashConvert _ANSI_ARGS_((char *l, CONST char *p, + int n, double width)); +#define ABS(a) ((a>=0)?(a):(-(a))) + +/* + *-------------------------------------------------------------- + * + * TkCanvasDashParseProc -- + * + * This procedure is invoked during option processing to handle + * "-dash", "-activedash" and "-disableddash" options for canvas + * objects. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The dash list for a given canvas object gets replaced by + * those indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +int +TkCanvasDashParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* Not used.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + return Tk_GetDash(interp, value, (Tk_Dash *)(widgRec+offset)); +} + +/* + *-------------------------------------------------------------- + * + * TkCanvasDashPrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-dash", "-activedash" + * and "-disableddash" configuration options for canvas items. + * + * Results: + * The return value is a string describing all the dash list for + * the item referred to by "widgRec"and "offset". In addition, + * *freeProcPtr is filled in with the address of a procedure to + * call to free the result string when it's no longer needed (or + * NULL to indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +char * +TkCanvasDashPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset in record for item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + Tk_Dash *dash = (Tk_Dash *) (widgRec+offset); + char *buffer; + char *p; + int i = dash->number; + + if (i < 0) { + i = -i; + *freeProcPtr = TCL_DYNAMIC; + buffer = (char *) ckalloc((unsigned int) (i+1)); + p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + memcpy(buffer, p, (unsigned int) i); + buffer[i] = 0; + return buffer; + } else if (!i) { + *freeProcPtr = (Tcl_FreeProc *) NULL; + return ""; + } + buffer = (char *)ckalloc((unsigned int) (4*i)); + *freeProcPtr = TCL_DYNAMIC; + + p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + sprintf(buffer, "%d", *p++ & 0xff); + while(--i) { + sprintf(buffer+strlen(buffer), " %d", *p++ & 0xff); + } + return buffer; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CreateSmoothMethod -- + * + * This procedure is invoked to add additional values + * for the "-smooth" option to the list. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * In the future "-smooth <name>" will be accepted as + * smooth method for the line and polygon. + * + *-------------------------------------------------------------- + */ + +Tk_SmoothMethod tkBezierSmoothMethod = { + "bezier", + TkMakeBezierCurve, + (void (*) _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, + double *coordPtr, int numPoints, int numSteps))) + TkMakeBezierPostscript, +}; + +static void SmoothMethodCleanupProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp)); + +typedef struct SmoothAssocData { + struct SmoothAssocData *nextPtr; /* pointer to next SmoothAssocData */ + Tk_SmoothMethod smooth; /* name and functions associated with this + * option */ +} SmoothAssocData; + +void +Tk_CreateSmoothMethod(interp, smooth) + Tcl_Interp *interp; + Tk_SmoothMethod *smooth; +{ + SmoothAssocData *methods, *typePtr2, *prevPtr, *ptr; + methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothMethod", + (Tcl_InterpDeleteProc **) NULL); + + /* + * If there's already a smooth method with the given name, remove it. + */ + + for (typePtr2 = methods, prevPtr = NULL; typePtr2 != NULL; + prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) { + if (!strcmp(typePtr2->smooth.name, smooth->name)) { + if (prevPtr == NULL) { + methods = typePtr2->nextPtr; + } else { + prevPtr->nextPtr = typePtr2->nextPtr; + } + ckfree((char *) typePtr2); + break; + } + } + ptr = (SmoothAssocData *) ckalloc(sizeof(SmoothAssocData)); + ptr->smooth.name = smooth->name; + ptr->smooth.coordProc = smooth->coordProc; + ptr->smooth.postscriptProc = smooth->postscriptProc; + ptr->nextPtr = methods; + Tcl_SetAssocData(interp, "smoothMethod", SmoothMethodCleanupProc, + (ClientData) ptr); +} +/* + *---------------------------------------------------------------------- + * + * SmoothMethodCleanupProc -- + * + * This procedure is invoked whenever an interpreter is deleted + * to cleanup the smooth methods. + * + * Results: + * None. + * + * Side effects: + * Smooth methods are removed. + * + *---------------------------------------------------------------------- + */ + +static void +SmoothMethodCleanupProc(clientData, interp) + ClientData clientData; /* Points to "smoothMethod" AssocData + * for the interpreter. */ + Tcl_Interp *interp; /* Interpreter that is being deleted. */ +{ + SmoothAssocData *ptr, *methods = (SmoothAssocData *) clientData; + + while (methods != NULL) { + methods = (ptr = methods)->nextPtr; + ckfree((char *) ptr); + } +} +/* + *-------------------------------------------------------------- + * + * TkSmoothParseProc -- + * + * This procedure is invoked during option processing to handle + * the "-smooth" option. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The smooth option for a given item gets replaced by the value + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +int +TkSmoothParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + register Tk_SmoothMethod **smoothPtr = + (Tk_SmoothMethod **) (widgRec + offset); + Tk_SmoothMethod *smooth = NULL; + int b; + size_t length; + SmoothAssocData *methods; + + if (value == NULL || *value == 0) { + *smoothPtr = (Tk_SmoothMethod *) NULL; + return TCL_OK; + } + length = strlen(value); + methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothMethod", + (Tcl_InterpDeleteProc **) NULL); + while (methods != (SmoothAssocData *) NULL) { + if (strncmp(value, methods->smooth.name, length) == 0) { + if (smooth != (Tk_SmoothMethod *) NULL) { + Tcl_AppendResult(interp, "ambigeous smooth method \"", value, + "\"", (char *) NULL); + return TCL_ERROR; + } + smooth = &methods->smooth; + } + methods = methods->nextPtr; + } + if (smooth) { + *smoothPtr = smooth; + return TCL_OK; + } + + if (Tcl_GetBoolean(interp, (char *) value, &b) != TCL_OK) { + return TCL_ERROR; + } + *smoothPtr = b ? &tkBezierSmoothMethod : (Tk_SmoothMethod*) NULL; + return TCL_OK; +} +/* + *-------------------------------------------------------------- + * + * TkSmoothPrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-smooth" + * configuration option. + * + * Results: + * The return value is a string describing the smooth option for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +char * +TkSmoothPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register Tk_SmoothMethod **smoothPtr = (Tk_SmoothMethod **) (widgRec + offset); + + return (*smoothPtr) ? (*smoothPtr)->name : "0"; +} +/* + *-------------------------------------------------------------- + * + * Tk_GetDash + * + * This procedure is used to parse a string, assuming + * it is dash information. + * + * Results: + * The return value is a standard Tcl result: TCL_OK means + * that the dash information was parsed ok, and + * TCL_ERROR means it couldn't be parsed. + * + * Side effects: + * Dash information in the dash structure is updated. + * + *-------------------------------------------------------------- + */ + +int +Tk_GetDash(interp, value, dash) + Tcl_Interp *interp; /* Used for error reporting. */ + CONST char *value; /* Textual specification of dash list. */ + Tk_Dash *dash; /* Pointer to record in which to + * store dash information. */ +{ + int argc, i; + char **largv, **argv = NULL; + char *pt; + + if ((value==(char *) NULL) || (*value==0) ) { + dash->number = 0; + return TCL_OK; + } + if ((*value == '.') || (*value == ',') || + (*value == '-') || (*value == '_')) { + i = DashConvert((char *) NULL, value, -1, 0.0); + if (i>0) { + i = strlen(value); + } else { + goto badDashList; + } + if (i > sizeof(char *)) { + dash->pattern.pt = pt = (char *) ckalloc(strlen(value)); + } else { + pt = dash->pattern.array; + } + memcpy(pt,value, (unsigned int) i); + dash->number = -i; + return TCL_OK; + } + if (Tcl_SplitList(interp, (char *) value, &argc, &argv) != TCL_OK) { + Tcl_ResetResult(interp); + badDashList: + Tcl_AppendResult(interp, "bad dash list \"", value, + "\": must be a list of integers or a format like \"-..\"", + (char *) NULL); + syntaxError: + if (argv != NULL) { + ckfree((char *) argv); + } + if (ABS(dash->number) > sizeof(char *)) + ckfree((char *) dash->pattern.pt); + dash->number = 0; + return TCL_ERROR; + } + + if (ABS(dash->number) > sizeof(char *)) { + ckfree((char *) dash->pattern.pt); + } + if (argc > sizeof(char *)) { + dash->pattern.pt = pt = (char *) ckalloc((unsigned int) argc); + } else { + pt = dash->pattern.array; + } + dash->number = argc; + + largv = argv; + while(argc>0) { + if (Tcl_GetInt(interp, *largv, &i) != TCL_OK || + i < 1 || i>255) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "expected integer in the range 1..255 but got \"", + *largv, "\"", (char *) NULL); + goto syntaxError; + } + *pt++ = i; + argc--; largv++; + } + + if (argv != NULL) { + ckfree((char *) argv); + } + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CreateOutline + * + * This procedure initializes the Tk_Outline structure + * with default values. + * + * Results: + * None + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +void Tk_CreateOutline(outline) + Tk_Outline *outline; +{ + outline->gc = None; + outline->width = 1.0; + outline->activeWidth = 0.0; + outline->disabledWidth = 0.0; + outline->offset = 0; + outline->dash.number = 0; + outline->activeDash.number = 0; + outline->disabledDash.number = 0; + outline->tsoffset.flags = 0; + outline->tsoffset.xoffset = 0; + outline->tsoffset.yoffset = 0; + outline->color = NULL; + outline->activeColor = NULL; + outline->disabledColor = NULL; + outline->stipple = None; + outline->activeStipple = None; + outline->disabledStipple = None; +} + +/* + *-------------------------------------------------------------- + * + * Tk_DeleteOutline + * + * This procedure frees all memory that might be + * allocated and referenced in the Tk_Outline structure. + * + * Results: + * None + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +void Tk_DeleteOutline(display, outline) + Display *display; /* Display containing window */ + Tk_Outline *outline; +{ + if (outline->gc != None) { + Tk_FreeGC(display, outline->gc); + } + if (ABS(outline->dash.number) > sizeof(char *)) { + ckfree((char *) outline->dash.pattern.pt); + } + if (ABS(outline->activeDash.number) > sizeof(char *)) { + ckfree((char *) outline->activeDash.pattern.pt); + } + if (ABS(outline->disabledDash.number) > sizeof(char *)) { + ckfree((char *) outline->disabledDash.pattern.pt); + } + if (outline->color != NULL) { + Tk_FreeColor(outline->color); + } + if (outline->activeColor != NULL) { + Tk_FreeColor(outline->activeColor); + } + if (outline->disabledColor != NULL) { + Tk_FreeColor(outline->disabledColor); + } + if (outline->stipple != None) { + Tk_FreeBitmap(display, outline->stipple); + } + if (outline->activeStipple != None) { + Tk_FreeBitmap(display, outline->activeStipple); + } + if (outline->disabledStipple != None) { + Tk_FreeBitmap(display, outline->disabledStipple); + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_ConfigOutlineGC + * + * This procedure should be called in the canvas object + * during the configure command. The graphics context + * description in gcValues is updated according to the + * information in the dash structure, as far as possible. + * + * Results: + * The return-value is a mask, indicating which + * elements of gcValues have been updated. + * 0 means there is no outline. + * + * Side effects: + * GC information in gcValues is updated. + * + *-------------------------------------------------------------- + */ + +int Tk_ConfigOutlineGC(gcValues, canvas, item, outline) + XGCValues *gcValues; + Tk_Canvas canvas; + Tk_Item *item; + Tk_Outline *outline; +{ + int mask = 0; + double width; + Tk_Dash *dash; + XColor *color; + Pixmap stipple; + Tk_State state = item->state; + + if (outline->width < 0.0) { + outline->width = 0.0; + } + if (outline->activeWidth < 0.0) { + outline->activeWidth = 0.0; + } + if (outline->disabledWidth < 0) { + outline->disabledWidth = 0.0; + } + if (state==TK_STATE_HIDDEN) { + return 0; + } + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dash = &(outline->dash); + color = outline->color; + stipple = outline->stipple; + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (((TkCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth>width) { + width = outline->activeWidth; + } + if (outline->activeDash.number != 0) { + dash = &(outline->activeDash); + } + if (outline->activeColor!=NULL) { + color = outline->activeColor; + } + if (outline->activeStipple!=None) { + stipple = outline->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (outline->disabledWidth>0) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number != 0) { + dash = &(outline->disabledDash); + } + if (outline->disabledColor!=NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple!=None) { + stipple = outline->disabledStipple; + } + } + + if (color==NULL) { + return 0; + } + + gcValues->line_width = (int) (width + 0.5); + if (color != NULL) { + gcValues->foreground = color->pixel; + mask = GCForeground|GCLineWidth; + if (stipple != None) { + gcValues->stipple = stipple; + gcValues->fill_style = FillStippled; + mask |= GCStipple|GCFillStyle; + } + } + if (mask && (dash->number != 0)) { + gcValues->line_style = LineOnOffDash; + gcValues->dash_offset = outline->offset; + if (dash->number >= 2) { + gcValues->dashes = 4; + } else if (dash->number > 0) { + gcValues->dashes = dash->pattern.array[0]; + } else { + gcValues->dashes = (char) (4 * width); + } + mask |= GCLineStyle|GCDashList|GCDashOffset; + } + return mask; +} + +/* + *-------------------------------------------------------------- + * + * Tk_ChangeOutlineGC + * + * Updates the GC to represent the full information of + * the dash structure. Partly this is already done in + * Tk_ConfigOutlineGC(). + * This function should be called just before drawing + * the dashed item. + * + * Results: + * 1 if there is a stipple pattern. + * 0 otherwise. + * + * Side effects: + * GC is updated. + * + *-------------------------------------------------------------- + */ + +int +Tk_ChangeOutlineGC(canvas, item, outline) + Tk_Canvas canvas; + Tk_Item *item; + Tk_Outline *outline; +{ + CONST char *p; + double width; + Tk_Dash *dash; + XColor *color; + Pixmap stipple; + Tk_State state = item->state; + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dash = &(outline->dash); + color = outline->color; + stipple = outline->stipple; + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (((TkCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth > width) { + width = outline->activeWidth; + } + if (outline->activeDash.number != 0) { + dash = &(outline->activeDash); + } + if (outline->activeColor != NULL) { + color = outline->activeColor; + } + if (outline->activeStipple != None) { + stipple = outline->activeStipple; + } + } else if (state == TK_STATE_DISABLED) { + if (outline->disabledWidth > width) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number != 0) { + dash = &(outline->disabledDash); + } + if (outline->disabledColor != NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple != None) { + stipple = outline->disabledStipple; + } + } + if (color==NULL) { + return 0; + } + + if ((dash->number<-1) || ((dash->number == -1) && (dash->pattern.array[1]!=','))) { + char *q; + int i = -dash->number; + + p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + q = (char *) ckalloc(2*(unsigned int)i); + i = DashConvert(q, p, i, width); + XSetDashes(((TkCanvas *)canvas)->display, outline->gc, outline->offset, q, i); + ckfree(q); + } else if ( dash->number>2 || (dash->number==2 && + (dash->pattern.array[0]!=dash->pattern.array[1]))) { + p = (char *) (dash->number > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + XSetDashes(((TkCanvas *)canvas)->display, outline->gc, outline->offset, p, dash->number); + } + if (stipple!=None) { + int w=0; int h=0; + Tk_TSOffset *tsoffset = &outline->tsoffset; + int flags = tsoffset->flags; + if (!(flags & TK_OFFSET_INDEX) && (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) { + Tk_SizeOfBitmap(((TkCanvas *)canvas)->display, stipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset->xoffset -= w; + tsoffset->yoffset -= h; + Tk_CanvasSetOffset(canvas, outline->gc, tsoffset); + tsoffset->xoffset += w; + tsoffset->yoffset += h; + return 1; + } + return 0; +} + + +/* + *-------------------------------------------------------------- + * + * Tk_ResetOutlineGC + * + * Restores the GC to the situation before + * Tk_ChangeDashGC() was called. + * This function should be called just after the dashed + * item is drawn, because the GC is supposed to be + * read-only. + * + * Results: + * 1 if there is a stipple pattern. + * 0 otherwise. + * + * Side effects: + * GC is updated. + * + *-------------------------------------------------------------- + */ +int +Tk_ResetOutlineGC(canvas, item, outline) + Tk_Canvas canvas; + Tk_Item *item; + Tk_Outline *outline; +{ + char dashList; + double width; + Tk_Dash *dash; + XColor *color; + Pixmap stipple; + Tk_State state = item->state; + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dash = &(outline->dash); + color = outline->color; + stipple = outline->stipple; + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (((TkCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth>width) { + width = outline->activeWidth; + } + if (outline->activeDash.number != 0) { + dash = &(outline->activeDash); + } + if (outline->activeColor!=NULL) { + color = outline->activeColor; + } + if (outline->activeStipple!=None) { + stipple = outline->activeStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (outline->disabledWidth>width) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number != 0) { + dash = &(outline->disabledDash); + } + if (outline->disabledColor!=NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple!=None) { + stipple = outline->disabledStipple; + } + } + if (color==NULL) { + return 0; + } + + if ((dash->number > 2) || (dash->number < -1) || (dash->number==2 && + (dash->pattern.array[0] != dash->pattern.array[1])) || + ((dash->number == -1) && (dash->pattern.array[1] != ','))) { + if (dash->number < 0) { + dashList = (int) (4 * width + 0.5); + } else if (dash->number<3) { + dashList = dash->pattern.array[0]; + } else { + dashList = 4; + } + XSetDashes(((TkCanvas *)canvas)->display, outline->gc, + outline->offset, &dashList , 1); + } + if (stipple != None) { + XSetTSOrigin(((TkCanvas *)canvas)->display, outline->gc, 0, 0); + return 1; + } + return 0; +} + + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsOutline + * + * Creates the postscript command for the correct + * Outline-information (width, dash, color and stipple). + * + * Results: + * TCL_OK if succeeded, otherwise TCL_ERROR. + * + * Side effects: + * canvas->interp->result contains the postscript string, + * or an error message if the result was TCL_ERROR. + * + *-------------------------------------------------------------- + */ +int +Tk_CanvasPsOutline(canvas, item, outline) + Tk_Canvas canvas; + Tk_Item *item; + Tk_Outline *outline; +{ + char string[41]; + char pattern[11]; + int i; + char *ptr; + char *str = string; + char *lptr = pattern; + Tcl_Interp *interp = ((TkCanvas *)canvas)->interp; + double width; + Tk_Dash *dash; + XColor *color; + Pixmap stipple; + Tk_State state = item->state; + + width = outline->width; + dash = &(outline->dash); + color = outline->color; + stipple = outline->stipple; + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (((TkCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth > width) { + width = outline->activeWidth; + } + if (outline->activeDash.number > 0) { + dash = &(outline->activeDash); + } + if (outline->activeColor != NULL) { + color = outline->activeColor; + } + if (outline->activeStipple != None) { + stipple = outline->activeStipple; + } + } else if (state == TK_STATE_DISABLED) { + if (outline->disabledWidth > 0) { + width = outline->disabledWidth; + } + if (outline->disabledDash.number > 0) { + dash = &(outline->disabledDash); + } + if (outline->disabledColor != NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple != None) { + stipple = outline->disabledStipple; + } + } + sprintf(string, "%.15g setlinewidth\n", width); + Tcl_AppendResult(interp, string, (char *) NULL); + + if (dash->number > 10) { + str = (char *)ckalloc((unsigned int) (1 + 4*dash->number)); + } else if (dash->number < -5) { + str = (char *)ckalloc((unsigned int) (1 - 8*dash->number)); + lptr = (char *)ckalloc((unsigned int) (1 - 2*dash->number)); + } + ptr = (char *) ((ABS(dash->number) > sizeof(char *)) ) ? + dash->pattern.pt : dash->pattern.array; + if (dash->number > 0) { + char *ptr0 = ptr; + sprintf(str, "[%d", *ptr++ & 0xff); + i = dash->number-1; + while (i--) { + sprintf(str+strlen(str), " %d", *ptr++ & 0xff); + } + Tcl_AppendResult(interp, str, (char *)NULL); + if (dash->number&1) { + Tcl_AppendResult(interp, " ", str+1, (char *)NULL); + } + sprintf(str, "] %d setdash\n", outline->offset); + Tcl_AppendResult(interp, str, (char *)NULL); + ptr = ptr0; + } else if (dash->number < 0) { + if ((i = DashConvert(lptr, ptr, -dash->number, width)) != 0) { + char *lptr0 = lptr; + sprintf(str, "[%d", *lptr++ & 0xff); + while (--i) { + sprintf(str+strlen(str), " %d", *lptr++ & 0xff); + } + Tcl_AppendResult(interp, str, (char *)NULL); + sprintf(str, "] %d setdash\n", outline->offset); + Tcl_AppendResult(interp, str, (char *)NULL); + lptr = lptr0; + } else { + Tcl_AppendResult(interp, "[] 0 setdash\n", (char *)NULL); + } + } else { + Tcl_AppendResult(interp, "[] 0 setdash\n", (char *)NULL); + } + if (str != string) { + ckfree(str); + } + if (lptr != pattern) { + ckfree(lptr); + } + if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL); + if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "stroke\n", (char *) NULL); + } + + return TCL_OK; +} + + +/* + *-------------------------------------------------------------- + * + * DashConvert + * + * Converts a character-like dash-list (e.g. "-..") + * into an X11-style. l must point to a string that + * holds room to at least 2*n characters. if + * l == NULL, this function can be used for + * syntax checking only. + * + * Results: + * The length of the resulting X11 compatible + * dash-list. -1 if failed. + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +static int +DashConvert (l, p, n, width) + char *l; + CONST char *p; + int n; + double width; +{ + int result = 0; + int size, intWidth; + + if (n<0) { + n = strlen(p); + } + intWidth = (int) (width + 0.5); + if (intWidth < 1) { + intWidth = 1; + } + while (n-- && *p) { + switch (*p++) { + case ' ': + if (result) { + if (l) { + l[-1] += intWidth + 1; + } + continue; + } else { + return 0; + } + break; + case '_': + size = 8; + break; + case '-': + size = 6; + break; + case ',': + size = 4; + break; + case '.': + size = 2; + break; + default: + return -1; + } + if (l) { + *l++ = size * intWidth; + *l++ = 4 * intWidth; + } + result += 2; + } + return result; +} + diff --git a/tk/generic/tkCanvWind.c b/tk/generic/tkCanvWind.c index 1aa81620210..8a452b70d39 100644 --- a/tk/generic/tkCanvWind.c +++ b/tk/generic/tkCanvWind.c @@ -41,7 +41,12 @@ typedef struct WindowItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; @@ -50,6 +55,9 @@ static Tk_ConfigSpec configSpecs[] = { "center", Tk_Offset(WindowItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL, "0", Tk_Offset(WindowItem, height), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, @@ -68,10 +76,10 @@ static void ComputeWindowBbox _ANSI_ARGS_((Tk_Canvas canvas, WindowItem *winItemPtr)); static int ConfigureWinItem _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateWinItem _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteWinItem _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayWinItem _ANSI_ARGS_((Tk_Canvas canvas, @@ -84,7 +92,7 @@ static void TranslateWinItem _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY)); static int WinItemCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); + Tcl_Obj *CONST argv[])); static void WinItemLostSlaveProc _ANSI_ARGS_(( ClientData clientData, Tk_Window tkwin)); static void WinItemRequestProc _ANSI_ARGS_((ClientData clientData, @@ -93,8 +101,17 @@ static void WinItemStructureProc _ANSI_ARGS_(( ClientData clientData, XEvent *eventPtr)); static int WinItemToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); +static int WinItemToPostscript _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); static double WinItemToPoint _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr)); +#ifdef X_GetImage +static int xerrorhandler _ANSI_ARGS_((ClientData clientData, + XErrorEvent *e)); +#endif +static int CanvasPsWindow _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, Tk_Canvas canvas, double x, + double y, int width, int height)); /* * The structure below defines the window item type by means of procedures @@ -110,10 +127,10 @@ Tk_ItemType tkWindowType = { WinItemCoords, /* coordProc */ DeleteWinItem, /* deleteProc */ DisplayWinItem, /* displayProc */ - 1, /* alwaysRedraw */ + 1|TK_CONFIG_OBJS, /* flags */ WinItemToPoint, /* pointProc */ WinItemToArea, /* areaProc */ - (Tk_ItemPostscriptProc *) NULL, /* postscriptProc */ + WinItemToPostscript, /* postscriptProc */ ScaleWinItem, /* scaleProc */ TranslateWinItem, /* translateProc */ (Tk_ItemIndexProc *) NULL, /* indexProc */ @@ -121,7 +138,7 @@ Tk_ItemType tkWindowType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; @@ -147,7 +164,7 @@ static Tk_GeomMgr canvasGeomType = { * Results: * A standard Tcl return value. If an error occurred in * creating the item, then an error message is left in - * interp->result; in this case itemPtr is + * the interp's result; in this case itemPtr is * left uninitialized, so it can be safely freed by the * caller. * @@ -164,11 +181,24 @@ CreateWinItem(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ + Tcl_Obj *CONST argv[]; /* Arguments describing window. */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; + int i; + + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj(argv[1], NULL); + if (((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z'))) { + i = 1; + } else { + i = 2; + } + } - if (argc < 2) { + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x y ?options?\"", @@ -190,18 +220,16 @@ CreateWinItem(interp, canvas, itemPtr, argc, argv) * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &winItemPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &winItemPtr->y) != TCL_OK)) { - return TCL_ERROR; + if ((WinItemCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureWinItem(interp, canvas, itemPtr, argc-2, argv+2, 0) - != TCL_OK) { - DeleteWinItem(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureWinItem(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { + return TCL_OK; } - return TCL_OK; + + error: + DeleteWinItem(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -214,7 +242,7 @@ CreateWinItem(interp, canvas, itemPtr, argc, argv) * details on what it does. * * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. * * Side effects: * The coordinates for the given item may be changed. @@ -230,26 +258,42 @@ WinItemCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, winItemPtr->x, x); - Tcl_PrintDouble(interp, winItemPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &winItemPtr->x) - != TCL_OK) || (Tk_CanvasGetCoord(interp, canvas, argv[1], + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(winItemPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(winItemPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (argc < 3) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 2) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], &winItemPtr->x) + != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], &winItemPtr->y) != TCL_OK)) { return TCL_ERROR; } ComputeWindowBbox(canvas, winItemPtr); } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 2, got %d", argc); + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; @@ -265,7 +309,7 @@ WinItemCoords(interp, canvas, itemPtr, argc, argv) * * Results: * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. + * an error message is left in the interp's result. * * Side effects: * Configuration information may be set for itemPtr. @@ -279,7 +323,7 @@ ConfigureWinItem(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Window item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; @@ -288,8 +332,8 @@ ConfigureWinItem(interp, canvas, itemPtr, argc, argv, flags) oldWindow = winItemPtr->tkwin; canvasTkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, canvasTkwin, configSpecs, argc, argv, - (char *) winItemPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, canvasTkwin, configSpecs, argc, (char **) argv, + (char *) winItemPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -415,11 +459,15 @@ ComputeWindowBbox(canvas, winItemPtr) * recomputed. */ { int width, height, x, y; + Tk_State state = winItemPtr->header.state; x = (int) (winItemPtr->x + ((winItemPtr->x >= 0) ? 0.5 : - 0.5)); y = (int) (winItemPtr->y + ((winItemPtr->y >= 0) ? 0.5 : - 0.5)); - if (winItemPtr->tkwin == NULL) { + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if ((winItemPtr->tkwin == NULL) || (state == TK_STATE_HIDDEN)) { /* * There is no window for this item yet. Just give it a 1x1 * bounding box. Don't give it a 0x0 bounding box; there are @@ -540,11 +588,18 @@ DisplayWinItem(canvas, itemPtr, display, drawable, regionX, regionY, int width, height; short x, y; Tk_Window canvasTkwin = Tk_CanvasTkwin(canvas); + Tk_State state = itemPtr->state; if (winItemPtr->tkwin == NULL) { return; } - + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (state == TK_STATE_HIDDEN) { + Tk_UnmapWindow(winItemPtr->tkwin); + return; + } Tk_CanvasWindowCoords(canvas, (double) winItemPtr->header.x1, (double) winItemPtr->header.y1, &x, &y); width = winItemPtr->header.x2 - winItemPtr->header.x1; @@ -591,7 +646,7 @@ DisplayWinItem(canvas, itemPtr, display, drawable, regionX, regionY, * WinItemToPoint -- * * Computes the distance from a given point to a given - * rectangle, in canvas units. + * window, in canvas units. * * Results: * The return value is 0 if the point whose x and y coordinates @@ -620,7 +675,7 @@ WinItemToPoint(canvas, itemPtr, pointPtr) y2 = winItemPtr->header.y2; /* - * Point is outside rectangle. + * Point is outside window. */ if (pointPtr[0] < x1) { @@ -690,16 +745,203 @@ WinItemToArea(canvas, itemPtr, rectPtr) /* *-------------------------------------------------------------- * + * xerrorhandler -- + * + * This is a dummy function to catch X11 errors during an + * attempt to print a canvas window. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +#ifdef X_GetImage +static int +xerrorhandler(clientData, e) + ClientData clientData; + XErrorEvent *e; +{ + return 0; +} +#endif + + +/* + *-------------------------------------------------------------- + * + * WinItemToPostscript -- + * + * This procedure is called to generate Postscript for + * window items. + * + * Results: + * The return value is a standard Tcl result. If an error + * occurs in generating Postscript then an error message is + * left in interp->result, replacing whatever used to be there. + * If no error occurs, then Postscript for the item is appended + * to the result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +WinItemToPostscript(interp, canvas, itemPtr, prepass) + Tcl_Interp *interp; /* Leave Postscript or error message + * here. */ + Tk_Canvas canvas; /* Information about overall canvas. */ + Tk_Item *itemPtr; /* Item for which Postscript is + * wanted. */ + int prepass; /* 1 means this is a prepass to + * collect font information; 0 means + * final Postscript is being created.*/ +{ + WindowItem *winItemPtr = (WindowItem *)itemPtr; + + double x, y; + int width, height; + Tk_Window tkwin = winItemPtr->tkwin; + + if (prepass || winItemPtr->tkwin == NULL) { + return TCL_OK; + } + + width = Tk_Width(tkwin); + height = Tk_Height(tkwin); + + /* + * Compute the coordinates of the lower-left corner of the window, + * taking into account the anchor position for the window. + */ + + x = winItemPtr->x; + y = Tk_CanvasPsY(canvas, winItemPtr->y); + + switch (winItemPtr->anchor) { + case TK_ANCHOR_NW: y -= height; break; + case TK_ANCHOR_N: x -= width/2.0; y -= height; break; + case TK_ANCHOR_NE: x -= width; y -= height; break; + case TK_ANCHOR_E: x -= width; y -= height/2.0; break; + case TK_ANCHOR_SE: x -= width; break; + case TK_ANCHOR_S: x -= width/2.0; break; + case TK_ANCHOR_SW: break; + case TK_ANCHOR_W: y -= height/2.0; break; + case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break; + } + + return CanvasPsWindow(interp, tkwin, canvas, x, y, width, height); +} + +static int +CanvasPsWindow(interp, tkwin, canvas, x, y, width, height) + Tcl_Interp *interp; /* Leave Postscript or error message + * here. */ + Tk_Window tkwin; /* window to be printed */ + Tk_Canvas canvas; /* Information about overall canvas. */ + double x, y; /* origin of window. */ + int width, height; /* width/height of window. */ +{ + char buffer[256]; + TkWindow *winPtr; + XImage *ximage; + int result; + Tcl_DString buffer1, buffer2; +#ifdef X_GetImage + Tk_ErrorHandler handle; +#endif + + sprintf(buffer, "\n%%%% %s item (%s, %d x %d)\n%.15g %.15g translate\n", + Tk_Class(tkwin), Tk_PathName(tkwin), width, height, x, y); + Tcl_AppendResult(interp, buffer, (char *) NULL); + + /* first try if the widget has its own "postscript" command. If it + * exists, this will produce much better postscript than + * when a pixmap is used. + */ + + Tcl_DStringInit(&buffer1); + Tcl_DStringInit(&buffer2); + Tcl_DStringGetResult(interp, &buffer2); + sprintf (buffer, "%s postscript -prolog 0\n", Tk_PathName(tkwin)); + result = Tcl_Eval(interp, buffer); + Tcl_DStringGetResult(interp, &buffer1); + Tcl_DStringResult(interp, &buffer2); + Tcl_DStringFree(&buffer2); + + if (result == TCL_OK) { + Tcl_AppendResult(interp, + "50 dict begin\nsave\ngsave\n", + (char *) NULL); + sprintf (buffer, + "0 %d moveto %d 0 rlineto 0 -%d rlineto -%d", + height, width, height, width); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " 0 rlineto closepath\n", + "1.000 1.000 1.000 setrgbcolor AdjustColor\nfill\ngrestore\n", + Tcl_DStringValue(&buffer1), "\nrestore\nend\n\n\n", + (char *) NULL); + Tcl_DStringFree(&buffer1); + + for (winPtr = ((TkWindow *) tkwin)->childList; winPtr != NULL; + winPtr = winPtr->nextPtr) { + if (Tk_IsMapped(winPtr)) { +/* printf("child window: %s\n", winPtr->pathName);*/ + } + } + return result; + } + Tcl_DStringFree(&buffer1); + + /* + * If the window is off the screen it will generate an BadMatch/XError + * We catch any BadMatch errors here + */ +#ifdef X_GetImage + handle = Tk_CreateErrorHandler(Tk_Display(tkwin), BadMatch, + X_GetImage, -1, xerrorhandler, (ClientData) tkwin); +#endif + + /* + * Generate an XImage from the window. We can then read pixel + * values out of the XImage. + */ + + ximage = XGetImage(Tk_Display(tkwin), Tk_WindowId(tkwin), 0, 0, + (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); + +#ifdef X_GetImage + Tk_DeleteErrorHandler(handle); +#endif + + if (ximage == (XImage*) NULL) { + return TCL_OK; + } + + result = TkPostscriptImage(interp, tkwin, + ((TkCanvas *)canvas)->psInfo, ximage, 0, 0, width, height); + + XDestroyImage(ximage); + return result; +} + +/* + *-------------------------------------------------------------- + * * ScaleWinItem -- * - * This procedure is invoked to rescale a rectangle or oval - * item. + * This procedure is invoked to rescale a window item. * * Results: * None. * * Side effects: - * The rectangle or oval referred to by itemPtr is rescaled + * The window referred to by itemPtr is rescaled * so that the following transformation is applied to all * point coordinates: * x' = originX + scaleX*(x-originX) @@ -710,9 +952,9 @@ WinItemToArea(canvas, itemPtr, rectPtr) static void ScaleWinItem(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing rectangle. */ - Tk_Item *itemPtr; /* Rectangle to be scaled. */ - double originX, originY; /* Origin about which to scale rect. */ + Tk_Canvas canvas; /* Canvas containing window. */ + Tk_Item *itemPtr; /* Window to be scaled. */ + double originX, originY; /* Origin about which to scale window. */ double scaleX; /* Amount to scale in X direction. */ double scaleY; /* Amount to scale in Y direction. */ { @@ -734,16 +976,15 @@ ScaleWinItem(canvas, itemPtr, originX, originY, scaleX, scaleY) * * TranslateWinItem -- * - * This procedure is called to move a rectangle or oval by a - * given amount. + * This procedure is called to move a window by a given amount. * * Results: * None. * * Side effects: - * The position of the rectangle or oval is offset by - * (xDelta, yDelta), and the bounding box is updated in the - * generic part of the item structure. + * The position of the window is offset by (xDelta, yDelta), + * and the bounding box is updated in the generic part of the + * item structure. * *-------------------------------------------------------------- */ @@ -860,3 +1101,4 @@ WinItemLostSlaveProc(clientData, tkwin) Tk_UnmapWindow(winItemPtr->tkwin); winItemPtr->tkwin = NULL; } + diff --git a/tk/generic/tkCanvas.c b/tk/generic/tkCanvas.c index 9455014c030..aea03485631 100644 --- a/tk/generic/tkCanvas.c +++ b/tk/generic/tkCanvas.c @@ -6,8 +6,8 @@ * objects such as rectangles, lines, and texts. * * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. - * Copyright (c) 1998 by Scriptics Corporation. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -15,6 +15,8 @@ * RCS: @(#) $Id$ */ +/* #define USE_OLD_TAG_SEARCH 1 */ + #include "default.h" #include "tkInt.h" #include "tkPort.h" @@ -24,6 +26,7 @@ * See tkCanvas.h for key data structures used to implement canvases. */ +#ifdef USE_OLD_TAG_SEARCH /* * The structure defined below is used to keep track of a tag search * in progress. No field should be accessed by anyone other than @@ -43,6 +46,65 @@ typedef struct TagSearch { * return NULL. */ } TagSearch; +#else /* USE_OLD_TAG_SEARCH */ +/* + * The structure defined below is used to keep track of a tag search + * in progress. No field should be accessed by anyone other than + * TagSearchScan, TagSearchFirst, TagSearchNext, + * TagSearchScanExpr, TagSearchEvalExpr, + * TagSearchExprInit, TagSearchExprDestroy, + * TagSearchDestroy. + * ( + * Not quite accurate: the TagSearch structure is also accessed from: + * CanvasWidgetCmd, FindItems, RelinkItems + * The only instances of the structure are owned by: + * CanvasWidgetCmd + * CanvasWidgetCmd is the only function that calls: + * FindItems, RelinkItems + * CanvasWidgetCmd, FindItems, RelinkItems, are the only functions that call + * TagSearch* + * ) + */ + +typedef struct TagSearch { + TkCanvas *canvasPtr; /* Canvas widget being searched. */ + Tk_Item *currentPtr; /* Pointer to last item returned. */ + Tk_Item *lastPtr; /* The item right before the currentPtr + * is tracked so if the currentPtr is + * deleted we don't have to start from the + * beginning. */ + int searchOver; /* Non-zero means NextItem should always + * return NULL. */ + int type; /* search type */ + int id; /* item id for searches by id */ + + char *string; /* tag expression string */ + int stringIndex; /* current position in string scan */ + int stringLength; /* length of tag expression string */ + + char *rewritebuffer; /* tag string (after removing escapes) */ + unsigned int rewritebufferAllocated; /* available space for rewrites */ + + TagSearchExpr *expr; /* compiled tag expression */ +} TagSearch; +#endif /* USE_OLD_TAG_SEARCH */ + +/* + * Custom option for handling "-state" and "-offset" + */ + +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, + (ClientData) NULL /* only "normal" and "disabled" */ +}; + +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, + (ClientData) TK_OFFSET_RELATIVE +}; + /* * Information used for argv parsing. */ @@ -90,6 +152,9 @@ static Tk_ConfigSpec configSpecs[] = { DEF_CANVAS_INSERT_ON_TIME, Tk_Offset(TkCanvas, insertOnTime), 0}, {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", DEF_CANVAS_INSERT_WIDTH, Tk_Offset(TkCanvas, textInfo.insertWidth), 0}, + {TK_CONFIG_CUSTOM, "-offset", "offset", "Offset", "0,0", + Tk_Offset(TkCanvas, tsoffset),TK_CONFIG_DONT_SET_DEFAULT, + &offsetOption}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_CANVAS_RELIEF, Tk_Offset(TkCanvas, relief), 0}, {TK_CONFIG_STRING, "-scrollregion", "scrollRegion", "ScrollRegion", @@ -113,6 +178,9 @@ static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(TkCanvas, textInfo.selFgColorPtr), TK_CONFIG_MONO_ONLY}, + {TK_CONFIG_CUSTOM, "-state", "state", "State", + "normal", Tk_Offset(TkCanvas, canvas_state), TK_CONFIG_DONT_SET_DEFAULT, + &stateOption}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_CANVAS_TAKE_FOCUS, Tk_Offset(TkCanvas, takeFocus), TK_CONFIG_NULL_OK}, @@ -143,27 +211,30 @@ static Tk_ConfigSpec configSpecs[] = { static Tk_ItemType *typeList = NULL; /* NULL means initialization hasn't * been done yet. */ +#ifndef USE_OLD_TAG_SEARCH /* - * Standard item types provided by Tk: + * Uids for operands in compiled advanced tag search expressions + * Initialization is done by InitCanvas() */ - -extern Tk_ItemType tkArcType, tkBitmapType, tkImageType, tkLineType; -extern Tk_ItemType tkOvalType, tkPolygonType; -extern Tk_ItemType tkRectangleType, tkTextType, tkWindowType; - -/* - * Various Tk_Uid's used by this module (set up during initialization): - */ - static Tk_Uid allUid = NULL; static Tk_Uid currentUid = NULL; +static Tk_Uid andUid = NULL; +static Tk_Uid orUid = NULL; +static Tk_Uid xorUid = NULL; +static Tk_Uid parenUid = NULL; +static Tk_Uid negparenUid = NULL; +static Tk_Uid endparenUid = NULL; +static Tk_Uid tagvalUid = NULL; +static Tk_Uid negtagvalUid = NULL; +#endif /* USE_OLD_TAG_SEARCH */ /* - * Statistics counters: + * Standard item types provided by Tk: */ -static int numIdSearches; -static int numSlowSearches; +extern Tk_ItemType tkArcType, tkBitmapType, tkImageType, tkLineType; +extern Tk_ItemType tkOvalType, tkPolygonType; +extern Tk_ItemType tkRectangleType, tkTextType, tkWindowType; /* * Prototypes for procedures defined later in this file: @@ -194,34 +265,65 @@ static void CanvasSetOrigin _ANSI_ARGS_((TkCanvas *canvasPtr, static void CanvasUpdateScrollbars _ANSI_ARGS_(( TkCanvas *canvasPtr)); static int CanvasWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); + Tcl_Interp *interp, int argc, Tcl_Obj *CONST *argv)); static void CanvasWorldChanged _ANSI_ARGS_(( ClientData instanceData)); static int ConfigureCanvas _ANSI_ARGS_((Tcl_Interp *interp, - TkCanvas *canvasPtr, int argc, char **argv, + TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv, int flags)); static void DestroyCanvas _ANSI_ARGS_((char *memPtr)); static void DisplayCanvas _ANSI_ARGS_((ClientData clientData)); static void DoItem _ANSI_ARGS_((Tcl_Interp *interp, Tk_Item *itemPtr, Tk_Uid tag)); +static void EventuallyRedrawItem _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr)); +#ifdef USE_OLD_TAG_SEARCH +static int FindItems _ANSI_ARGS_((Tcl_Interp *interp, + TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv, + Tcl_Obj *newTagObj, int first)); +#else /* USE_OLD_TAG_SEARCH */ static int FindItems _ANSI_ARGS_((Tcl_Interp *interp, - TkCanvas *canvasPtr, int argc, char **argv, - char *newTag, char *cmdName, char *option)); + TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv, + Tcl_Obj *newTagObj, int first, + TagSearch **searchPtrPtr)); +#endif /* USE_OLD_TAG_SEARCH */ static int FindArea _ANSI_ARGS_((Tcl_Interp *interp, - TkCanvas *canvasPtr, char **argv, Tk_Uid uid, + TkCanvas *canvasPtr, Tcl_Obj *CONST *argv, Tk_Uid uid, int enclosed)); static double GridAlign _ANSI_ARGS_((double coord, double spacing)); +static char** GetStringsFromObjs _ANSI_ARGS_((int argc, + Tcl_Obj *CONST *objv)); static void InitCanvas _ANSI_ARGS_((void)); +#ifdef USE_OLD_TAG_SEARCH static Tk_Item * NextItem _ANSI_ARGS_((TagSearch *searchPtr)); +#endif /* USE_OLD_TAG_SEARCH */ static void PickCurrentItem _ANSI_ARGS_((TkCanvas *canvasPtr, XEvent *eventPtr)); static void PrintScrollFractions _ANSI_ARGS_((int screen1, int screen2, int object1, int object2, char *string)); +#ifdef USE_OLD_TAG_SEARCH static void RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr, - char *tag, Tk_Item *prevPtr)); + Tcl_Obj *tag, Tk_Item *prevPtr)); static Tk_Item * StartTagSearch _ANSI_ARGS_((TkCanvas *canvasPtr, - char *tag, TagSearch *searchPtr)); + Tcl_Obj *tag, TagSearch *searchPtr)); +#else /* USE_OLD_TAG_SEARCH */ +static int RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr, + Tcl_Obj *tag, Tk_Item *prevPtr, + TagSearch **searchPtrPtr)); +static void TagSearchExprInit _ANSI_ARGS_ (( + TagSearchExpr **exprPtrPtr)); +static void TagSearchExprDestroy _ANSI_ARGS_((TagSearchExpr *expr)); +static void TagSearchDestroy _ANSI_ARGS_((TagSearch *searchPtr)); +static int TagSearchScan _ANSI_ARGS_((TkCanvas *canvasPtr, + Tcl_Obj *tag, TagSearch **searchPtrPtr)); +static int TagSearchScanExpr _ANSI_ARGS_((Tcl_Interp *interp, + TagSearch *searchPtr, TagSearchExpr *expr)); +static int TagSearchEvalExpr _ANSI_ARGS_((TagSearchExpr *expr, + Tk_Item *itemPtr)); +static Tk_Item * TagSearchFirst _ANSI_ARGS_((TagSearch *searchPtr)); +static Tk_Item * TagSearchNext _ANSI_ARGS_((TagSearch *searchPtr)); +#endif /* USE_OLD_TAG_SEARCH */ /* * The structure below defines canvas class behavior by means of procedures @@ -238,7 +340,7 @@ static TkClassProcs canvasClass = { /* *-------------------------------------------------------------- * - * Tk_CanvasCmd -- + * Tk_CanvasObjCmd -- * * This procedure is invoked to process the "canvas" Tcl * command. See the user documentation for details on what @@ -254,12 +356,12 @@ static TkClassProcs canvasClass = { */ int -Tk_CanvasCmd(clientData, interp, argc, argv) +Tk_CanvasObjCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + Tcl_Obj *CONST argv[]; /* Argument objects. */ { Tk_Window tkwin = (Tk_Window) clientData; TkCanvas *canvasPtr; @@ -270,12 +372,12 @@ Tk_CanvasCmd(clientData, interp, argc, argv) } if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); + Tcl_WrongNumArgs(interp, 1, argv, "pathName ?options?"); return TCL_ERROR; } - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); + new = Tk_CreateWindowFromPath(interp, tkwin, + Tcl_GetString(argv[1]), (char *) NULL); if (new == NULL) { return TCL_ERROR; } @@ -290,7 +392,7 @@ Tk_CanvasCmd(clientData, interp, argc, argv) canvasPtr->tkwin = new; canvasPtr->display = Tk_Display(new); canvasPtr->interp = interp; - canvasPtr->widgetCmd = Tcl_CreateCommand(interp, + canvasPtr->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd, (ClientData) canvasPtr, CanvasCmdDeletedProc); canvasPtr->firstItemPtr = NULL; @@ -354,9 +456,16 @@ Tk_CanvasCmd(clientData, interp, argc, argv) canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(new)); canvasPtr->flags = 0; canvasPtr->nextId = 1; - canvasPtr->psInfoPtr = NULL; + canvasPtr->psInfo = NULL; + canvasPtr->canvas_state = TK_STATE_NORMAL; + canvasPtr->tsoffset.flags = 0; + canvasPtr->tsoffset.xoffset = 0; + canvasPtr->tsoffset.yoffset = 0; +#ifndef USE_OLD_TAG_SEARCH + canvasPtr->bindTagExprs = NULL; +#endif Tcl_InitHashTable(&canvasPtr->idTable, TCL_ONE_WORD_KEYS); - + Tk_SetClass(canvasPtr->tkwin, "Canvas"); TkSetClassProcs(canvasPtr->tkwin, &canvasClass, (ClientData) canvasPtr); Tk_CreateEventHandler(canvasPtr->tkwin, @@ -372,7 +481,7 @@ Tk_CanvasCmd(clientData, interp, argc, argv) goto error; } - interp->result = Tk_PathName(canvasPtr->tkwin); + Tcl_SetResult(interp, Tk_PathName(canvasPtr->tkwin), TCL_STATIC); return TCL_OK; error: @@ -404,50 +513,93 @@ CanvasWidgetCmd(clientData, interp, argc, argv) * widget. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + Tcl_Obj *CONST argv[]; /* Argument objects. */ { TkCanvas *canvasPtr = (TkCanvas *) clientData; - size_t length; + unsigned int length; int c, result; Tk_Item *itemPtr = NULL; /* Initialization needed only to * prevent compiler warning. */ +#ifdef USE_OLD_TAG_SEARCH TagSearch search; +#else /* USE_OLD_TAG_SEARCH */ + TagSearch *searchPtr = NULL; /* Allocated by first TagSearchScan + * Freed by TagSearchDestroy */ +#endif /* USE_OLD_TAG_SEARCH */ + + int index; + static char *optionStrings[] = { + "addtag", "bbox", "bind", "canvasx", + "canvasy", "cget", "configure", "coords", + "create", "dchars", "delete", "dtag", + "find", "focus", "gettags", "icursor", + "index", "insert", "itemcget", "itemconfigure", + "lower", "move", "postscript", "raise", + "scale", "scan", "select", "type", + "xview", "yview", + NULL + }; + enum options { + CANV_ADDTAG, CANV_BBOX, CANV_BIND, CANV_CANVASX, + CANV_CANVASY, CANV_CGET, CANV_CONFIGURE, CANV_COORDS, + CANV_CREATE, CANV_DCHARS, CANV_DELETE, CANV_DTAG, + CANV_FIND, CANV_FOCUS, CANV_GETTAGS, CANV_ICURSOR, + CANV_INDEX, CANV_INSERT, CANV_ITEMCGET, CANV_ITEMCONFIGURE, + CANV_LOWER, CANV_MOVE, CANV_POSTSCRIPT,CANV_RAISE, + CANV_SCALE, CANV_SCAN, CANV_SELECT, CANV_TYPE, + CANV_XVIEW, CANV_YVIEW + }; if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); + Tcl_WrongNumArgs(interp, 1, argv, "option ?arg arg ...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, argv[1], optionStrings, "option", 0, + &index) != TCL_OK) { return TCL_ERROR; } Tcl_Preserve((ClientData) canvasPtr); + result = TCL_OK; - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (strncmp(argv[1], "addtag", length) == 0)) { + switch ((enum options) index) { + case CANV_ADDTAG: { if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " addtags tag searchCommand ?arg arg ...?\"", - (char *) NULL); - goto error; - } - result = FindItems(interp, canvasPtr, argc-3, argv+3, argv[2], argv[0], - " addtag tag"); - } else if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0) - && (length >= 2)) { + Tcl_WrongNumArgs(interp, 2, argv, "tag searchCommand ?arg arg ...?"); + result = TCL_ERROR; + goto done; + } +#ifdef USE_OLD_TAG_SEARCH + result = FindItems(interp, canvasPtr, argc, argv, argv[2], 3); +#else /* USE_OLD_TAG_SEARCH */ + result = FindItems(interp, canvasPtr, argc, argv, argv[2], 3, &searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + + case CANV_BBOX: { int i, gotAny; int x1 = 0, y1 = 0, x2 = 0, y2 = 0; /* Initializations needed * only to prevent compiler * warnings. */ if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " bbox tagOrId ?tagOrId ...?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?tagOrId ...?"); + result = TCL_ERROR; + goto done; } gotAny = 0; for (i = 2; i < argc; i++) { +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[i], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ + if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2)) { continue; @@ -475,17 +627,20 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } } if (gotAny) { - sprintf(interp->result, "%d %d %d %d", x1, y1, x2, y2); - } - } else if ((c == 'b') && (strncmp(argv[1], "bind", length) == 0) - && (length >= 2)) { + char buf[TCL_INTEGER_SPACE * 4]; + + sprintf(buf, "%d %d %d %d", x1, y1, x2, y2); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + } + break; + } + case CANV_BIND: { ClientData object; if ((argc < 3) || (argc > 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " bind tagOrId ?sequence? ?command?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?sequence? ?command?"); + result = TCL_ERROR; + goto done; } /* @@ -494,12 +649,13 @@ CanvasWidgetCmd(clientData, interp, argc, argv) */ object = 0; - if (isdigit(UCHAR(argv[2][0]))) { +#ifdef USE_OLD_TAG_SEARCH + if (isdigit(UCHAR(Tcl_GetString(argv[2])[0]))) { int id; char *end; Tcl_HashEntry *entryPtr; - id = strtoul(argv[2], &end, 0); + id = strtoul(Tcl_GetString(argv[2]), &end, 0); if (*end != 0) { goto bindByTag; } @@ -510,14 +666,38 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } if (object == 0) { - Tcl_AppendResult(interp, "item \"", argv[2], + Tcl_AppendResult(interp, "item \"", Tcl_GetString(argv[2]), "\" doesn't exist", (char *) NULL); - goto error; + result = TCL_ERROR; + goto done; } } else { bindByTag: - object = (ClientData) Tk_GetUid(argv[2]); + object = (ClientData) Tk_GetUid(Tcl_GetString(argv[2])); + } +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + if (searchPtr->type == 1) { + Tcl_HashEntry *entryPtr; + + entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) searchPtr->id); + if (entryPtr != NULL) { + itemPtr = (Tk_Item *) Tcl_GetHashValue(entryPtr); + object = (ClientData) itemPtr; + } + + if (object == 0) { + Tcl_AppendResult(interp, "item \"", Tcl_GetString(argv[2]), + "\" doesn't exist", (char *) NULL); + result = TCL_ERROR; + goto done; + } + } else { + object = (ClientData) searchPtr->expr->uid; } +#endif /* USE_OLD_TAG_SEARCH */ /* * Make a binding table if the canvas doesn't already have @@ -531,20 +711,51 @@ CanvasWidgetCmd(clientData, interp, argc, argv) if (argc == 5) { int append = 0; unsigned long mask; + char* argv4 = Tcl_GetStringFromObj(argv[4],NULL); - if (argv[4][0] == 0) { + if (argv4[0] == 0) { result = Tk_DeleteBinding(interp, canvasPtr->bindingTable, - object, argv[3]); + object, Tcl_GetStringFromObj(argv[3], NULL)); goto done; } - if (argv[4][0] == '+') { - argv[4]++; +#ifndef USE_OLD_TAG_SEARCH + if (searchPtr->type == 4) { + /* + * if new tag expression, then insert in linked list + */ + TagSearchExpr *expr, **lastPtr; + + lastPtr = &(canvasPtr->bindTagExprs); + while ((expr = *lastPtr) != NULL) { + if (expr->uid == searchPtr->expr->uid) { + break; + } + lastPtr = &(expr->next); + } + if (!expr) { + /* + * transfer ownership of expr to bindTagExprs list + */ + *lastPtr = searchPtr->expr; + searchPtr->expr->next = NULL; + + /* + * flag in TagSearch that expr has changed ownership + * so that TagSearchDestroy doesn't try to free it + */ + searchPtr->expr = NULL; + } + } +#endif /* not USE_OLD_TAG_SEARCH */ + if (argv4[0] == '+') { + argv4++; append = 1; } mask = Tk_CreateBinding(interp, canvasPtr->bindingTable, - object, argv[3], argv[4], append); + object, Tcl_GetStringFromObj(argv[3],NULL), argv4, append); if (mask == 0) { - goto error; + result = TCL_ERROR; + goto done; } if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask |Button2MotionMask|Button3MotionMask|Button4MotionMask @@ -552,140 +763,183 @@ CanvasWidgetCmd(clientData, interp, argc, argv) |EnterWindowMask|LeaveWindowMask|KeyPressMask |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) { Tk_DeleteBinding(interp, canvasPtr->bindingTable, - object, argv[3]); + object, Tcl_GetStringFromObj(argv[3], NULL)); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "requested illegal events; ", "only key, button, motion, enter, leave, and virtual ", "events may be used", (char *) NULL); - goto error; + result = TCL_ERROR; + goto done; } } else if (argc == 4) { char *command; command = Tk_GetBinding(interp, canvasPtr->bindingTable, - object, argv[3]); + object, Tcl_GetStringFromObj(argv[3], NULL)); if (command == NULL) { - goto error; + char *string; + + string = Tcl_GetStringResult(interp); + /* + * Ignore missing binding errors. This is a special hack + * that relies on the error message returned by FindSequence + * in tkBind.c. + */ + + if (string[0] != '\0') { + result = TCL_ERROR; + goto done; + } else { + Tcl_ResetResult(interp); + } + } else { + Tcl_SetResult(interp, command, TCL_STATIC); } - interp->result = command; } else { Tk_GetAllBindings(interp, canvasPtr->bindingTable, object); } - } else if ((c == 'c') && (strcmp(argv[1], "canvasx") == 0)) { + break; + } + case CANV_CANVASX: { int x; double grid; + char buf[TCL_DOUBLE_SPACE]; if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " canvasx screenx ?gridspacing?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "screenx ?gridspacing?"); + result = TCL_ERROR; + goto done; } - if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &x) != TCL_OK) { - goto error; + if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, argv[2], &x) != TCL_OK) { + result = TCL_ERROR; + goto done; } if (argc == 4) { - if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], + if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3], &grid) != TCL_OK) { - goto error; + result = TCL_ERROR; + goto done; } } else { grid = 0.0; } x += canvasPtr->xOrigin; - Tcl_PrintDouble(interp, GridAlign((double) x, grid), interp->result); - } else if ((c == 'c') && (strcmp(argv[1], "canvasy") == 0)) { + Tcl_PrintDouble(interp, GridAlign((double) x, grid), buf); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + break; + } + case CANV_CANVASY: { int y; double grid; + char buf[TCL_DOUBLE_SPACE]; if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " canvasy screeny ?gridspacing?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "screeny ?gridspacing?"); + result = TCL_ERROR; + goto done; } - if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &y) != TCL_OK) { - goto error; + if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, argv[2], &y) != TCL_OK) { + result = TCL_ERROR; + goto done; } if (argc == 4) { - if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, + if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3], &grid) != TCL_OK) { - goto error; + result = TCL_ERROR; + goto done; } } else { grid = 0.0; } y += canvasPtr->yOrigin; - Tcl_PrintDouble(interp, GridAlign((double) y, grid), interp->result); - } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { + Tcl_PrintDouble(interp, GridAlign((double) y, grid), buf); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + break; + } + case CANV_CGET: { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "option"); + result = TCL_ERROR; + goto done; } result = Tk_ConfigureValue(interp, canvasPtr->tkwin, configSpecs, - (char *) canvasPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 3)) { + (char *) canvasPtr, Tcl_GetString(argv[2]), 0); + break; + } + case CANV_CONFIGURE: { if (argc == 2) { result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs, (char *) canvasPtr, (char *) NULL, 0); } else if (argc == 3) { result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs, - (char *) canvasPtr, argv[2], 0); + (char *) canvasPtr, Tcl_GetString(argv[2]), 0); } else { result = ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, TK_CONFIG_ARGV_ONLY); } - } else if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0) - && (length >= 3)) { + break; + } + case CANV_COORDS: { if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " coords tagOrId ?x y x y ...?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?x y x y ...?"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH itemPtr = StartTagSearch(canvasPtr, argv[2], &search); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + itemPtr = TagSearchFirst(searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr != NULL) { if (argc != 3) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } if (itemPtr->typePtr->coordProc != NULL) { + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { result = (*itemPtr->typePtr->coordProc)(interp, (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3); + } else { + char **args = GetStringsFromObjs(argc-3, argv+3); + result = (*itemPtr->typePtr->coordProc)(interp, + (Tk_Canvas) canvasPtr, itemPtr, argc-3, (Tcl_Obj **) args); + if (args) ckfree((char *) args); + } } if (argc != 3) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } } - } else if ((c == 'c') && (strncmp(argv[1], "create", length) == 0) - && (length >= 2)) { + break; + } + case CANV_CREATE: { Tk_ItemType *typePtr; Tk_ItemType *matchPtr = NULL; Tk_Item *itemPtr; + char buf[TCL_INTEGER_SPACE]; int isNew = 0; Tcl_HashEntry *entryPtr; - + char *arg; + if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " create type ?arg arg ...?\"", (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "type ?arg arg ...?"); + result = TCL_ERROR; + goto done; } - c = argv[2][0]; - length = strlen(argv[2]); + arg = Tcl_GetStringFromObj(argv[2], (int *) &length); + c = arg[0]; for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr) { if ((c == typePtr->name[0]) - && (strncmp(argv[2], typePtr->name, length) == 0)) { + && (strncmp(arg, typePtr->name, length) == 0)) { if (matchPtr != NULL) { badType: Tcl_AppendResult(interp, "unknown or ambiguous item type \"", - argv[2], "\"", (char *) NULL); - goto error; + arg, "\"", (char *) NULL); + result = TCL_ERROR; + goto done; } matchPtr = typePtr; } @@ -701,10 +955,21 @@ CanvasWidgetCmd(clientData, interp, argc, argv) itemPtr->tagSpace = TK_TAG_SPACE; itemPtr->numTags = 0; itemPtr->typePtr = typePtr; - if ((*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argc-3, argv+3) != TCL_OK) { + itemPtr->state = TK_STATE_NULL; + itemPtr->redraw_flags = 0; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = (*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr, + itemPtr, argc-3, argv+3); + } else { + char **args = GetStringsFromObjs(argc-3, argv+3); + result = (*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr, + itemPtr, argc-3, (Tcl_Obj **) args); + if (args) ckfree((char *) args); + } + if (result != TCL_OK) { ckfree((char *) itemPtr); - goto error; + result = TCL_ERROR; + goto done; } itemPtr->nextPtr = NULL; entryPtr = Tcl_CreateHashEntry(&canvasPtr->idTable, @@ -719,35 +984,56 @@ CanvasWidgetCmd(clientData, interp, argc, argv) canvasPtr->lastItemPtr->nextPtr = itemPtr; } canvasPtr->lastItemPtr = itemPtr; - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + itemPtr->redraw_flags |= FORCE_REDRAW; + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; - sprintf(interp->result, "%d", itemPtr->id); - } else if ((c == 'd') && (strncmp(argv[1], "dchars", length) == 0) - && (length >= 2)) { + sprintf(buf, "%d", itemPtr->id); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + break; + } + case CANV_DCHARS: { int first, last; + int x1,x2,y1,y2; if ((argc != 4) && (argc != 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " dchars tagOrId first ?last?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId first ?last?"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if ((itemPtr->typePtr->indexProc == NULL) || (itemPtr->typePtr->dCharsProc == NULL)) { continue; } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &first) != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[3], &first); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &first); + } + if (result != TCL_OK) { + goto done; } if (argc == 5) { - if ((*itemPtr->typePtr->indexProc)(interp, - (Tk_Canvas) canvasPtr, itemPtr, argv[4], &last) - != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[4], &last); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[4], NULL), &last); + } + if (result != TCL_OK) { + goto done; } } else { last = first; @@ -756,26 +1042,40 @@ CanvasWidgetCmd(clientData, interp, argc, argv) /* * Redraw both item's old and new areas: it's possible * that a delete could result in a new area larger than - * the old area. + * the old area. Except if the insertProc sets the + * TK_ITEM_DONT_REDRAW flag, nothing more needs to be done. */ - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + x1 = itemPtr->x1; y1 = itemPtr->y1; + x2 = itemPtr->x2; y2 = itemPtr->y2; + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; (*itemPtr->typePtr->dCharsProc)((Tk_Canvas) canvasPtr, itemPtr, first, last); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) { + Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, + x1, y1, x2, y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); + } + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; } - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0) - && (length >= 2)) { + break; + } + case CANV_DELETE: { int i; Tcl_HashEntry *entryPtr; for (i = 2; i < argc; i++) { +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[i], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); if (canvasPtr->bindingTable != NULL) { Tk_DeleteAllBindings(canvasPtr->bindingTable, (ClientData) itemPtr); @@ -824,24 +1124,32 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } } } - } else if ((c == 'd') && (strncmp(argv[1], "dtag", length) == 0) - && (length >= 2)) { + break; + } + case CANV_DTAG: { Tk_Uid tag; int i; if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " dtag tagOrId ?tagToDelete?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?tagToDelete?"); + result = TCL_ERROR; + goto done; } if (argc == 4) { - tag = Tk_GetUid(argv[3]); + tag = Tk_GetUid(Tcl_GetStringFromObj(argv[3], NULL)); } else { - tag = Tk_GetUid(argv[2]); + tag = Tk_GetUid(Tcl_GetStringFromObj(argv[2], NULL)); } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ for (i = itemPtr->numTags-1; i >= 0; i--) { if (itemPtr->tagPtr[i] == tag) { itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1]; @@ -849,41 +1157,55 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } } } - } else if ((c == 'f') && (strncmp(argv[1], "find", length) == 0) - && (length >= 2)) { + break; + } + case CANV_FIND: { if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " find searchCommand ?arg arg ...?\"", - (char *) NULL); - goto error; - } - result = FindItems(interp, canvasPtr, argc-2, argv+2, (char *) NULL, - argv[0]," find"); - } else if ((c == 'f') && (strncmp(argv[1], "focus", length) == 0) - && (length >= 2)) { + Tcl_WrongNumArgs(interp, 2, argv, "searchCommand ?arg arg ...?"); + result = TCL_ERROR; + goto done; + } +#ifdef USE_OLD_TAG_SEARCH + result = FindItems(interp, canvasPtr, argc, argv, (Tcl_Obj *) NULL, 2); +#else /* USE_OLD_TAG_SEARCH */ + result = FindItems(interp, canvasPtr, argc, argv, + (Tcl_Obj *) NULL, 2, &searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + case CANV_FOCUS: { if (argc > 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " focus ?tagOrId?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "?tagOrId?"); + result = TCL_ERROR; + goto done; } itemPtr = canvasPtr->textInfo.focusItemPtr; if (argc == 2) { if (itemPtr != NULL) { - sprintf(interp->result, "%d", itemPtr->id); + char buf[TCL_INTEGER_SPACE]; + + sprintf(buf, "%d", itemPtr->id); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } goto done; } if ((itemPtr != NULL) && (canvasPtr->textInfo.gotFocus)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } - if (argv[2][0] == 0) { + if (Tcl_GetStringFromObj(argv[2], NULL)[0] == 0) { canvasPtr->textInfo.focusItemPtr = NULL; goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr->typePtr->icursorProc != NULL) { break; } @@ -893,134 +1215,214 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } canvasPtr->textInfo.focusItemPtr = itemPtr; if (canvasPtr->textInfo.gotFocus) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } - } else if ((c == 'g') && (strncmp(argv[1], "gettags", length) == 0)) { + break; + } + case CANV_GETTAGS: { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " gettags tagOrId\"", (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH itemPtr = StartTagSearch(canvasPtr, argv[2], &search); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + itemPtr = TagSearchFirst(searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr != NULL) { int i; for (i = 0; i < itemPtr->numTags; i++) { Tcl_AppendElement(interp, (char *) itemPtr->tagPtr[i]); } } - } else if ((c == 'i') && (strncmp(argv[1], "icursor", length) == 0) - && (length >= 2)) { + break; + } + case CANV_ICURSOR: { int index; if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " icursor tagOrId index\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId index"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if ((itemPtr->typePtr->indexProc == NULL) || (itemPtr->typePtr->icursorProc == NULL)) { goto done; } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &index) != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[3], &index); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &index); + } + if (result != TCL_OK) { + goto done; } (*itemPtr->typePtr->icursorProc)((Tk_Canvas) canvasPtr, itemPtr, index); if ((itemPtr == canvasPtr->textInfo.focusItemPtr) && (canvasPtr->textInfo.cursorOn)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } } - } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0) - && (length >= 3)) { + break; + } + case CANV_INDEX: { + int index; + char buf[TCL_INTEGER_SPACE]; if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " index tagOrId string\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId string"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr->typePtr->indexProc != NULL) { break; } } if (itemPtr == NULL) { Tcl_AppendResult(interp, "can't find an indexable item \"", - argv[2], "\"", (char *) NULL); - goto error; + Tcl_GetStringFromObj(argv[2], NULL), "\"", (char *) NULL); + result = TCL_ERROR; + goto done; } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &index) != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[3], &index); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &index); } - sprintf(interp->result, "%d", index); - } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0) - && (length >= 3)) { + if (result != TCL_OK) { + goto done; + } + sprintf(buf, "%d", index); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + break; + } + case CANV_INSERT: { int beforeThis; + int x1,x2,y1,y2; if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " insert tagOrId beforeThis string\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId beforeThis string"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if ((itemPtr->typePtr->indexProc == NULL) || (itemPtr->typePtr->insertProc == NULL)) { continue; } - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[3], &beforeThis) != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[3], &beforeThis); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &beforeThis); + } + if (result != TCL_OK) { + goto done; } /* * Redraw both item's old and new areas: it's possible * that an insertion could result in a new area either - * larger or smaller than the old area. + * larger or smaller than the old area. Except if the + * insertProc sets the TK_ITEM_DONT_REDRAW flag, nothing + * more needs to be done. */ - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); - (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr, - itemPtr, beforeThis, argv[4]); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1, - itemPtr->y1, itemPtr->x2, itemPtr->y2); + x1 = itemPtr->x1; y1 = itemPtr->y1; + x2 = itemPtr->x2; y2 = itemPtr->y2; + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr, + itemPtr, beforeThis, (char *) argv[4]); + } else { + (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr, + itemPtr, beforeThis, Tcl_GetStringFromObj(argv[4], NULL)); + } + if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) { + Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, + x1, y1, x2, y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); + } + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; } - } else if ((c == 'i') && (strncmp(argv[1], "itemcget", length) == 0) - && (length >= 6)) { + break; + } + case CANV_ITEMCGET: { if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " itemcget tagOrId option\"", - (char *) NULL); + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId option"); return TCL_ERROR; } +#ifdef USE_OLD_TAG_SEARCH itemPtr = StartTagSearch(canvasPtr, argv[2], &search); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + itemPtr = TagSearchFirst(searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr != NULL) { result = Tk_ConfigureValue(canvasPtr->interp, canvasPtr->tkwin, itemPtr->typePtr->configSpecs, (char *) itemPtr, - argv[3], 0); + Tcl_GetStringFromObj(argv[3], NULL), 0); } - } else if ((c == 'i') && (strncmp(argv[1], "itemconfigure", length) == 0) - && (length >= 6)) { + break; + } + case CANV_ITEMCONFIGURE: { if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " itemconfigure tagOrId ?option value ...?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?option value ...?"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if (argc == 3) { result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin, itemPtr->typePtr->configSpecs, (char *) itemPtr, @@ -1028,29 +1430,36 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } else if (argc == 4) { result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin, itemPtr->typePtr->configSpecs, (char *) itemPtr, - argv[3], 0); + Tcl_GetString(argv[3]), 0); } else { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { result = (*itemPtr->typePtr->configProc)(interp, (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3, TK_CONFIG_ARGV_ONLY); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + } else { + char **args = GetStringsFromObjs(argc-3, argv+3); + result = (*itemPtr->typePtr->configProc)(interp, + (Tk_Canvas) canvasPtr, itemPtr, argc-3, (Tcl_Obj **) args, + TK_CONFIG_ARGV_ONLY); + if (args) ckfree((char *) args); + } + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } if ((result != TCL_OK) || (argc < 5)) { break; } } - } else if ((c == 'l') && (strncmp(argv[1], "lower", length) == 0)) { + break; + } + case CANV_LOWER: { Tk_Item *itemPtr; if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " lower tagOrId ?belowThis?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?belowThis?"); + result = TCL_ERROR; + goto done; } /* @@ -1061,49 +1470,75 @@ CanvasWidgetCmd(clientData, interp, argc, argv) if (argc == 3) { itemPtr = NULL; } else { +#ifdef USE_OLD_TAG_SEARCH itemPtr = StartTagSearch(canvasPtr, argv[3], &search); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) { + goto done; + } + itemPtr = TagSearchFirst(searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr == NULL) { - Tcl_AppendResult(interp, "tag \"", argv[3], + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(argv[3]), "\" doesn't match any items", (char *) NULL); - goto error; + goto done; } itemPtr = itemPtr->prevPtr; } +#ifdef USE_OLD_TAG_SEARCH RelinkItems(canvasPtr, argv[2], itemPtr); - } else if ((c == 'm') && (strncmp(argv[1], "move", length) == 0)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = RelinkItems(canvasPtr, argv[2], itemPtr, &searchPtr)) != TCL_OK) { + goto done; + } +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + case CANV_MOVE: { double xAmount, yAmount; if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " move tagOrId xAmount yAmount\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId xAmount yAmount"); + result = TCL_ERROR; + goto done; } - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], - &xAmount) != TCL_OK) || (Tk_CanvasGetCoord(interp, + if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3], + &xAmount) != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[4], &yAmount) != TCL_OK)) { - goto error; + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); (void) (*itemPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr, itemPtr, xAmount, yAmount); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } - } else if ((c == 'p') && (strncmp(argv[1], "postscript", length) == 0)) { - result = TkCanvPostscriptCmd(canvasPtr, interp, argc, argv); - } else if ((c == 'r') && (strncmp(argv[1], "raise", length) == 0)) { + break; + } + case CANV_POSTSCRIPT: { + char **args = GetStringsFromObjs(argc, argv); + result = TkCanvPostscriptCmd(canvasPtr, interp, argc, args); + if (args) ckfree((char *) args); + break; + } + case CANV_RAISE: { Tk_Item *prevPtr; if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " raise tagOrId ?aboveThis?\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?aboveThis?"); + result = TCL_ERROR; + goto done; } /* @@ -1115,70 +1550,106 @@ CanvasWidgetCmd(clientData, interp, argc, argv) prevPtr = canvasPtr->lastItemPtr; } else { prevPtr = NULL; +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ prevPtr = itemPtr; } if (prevPtr == NULL) { - Tcl_AppendResult(interp, "tagOrId \"", argv[3], + Tcl_AppendResult(interp, "tagOrId \"", Tcl_GetStringFromObj(argv[3], NULL), "\" doesn't match any items", (char *) NULL); - goto error; + result = TCL_ERROR; + goto done; } } +#ifdef USE_OLD_TAG_SEARCH RelinkItems(canvasPtr, argv[2], prevPtr); - } else if ((c == 's') && (strncmp(argv[1], "scale", length) == 0) - && (length >= 3)) { +#else /* USE_OLD_TAG_SEARCH */ + result = RelinkItems(canvasPtr, argv[2], prevPtr, &searchPtr); + if (result != TCL_OK) { + goto done; + } +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + case CANV_SCALE: { double xOrigin, yOrigin, xScale, yScale; if (argc != 7) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scale tagOrId xOrigin yOrigin xScale yScale\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId xOrigin yOrigin xScale yScale"); + result = TCL_ERROR; + goto done; } - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, + if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3], &xOrigin) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, + || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[4], &yOrigin) != TCL_OK) - || (Tcl_GetDouble(interp, argv[5], &xScale) != TCL_OK) - || (Tcl_GetDouble(interp, argv[6], &yScale) != TCL_OK)) { - goto error; + || (Tcl_GetDoubleFromObj(interp, argv[5], &xScale) != TCL_OK) + || (Tcl_GetDoubleFromObj(interp, argv[6], &yScale) != TCL_OK)) { + result = TCL_ERROR; + goto done; } if ((xScale == 0.0) || (yScale == 0.0)) { - interp->result = "scale factor cannot be zero"; - goto error; + Tcl_SetResult(interp, "scale factor cannot be zero", TCL_STATIC); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); (void) (*itemPtr->typePtr->scaleProc)((Tk_Canvas) canvasPtr, itemPtr, xOrigin, yOrigin, xScale, yScale); - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } - } else if ((c == 's') && (strncmp(argv[1], "scan", length) == 0) - && (length >= 3)) { - int x, y; + break; + } + case CANV_SCAN: { + int x, y, gain=10; + static char *optionStrings[] = { + "mark", "dragto", NULL + }; - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scan mark|dragto x y\"", (char *) NULL); - goto error; + if (Tcl_GetIndexFromObj(interp, argv[2], optionStrings, "scan option", 0, + &index) != TCL_OK) { + return TCL_ERROR; } - if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){ - goto error; + + if ((argc != 5) && (argc != 5+index)) { + Tcl_WrongNumArgs(interp, 3, argv, index?"x y ?gain?":"x y"); + result = TCL_ERROR; + goto done; + } + if ((Tcl_GetIntFromObj(interp, argv[3], &x) != TCL_OK) + || (Tcl_GetIntFromObj(interp, argv[4], &y) != TCL_OK)){ + result = TCL_ERROR; + goto done; } - if ((argv[2][0] == 'm') - && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) { + if ((argc == 6) && (Tcl_GetIntFromObj(interp, argv[5], &gain) != TCL_OK)) { + result = TCL_ERROR; + goto done; + } + if (!index) { canvasPtr->scanX = x; canvasPtr->scanXOrigin = canvasPtr->xOrigin; canvasPtr->scanY = y; canvasPtr->scanYOrigin = canvasPtr->yOrigin; - } else if ((argv[2][0] == 'd') - && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) { + } else { int newXOrigin, newYOrigin, tmp; /* @@ -1186,30 +1657,41 @@ CanvasWidgetCmd(clientData, interp, argc, argv) * mouse motion. */ - tmp = canvasPtr->scanXOrigin - 10*(x - canvasPtr->scanX) + tmp = canvasPtr->scanXOrigin - gain*(x - canvasPtr->scanX) - canvasPtr->scrollX1; newXOrigin = canvasPtr->scrollX1 + tmp; - tmp = canvasPtr->scanYOrigin - 10*(y - canvasPtr->scanY) + tmp = canvasPtr->scanYOrigin - gain*(y - canvasPtr->scanY) - canvasPtr->scrollY1; newYOrigin = canvasPtr->scrollY1 + tmp; CanvasSetOrigin(canvasPtr, newXOrigin, newYOrigin); - } else { - Tcl_AppendResult(interp, "bad scan option \"", argv[2], - "\": must be mark or dragto", (char *) NULL); - goto error; } - } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0) - && (length >= 2)) { - int index; + break; + } + case CANV_SELECT: { + int index, optionindex; + static char *optionStrings[] = { + "adjust", "clear", "from", "item", "to", NULL + }; + enum options { + CANV_ADJUST, CANV_CLEAR, CANV_FROM, CANV_ITEM, CANV_TO + }; if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select option ?tagOrId? ?arg?\"", (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "option ?tagOrId? ?arg?"); + result = TCL_ERROR; + goto done; } if (argc >= 4) { +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) { + goto done; + } + for (itemPtr = TagSearchFirst(searchPtr); + itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if ((itemPtr->typePtr->indexProc != NULL) && (itemPtr->typePtr->selectionProc != NULL)){ break; @@ -1218,24 +1700,33 @@ CanvasWidgetCmd(clientData, interp, argc, argv) if (itemPtr == NULL) { Tcl_AppendResult(interp, "can't find an indexable and selectable item \"", - argv[3], "\"", (char *) NULL); - goto error; + Tcl_GetStringFromObj(argv[3], NULL), "\"", (char *) NULL); + result = TCL_ERROR; + goto done; } } if (argc == 5) { - if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr, - itemPtr, argv[4], &index) != TCL_OK) { - goto error; + if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, (char *) argv[4], &index); + } else { + result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr, + itemPtr, Tcl_GetStringFromObj(argv[4], NULL), &index); } + if (result != TCL_OK) { + goto done; + } + } + if (Tcl_GetIndexFromObj(interp, argv[2], optionStrings, "select option", 0, + &optionindex) != TCL_OK) { + return TCL_ERROR; } - length = strlen(argv[2]); - c = argv[2][0]; - if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) { + switch ((enum options) optionindex) { + case CANV_ADJUST: { if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select adjust tagOrId index\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 3, argv, "tagOrId index"); + result = TCL_ERROR; + goto done; } if (canvasPtr->textInfo.selItemPtr == itemPtr) { if (index < (canvasPtr->textInfo.selectFirst @@ -1248,66 +1739,78 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } } CanvasSelectTo(canvasPtr, itemPtr, index); - } else if ((c == 'c') && (argv[2] != NULL) - && (strncmp(argv[2], "clear", length) == 0)) { + break; + } + case CANV_CLEAR: { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select clear\"", (char *) NULL); - goto error; + Tcl_AppendResult(interp, 3, argv, (char *) NULL); + result = TCL_ERROR; + goto done; } if (canvasPtr->textInfo.selItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.selItemPtr->x1, - canvasPtr->textInfo.selItemPtr->y1, - canvasPtr->textInfo.selItemPtr->x2, - canvasPtr->textInfo.selItemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->textInfo.selItemPtr); canvasPtr->textInfo.selItemPtr = NULL; } goto done; - } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) { + break; + } + case CANV_FROM: { if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select from tagOrId index\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 3, argv, "tagOrId index"); + result = TCL_ERROR; + goto done; } canvasPtr->textInfo.anchorItemPtr = itemPtr; canvasPtr->textInfo.selectAnchor = index; - } else if ((c == 'i') && (strncmp(argv[2], "item", length) == 0)) { + break; + } + case CANV_ITEM: { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select item\"", (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 3, argv, (char *) NULL); + result = TCL_ERROR; + goto done; } if (canvasPtr->textInfo.selItemPtr != NULL) { - sprintf(interp->result, "%d", - canvasPtr->textInfo.selItemPtr->id); + char buf[TCL_INTEGER_SPACE]; + + sprintf(buf, "%d", canvasPtr->textInfo.selItemPtr->id); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } - } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) { + break; + } + case CANV_TO: { if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select to tagOrId index\"", - (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tagOrId index"); + result = TCL_ERROR; + goto done; } CanvasSelectTo(canvasPtr, itemPtr, index); - } else { - Tcl_AppendResult(interp, "bad select option \"", argv[2], - "\": must be adjust, clear, from, item, or to", - (char *) NULL); - goto error; + break; + } } - } else if ((c == 't') && (strncmp(argv[1], "type", length) == 0)) { + break; + } + case CANV_TYPE: { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " type tag\"", (char *) NULL); - goto error; + Tcl_WrongNumArgs(interp, 2, argv, "tag"); + result = TCL_ERROR; + goto done; } +#ifdef USE_OLD_TAG_SEARCH itemPtr = StartTagSearch(canvasPtr, argv[2], &search); +#else /* USE_OLD_TAG_SEARCH */ + if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) { + goto done; + } + itemPtr = TagSearchFirst(searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr != NULL) { - interp->result = itemPtr->typePtr->name; + Tcl_SetResult(interp, itemPtr->typePtr->name, TCL_STATIC); } - } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) { + break; + } + case CANV_XVIEW: { int count, type; int newX = 0; /* Initialization needed only to prevent * gcc warnings. */ @@ -1317,12 +1820,15 @@ CanvasWidgetCmd(clientData, interp, argc, argv) PrintScrollFractions(canvasPtr->xOrigin + canvasPtr->inset, canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin) - canvasPtr->inset, canvasPtr->scrollX1, - canvasPtr->scrollX2, interp->result); + canvasPtr->scrollX2, Tcl_GetStringResult(interp)); } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); + char **args = GetStringsFromObjs(argc, argv); + type = Tk_GetScrollInfo(interp, argc, args, &fraction, &count); + if (args) ckfree((char *) args); switch (type) { case TK_SCROLL_ERROR: - goto error; + result = TCL_ERROR; + goto done; case TK_SCROLL_MOVETO: newX = canvasPtr->scrollX1 - canvasPtr->inset + (int) (fraction * (canvasPtr->scrollX2 @@ -1345,7 +1851,9 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } CanvasSetOrigin(canvasPtr, newX, canvasPtr->yOrigin); } - } else if ((c == 'y') && (strncmp(argv[1], "yview", length) == 0)) { + break; + } + case CANV_YVIEW: { int count, type; int newY = 0; /* Initialization needed only to prevent * gcc warnings. */ @@ -1355,12 +1863,15 @@ CanvasWidgetCmd(clientData, interp, argc, argv) PrintScrollFractions(canvasPtr->yOrigin + canvasPtr->inset, canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin) - canvasPtr->inset, canvasPtr->scrollY1, - canvasPtr->scrollY2, interp->result); + canvasPtr->scrollY2, Tcl_GetStringResult(interp)); } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); + char **args = GetStringsFromObjs(argc, argv); + type = Tk_GetScrollInfo(interp, argc, args, &fraction, &count); + if (args) ckfree((char *) args); switch (type) { case TK_SCROLL_ERROR: - goto error; + result = TCL_ERROR; + goto done; case TK_SCROLL_MOVETO: newY = canvasPtr->scrollY1 - canvasPtr->inset + (int) (fraction*(canvasPtr->scrollY2 @@ -1384,24 +1895,15 @@ CanvasWidgetCmd(clientData, interp, argc, argv) } CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY); } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be addtag, bbox, bind, ", - "canvasx, canvasy, cget, configure, coords, create, ", - "dchars, delete, dtag, find, focus, ", - "gettags, icursor, index, insert, itemcget, itemconfigure, ", - "lower, move, postscript, raise, scale, scan, ", - "select, type, xview, or yview", - (char *) NULL); - goto error; + break; + } } done: +#ifndef USE_OLD_TAG_SEARCH + TagSearchDestroy(searchPtr); +#endif /* not USE_OLD_TAG_SEARCH */ Tcl_Release((ClientData) canvasPtr); return result; - - error: - Tcl_Release((ClientData) canvasPtr); - return TCL_ERROR; } /* @@ -1429,6 +1931,13 @@ DestroyCanvas(memPtr) TkCanvas *canvasPtr = (TkCanvas *) memPtr; Tk_Item *itemPtr; + if (canvasPtr->tkwin != NULL) { + Tcl_DeleteCommandFromToken(canvasPtr->interp, canvasPtr->widgetCmd); + } + if (canvasPtr->flags & REDRAW_PENDING) { + Tcl_CancelIdleCall(DisplayCanvas, (ClientData) canvasPtr); + } + /* * Free up all of the items in the canvas. */ @@ -1454,11 +1963,24 @@ DestroyCanvas(memPtr) if (canvasPtr->pixmapGC != None) { Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC); } +#ifndef USE_OLD_TAG_SEARCH + { + TagSearchExpr *expr, *next; + + expr = canvasPtr->bindTagExprs; + while (expr) { + next = expr->next; + TagSearchExprDestroy(expr); + expr = next; + } + } +#endif Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler); if (canvasPtr->bindingTable != NULL) { Tk_DeleteBindingTable(canvasPtr->bindingTable); } Tk_FreeOptions(configSpecs, (char *) canvasPtr, canvasPtr->display, 0); + canvasPtr->tkwin = NULL; ckfree((char *) canvasPtr); } @@ -1473,7 +1995,7 @@ DestroyCanvas(memPtr) * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as colors, border width, @@ -1489,14 +2011,14 @@ ConfigureCanvas(interp, canvasPtr, argc, argv, flags) TkCanvas *canvasPtr; /* Information about widget; may or may * not already have values for some fields. */ int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ + Tcl_Obj *CONST argv[]; /* Argument objects. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { XGCValues gcValues; GC new; if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs, - argc, argv, (char *) canvasPtr, flags) != TCL_OK) { + argc, (char **) argv, (char *) canvasPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -1514,11 +2036,10 @@ ConfigureCanvas(interp, canvasPtr, argc, argv, flags) canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth; gcValues.function = GXcopy; - gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel; gcValues.graphics_exposures = False; - new = Tk_GetGCColor(canvasPtr->tkwin, - GCFunction|GCForeground|GCGraphicsExposures, &gcValues, - Tk_3DBorderColor(canvasPtr->bgBorder), NULL); + gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel; + new = Tk_GetGC(canvasPtr->tkwin, + GCFunction|GCGraphicsExposures|GCForeground, &gcValues); if (canvasPtr->pixmapGC != None) { Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC); } @@ -1578,6 +2099,22 @@ ConfigureCanvas(interp, canvasPtr, argc, argv, flags) ckfree((char *) argv2); } + flags = canvasPtr->tsoffset.flags; + if (flags & TK_OFFSET_LEFT) { + canvasPtr->tsoffset.xoffset = 0; + } else if (flags & TK_OFFSET_CENTER) { + canvasPtr->tsoffset.xoffset = canvasPtr->width/2; + } else if (flags & TK_OFFSET_RIGHT) { + canvasPtr->tsoffset.xoffset = canvasPtr->width; + } + if (flags & TK_OFFSET_TOP) { + canvasPtr->tsoffset.yoffset = 0; + } else if (flags & TK_OFFSET_MIDDLE) { + canvasPtr->tsoffset.yoffset = canvasPtr->height/2; + } else if (flags & TK_OFFSET_BOTTOM) { + canvasPtr->tsoffset.yoffset = canvasPtr->height; + } + /* * Reset the canvas's origin (this is a no-op unless confine * mode has just been turned on or the scroll region has changed). @@ -1668,6 +2205,7 @@ DisplayCanvas(clientData) if (canvasPtr->tkwin == NULL) { return; } + if (!Tk_IsMapped(tkwin)) { goto done; } @@ -1689,6 +2227,20 @@ DisplayCanvas(clientData) } /* + * Scan through the item list, registering the bounding box + * for all items that didn't do that for the final coordinates + * yet. This can be determined by the FORCE_REDRAW flag. + */ + + for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; + itemPtr = itemPtr->nextPtr) { + if (itemPtr->redraw_flags & FORCE_REDRAW) { + itemPtr->redraw_flags &= ~FORCE_REDRAW; + EventuallyRedrawItem((Tk_Canvas)canvasPtr, itemPtr); + itemPtr->redraw_flags &= ~FORCE_REDRAW; + } + } + /* * Compute the intersection between the area that needs redrawing * and the area that's visible on the screen. */ @@ -1780,7 +2332,7 @@ DisplayCanvas(clientData) || (itemPtr->y1 >= screenY2) || (itemPtr->x2 < screenX1) || (itemPtr->y2 < screenY1)) { - if (!itemPtr->typePtr->alwaysRedraw + if (!(itemPtr->typePtr->alwaysRedraw & 1) || (itemPtr->x1 >= canvasPtr->redrawX2) || (itemPtr->y1 >= canvasPtr->redrawY2) || (itemPtr->x2 < canvasPtr->redrawX1) @@ -1788,6 +2340,11 @@ DisplayCanvas(clientData) continue; } } + if (itemPtr->state == TK_STATE_HIDDEN || + (itemPtr->state == TK_STATE_NULL && + canvasPtr->canvas_state == TK_STATE_HIDDEN)) { + continue; + } (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr, canvasPtr->display, pixmap, screenX1, screenY1, width, height); @@ -1824,22 +2381,24 @@ DisplayCanvas(clientData) canvasPtr->borderWidth, canvasPtr->relief); } if (canvasPtr->highlightWidth != 0) { - GC gc; - + GC fgGC, bgGC; + + bgGC = Tk_GCForColor(canvasPtr->highlightBgColorPtr, + Tk_WindowId(tkwin)); if (canvasPtr->textInfo.gotFocus) { - gc = Tk_GCForColor(canvasPtr->highlightColorPtr, + fgGC = Tk_GCForColor(canvasPtr->highlightColorPtr, Tk_WindowId(tkwin)); + TkpDrawHighlightBorder(tkwin, fgGC, bgGC, + canvasPtr->highlightWidth, Tk_WindowId(tkwin)); } else { - gc = Tk_GCForColor(canvasPtr->highlightBgColorPtr, - Tk_WindowId(tkwin)); + TkpDrawHighlightBorder(tkwin, bgGC, bgGC, + canvasPtr->highlightWidth, Tk_WindowId(tkwin)); } - Tk_DrawFocusHighlight(tkwin, gc, canvasPtr->highlightWidth, - Tk_WindowId(tkwin)); } } done: - canvasPtr->flags &= ~REDRAW_PENDING; + canvasPtr->flags &= ~(REDRAW_PENDING|BBOX_NOT_EMPTY); canvasPtr->redrawX1 = canvasPtr->redrawX2 = 0; canvasPtr->redrawY1 = canvasPtr->redrawY2 = 0; if (canvasPtr->flags & UPDATE_SCROLLBARS) { @@ -1889,15 +2448,7 @@ CanvasEventProc(clientData, eventPtr) canvasPtr->flags |= REDRAW_BORDERS; } } else if (eventPtr->type == DestroyNotify) { - if (canvasPtr->tkwin != NULL) { - canvasPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(canvasPtr->interp, - canvasPtr->widgetCmd); - } - if (canvasPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayCanvas, (ClientData) canvasPtr); - } - Tcl_EventuallyFree((ClientData) canvasPtr, DestroyCanvas); + DestroyCanvas((char *) canvasPtr); } else if (eventPtr->type == ConfigureNotify) { canvasPtr->flags |= UPDATE_SCROLLBARS; @@ -1931,7 +2482,7 @@ CanvasEventProc(clientData, eventPtr) for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; itemPtr = itemPtr->nextPtr) { - if (itemPtr->typePtr->alwaysRedraw) { + if (itemPtr->typePtr->alwaysRedraw & 1) { (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr, canvasPtr->display, None, 0, 0, 0, 0); } @@ -2003,10 +2554,21 @@ Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2) * Pixels on edge are not redrawn. */ { TkCanvas *canvasPtr = (TkCanvas *) canvas; - if ((x1 == x2) || (y1 == y2)) { + /* + * If tkwin is NULL, the canvas has been destroyed, so we can't really + * redraw it. + */ + if (canvasPtr->tkwin == NULL) { return; } - if (canvasPtr->flags & REDRAW_PENDING) { + + if ((x1 >= x2) || (y1 >= y2) || + (x2 < canvasPtr->xOrigin) || (y2 < canvasPtr->yOrigin) || + (x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) || + (y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) { + return; + } + if (canvasPtr->flags & BBOX_NOT_EMPTY) { if (x1 <= canvasPtr->redrawX1) { canvasPtr->redrawX1 = x1; } @@ -2024,6 +2586,70 @@ Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2) canvasPtr->redrawY1 = y1; canvasPtr->redrawX2 = x2; canvasPtr->redrawY2 = y2; + canvasPtr->flags |= BBOX_NOT_EMPTY; + } + if (!(canvasPtr->flags & REDRAW_PENDING)) { + Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr); + canvasPtr->flags |= REDRAW_PENDING; + } +} + +/* + *-------------------------------------------------------------- + * + * EventuallyRedrawItem -- + * + * Arrange for part or all of a canvas widget to redrawn at + * some convenient time in the future. + * + * Results: + * None. + * + * Side effects: + * The screen will eventually be refreshed. + * + *-------------------------------------------------------------- + */ + +static void +EventuallyRedrawItem(canvas, itemPtr) + Tk_Canvas canvas; /* Information about widget. */ + Tk_Item *itemPtr; /* item to be redrawn. */ +{ + TkCanvas *canvasPtr = (TkCanvas *) canvas; + if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2) || + (itemPtr->x2 < canvasPtr->xOrigin) || + (itemPtr->y2 < canvasPtr->yOrigin) || + (itemPtr->x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) || + (itemPtr->y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) { + if (!(itemPtr->typePtr->alwaysRedraw & 1)) { + return; + } + } + if (!(itemPtr->redraw_flags & FORCE_REDRAW)) { + if (canvasPtr->flags & BBOX_NOT_EMPTY) { + if (itemPtr->x1 <= canvasPtr->redrawX1) { + canvasPtr->redrawX1 = itemPtr->x1; + } + if (itemPtr->y1 <= canvasPtr->redrawY1) { + canvasPtr->redrawY1 = itemPtr->y1; + } + if (itemPtr->x2 >= canvasPtr->redrawX2) { + canvasPtr->redrawX2 = itemPtr->x2; + } + if (itemPtr->y2 >= canvasPtr->redrawY2) { + canvasPtr->redrawY2 = itemPtr->y2; + } + } else { + canvasPtr->redrawX1 = itemPtr->x1; + canvasPtr->redrawY1 = itemPtr->y1; + canvasPtr->redrawX2 = itemPtr->x2; + canvasPtr->redrawY2 = itemPtr->y2; + canvasPtr->flags |= BBOX_NOT_EMPTY; + } + itemPtr->redraw_flags |= FORCE_REDRAW; + } + if (!(canvasPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr); canvasPtr->flags |= REDRAW_PENDING; } @@ -2142,10 +2768,21 @@ InitCanvas() tkBitmapType.nextPtr = &tkArcType; tkArcType.nextPtr = &tkWindowType; tkWindowType.nextPtr = NULL; +#ifndef USE_OLD_TAG_SEARCH allUid = Tk_GetUid("all"); currentUid = Tk_GetUid("current"); + andUid = Tk_GetUid("&&"); + orUid = Tk_GetUid("||"); + xorUid = Tk_GetUid("^"); + parenUid = Tk_GetUid("("); + endparenUid = Tk_GetUid(")"); + negparenUid = Tk_GetUid("!("); + tagvalUid = Tk_GetUid("!!"); + negtagvalUid = Tk_GetUid("!"); +#endif /* USE_OLD_TAG_SEARCH */ } +#ifdef USE_OLD_TAG_SEARCH /* *-------------------------------------------------------------- * @@ -2172,10 +2809,10 @@ InitCanvas() */ static Tk_Item * -StartTagSearch(canvasPtr, tag, searchPtr) +StartTagSearch(canvasPtr, tagObj, searchPtr) TkCanvas *canvasPtr; /* Canvas whose items are to be * searched. */ - char *tag; /* String giving tag value. */ + Tcl_Obj *tagObj; /* Object giving tag value. */ TagSearch *searchPtr; /* Record describing tag search; * will be initialized here. */ { @@ -2183,7 +2820,13 @@ StartTagSearch(canvasPtr, tag, searchPtr) Tk_Item *itemPtr, *lastPtr; Tk_Uid *tagPtr; Tk_Uid uid; + char *tag = Tcl_GetString(tagObj); int count; + TkWindow *tkwin; + TkDisplay *dispPtr; + + tkwin = (TkWindow *) canvasPtr->tkwin; + dispPtr = tkwin->dispPtr; /* * Initialize the search. @@ -2202,15 +2845,15 @@ StartTagSearch(canvasPtr, tag, searchPtr) if (isdigit(UCHAR(*tag))) { char *end; Tcl_HashEntry *entryPtr; - - numIdSearches++; + + dispPtr->numIdSearches++; id = strtoul(tag, &end, 0); if (*end == 0) { itemPtr = canvasPtr->hotPtr; - lastPtr = canvasPtr->hotPrevPtr; + lastPtr = canvasPtr->hotPrevPtr; if ((itemPtr == NULL) || (itemPtr->id != id) || (lastPtr == NULL) || (lastPtr->nextPtr != itemPtr)) { - numSlowSearches++; + dispPtr->numSlowSearches++; entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id); if (entryPtr != NULL) { itemPtr = (Tk_Item *)Tcl_GetHashValue(entryPtr); @@ -2228,8 +2871,7 @@ StartTagSearch(canvasPtr, tag, searchPtr) } searchPtr->tag = uid = Tk_GetUid(tag); - if (uid == allUid) { - + if (uid == Tk_GetUid("all")) { /* * All items match. */ @@ -2348,6 +2990,853 @@ NextItem(searchPtr) return NULL; } +#else /* USE_OLD_TAG_SEARCH */ +/* + *-------------------------------------------------------------- + * + * TagSearchExprInit -- + * + * This procedure allocates and initializes one TagSearchExpr struct. + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static void +TagSearchExprInit(exprPtrPtr) +TagSearchExpr **exprPtrPtr; +{ + TagSearchExpr* expr = *exprPtrPtr; + + if (! expr) { + expr = (TagSearchExpr *) ckalloc(sizeof(TagSearchExpr)); + expr->allocated = 0; + expr->uids = NULL; + expr->next = NULL; + } + expr->uid = NULL; + expr->index = 0; + expr->length = 0; + *exprPtrPtr = expr; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchExprDestroy -- + * + * This procedure destroys one TagSearchExpr structure. + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static void +TagSearchExprDestroy(expr) + TagSearchExpr *expr; +{ + if (expr) { + if (expr->uids) { + ckfree((char *)expr->uids); + } + ckfree((char *)expr); + } +} + +/* + *-------------------------------------------------------------- + * + * TagSearchScan -- + * + * This procedure is called to initiate an enumeration of + * all items in a given canvas that contain a tag that matches + * the tagOrId expression. + * + * Results: + * The return value indicates if the tagOrId expression + * was successfully scanned (syntax). + * The information at *searchPtr is initialized + * such that a call to TagSearchFirst, followed by + * successive calls to TagSearchNext will return items + * that match tag. + * + * Side effects: + * SearchPtr is linked into a list of searches in progress + * on canvasPtr, so that elements can safely be deleted + * while the search is in progress. + * + *-------------------------------------------------------------- + */ + +static int +TagSearchScan(canvasPtr, tagObj, searchPtrPtr) + TkCanvas *canvasPtr; /* Canvas whose items are to be + * searched. */ + Tcl_Obj *tagObj; /* Object giving tag value. */ + TagSearch **searchPtrPtr; /* Record describing tag search; + * will be initialized here. */ +{ + char *tag = Tcl_GetStringFromObj(tagObj,NULL); + int i; + TagSearch *searchPtr; + + /* + * Initialize the search. + */ + + if (*searchPtrPtr) { + searchPtr = *searchPtrPtr; + } else { + /* Allocate primary search struct on first call */ + *searchPtrPtr = searchPtr = (TagSearch *) ckalloc(sizeof(TagSearch)); + searchPtr->expr = NULL; + + /* Allocate buffer for rewritten tags (after de-escaping) */ + searchPtr->rewritebufferAllocated = 100; + searchPtr->rewritebuffer = + ckalloc(searchPtr->rewritebufferAllocated); + } + TagSearchExprInit(&(searchPtr->expr)); + + /* How long is the tagOrId ? */ + searchPtr->stringLength = strlen(tag); + + /* Make sure there is enough buffer to hold rewritten tags */ + if ((unsigned int)searchPtr->stringLength >= + searchPtr->rewritebufferAllocated) { + searchPtr->rewritebufferAllocated = searchPtr->stringLength + 100; + searchPtr->rewritebuffer = + ckrealloc(searchPtr->rewritebuffer, + searchPtr->rewritebufferAllocated); + } + + /* Initialize search */ + searchPtr->canvasPtr = canvasPtr; + searchPtr->searchOver = 0; + searchPtr->type = 0; + + /* + * Find the first matching item in one of several ways. If the tag + * is a number then it selects the single item with the matching + * identifier. In this case see if the item being requested is the + * hot item, in which case the search can be skipped. + */ + + if (searchPtr->stringLength && isdigit(UCHAR(*tag))) { + char *end; + + searchPtr->id = strtoul(tag, &end, 0); + if (*end == 0) { + searchPtr->type = 1; + return TCL_OK; + } + } + + /* + * For all other tags and tag expressions convert to a UID. + * This UID is kept forever, but this should be thought of + * as a cache rather than as a memory leak. + */ + searchPtr->expr->uid = Tk_GetUid(tag); + + /* short circuit impossible searches for null tags */ + if (searchPtr->stringLength == 0) { + return TCL_OK; + } + + /* + * Pre-scan tag for at least one unquoted "&&" "||" "^" "!" + * if not found then use string as simple tag + */ + for (i = 0; i < searchPtr->stringLength ; i++) { + if (tag[i] == '"') { + i++; + for ( ; i < searchPtr->stringLength; i++) { + if (tag[i] == '\\') { + i++; + continue; + } + if (tag[i] == '"') { + break; + } + } + } else { + if ((tag[i] == '&' && tag[i+1] == '&') + || (tag[i] == '|' && tag[i+1] == '|') + || (tag[i] == '^') + || (tag[i] == '!')) { + searchPtr->type = 4; + break; + } + } + } + + searchPtr->string = tag; + searchPtr->stringIndex = 0; + if (searchPtr->type == 4) { + /* + * an operator was found in the prescan, so + * now compile the tag expression into array of Tk_Uid + * flagging any syntax errors found + */ + if (TagSearchScanExpr(canvasPtr->interp, searchPtr, searchPtr->expr) != TCL_OK) { + /* Syntax error in tag expression */ + /* Result message set by TagSearchScanExpr */ + return TCL_ERROR; + } + searchPtr->expr->length = searchPtr->expr->index; + } else { + if (searchPtr->expr->uid == allUid) { + /* + * All items match. + */ + searchPtr->type = 2; + } else { + /* + * Optimized single-tag search + */ + searchPtr->type = 3; + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchDestroy -- + * + * This procedure destroys any dynamic structures that + * may have been allocated by TagSearchScan. + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static void +TagSearchDestroy(searchPtr) + TagSearch *searchPtr; /* Record describing tag search */ +{ + if (searchPtr) { + TagSearchExprDestroy(searchPtr->expr); + ckfree((char *)searchPtr->rewritebuffer); + ckfree((char *)searchPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * TagSearchScanExpr -- + * + * This recursive procedure is called to scan a tag expression + * and compile it into an array of Tk_Uids. + * + * Results: + * The return value indicates if the tagOrId expression + * was successfully scanned (syntax). + * The information at *searchPtr is initialized + * such that a call to TagSearchFirst, followed by + * successive calls to TagSearchNext will return items + * that match tag. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +TagSearchScanExpr(interp, searchPtr, expr) + Tcl_Interp *interp; /* Current interpreter. */ + TagSearch *searchPtr; /* Search data */ + TagSearchExpr *expr; /* compiled expression result */ +{ + int looking_for_tag; /* When true, scanner expects + * next char(s) to be a tag, + * else operand expected */ + int found_tag; /* One or more tags found */ + int found_endquote; /* For quoted tag string parsing */ + int negate_result; /* Pending negation of next tag value */ + char *tag; /* tag from tag expression string */ + char c; + + negate_result = 0; + found_tag = 0; + looking_for_tag = 1; + while (searchPtr->stringIndex < searchPtr->stringLength) { + c = searchPtr->string[searchPtr->stringIndex++]; + + if (expr->allocated == expr->index) { + expr->allocated += 15; + if (expr->uids) { + expr->uids = + (Tk_Uid *) ckrealloc((char *)(expr->uids), + (expr->allocated)*sizeof(Tk_Uid)); + } else { + expr->uids = + (Tk_Uid *) ckalloc((expr->allocated)*sizeof(Tk_Uid)); + } + } + + if (looking_for_tag) { + + switch (c) { + case ' ' : /* ignore unquoted whitespace */ + case '\t' : + case '\n' : + case '\r' : + break; + + case '!' : /* negate next tag or subexpr */ + if (looking_for_tag > 1) { + Tcl_AppendResult(interp, + "Too many '!' in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + looking_for_tag++; + negate_result = 1; + break; + + case '(' : /* scan (negated) subexpr recursively */ + if (negate_result) { + expr->uids[expr->index++] = negparenUid; + negate_result = 0; + } else { + expr->uids[expr->index++] = parenUid; + } + if (TagSearchScanExpr(interp, searchPtr, expr) != TCL_OK) { + /* Result string should be already set + * by nested call to tag_expr_scan() */ + return TCL_ERROR; + } + looking_for_tag = 0; + found_tag = 1; + break; + + case '"' : /* quoted tag string */ + if (negate_result) { + expr->uids[expr->index++] = negtagvalUid; + negate_result = 0; + } else { + expr->uids[expr->index++] = tagvalUid; + } + tag = searchPtr->rewritebuffer; + found_endquote = 0; + while (searchPtr->stringIndex < searchPtr->stringLength) { + c = searchPtr->string[searchPtr->stringIndex++]; + if (c == '\\') { + c = searchPtr->string[searchPtr->stringIndex++]; + } + if (c == '"') { + found_endquote = 1; + break; + } + *tag++ = c; + } + if (! found_endquote) { + Tcl_AppendResult(interp, + "Missing endquote in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + if (! (tag - searchPtr->rewritebuffer)) { + Tcl_AppendResult(interp, + "Null quoted tag string in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + *tag++ = '\0'; + expr->uids[expr->index++] = + Tk_GetUid(searchPtr->rewritebuffer); + looking_for_tag = 0; + found_tag = 1; + break; + + case '&' : /* illegal chars when looking for tag */ + case '|' : + case '^' : + case ')' : + Tcl_AppendResult(interp, + "Unexpected operator in tag search expression", + (char *) NULL); + return TCL_ERROR; + + default : /* unquoted tag string */ + if (negate_result) { + expr->uids[expr->index++] = negtagvalUid; + negate_result = 0; + } else { + expr->uids[expr->index++] = tagvalUid; + } + tag = searchPtr->rewritebuffer; + *tag++ = c; + /* copy rest of tag, including any embedded whitespace */ + while (searchPtr->stringIndex < searchPtr->stringLength) { + c = searchPtr->string[searchPtr->stringIndex]; + if (c == '!' || c == '&' || c == '|' || c == '^' + || c == '(' || c == ')' || c == '"') { + break; + } + *tag++ = c; + searchPtr->stringIndex++; + } + /* remove trailing whitespace */ + while (1) { + c = *--tag; + /* there must have been one non-whitespace char, + * so this will terminate */ + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') { + break; + } + } + *++tag = '\0'; + expr->uids[expr->index++] = + Tk_GetUid(searchPtr->rewritebuffer); + looking_for_tag = 0; + found_tag = 1; + } + + } else { /* ! looking_for_tag */ + + switch (c) { + case ' ' : /* ignore whitespace */ + case '\t' : + case '\n' : + case '\r' : + break; + + case '&' : /* AND operator */ + c = searchPtr->string[searchPtr->stringIndex++]; + if (c != '&') { + Tcl_AppendResult(interp, + "Singleton '&' in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + expr->uids[expr->index++] = andUid; + looking_for_tag = 1; + break; + + case '|' : /* OR operator */ + c = searchPtr->string[searchPtr->stringIndex++]; + if (c != '|') { + Tcl_AppendResult(interp, + "Singleton '|' in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + expr->uids[expr->index++] = orUid; + looking_for_tag = 1; + break; + + case '^' : /* XOR operator */ + expr->uids[expr->index++] = xorUid; + looking_for_tag = 1; + break; + + case ')' : /* end subexpression */ + expr->uids[expr->index++] = endparenUid; + goto breakwhile; + + default : /* syntax error */ + Tcl_AppendResult(interp, + "Invalid boolean operator in tag search expression", + (char *) NULL); + return TCL_ERROR; + } + } + } + breakwhile: + if (found_tag && ! looking_for_tag) { + return TCL_OK; + } + Tcl_AppendResult(interp, "Missing tag in tag search expression", + (char *) NULL); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchEvalExpr -- + * + * This recursive procedure is called to eval a tag expression. + * + * Results: + * The return value indicates if the tagOrId expression + * successfully matched the tags of the current item. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +TagSearchEvalExpr(expr, itemPtr) + TagSearchExpr *expr; /* Search expression */ + Tk_Item *itemPtr; /* Item being test for match */ +{ + int looking_for_tag; /* When true, scanner expects + * next char(s) to be a tag, + * else operand expected */ + int negate_result; /* Pending negation of next tag value */ + Tk_Uid uid; + Tk_Uid *tagPtr; + int count; + int result; /* Value of expr so far */ + int parendepth; + + result = 0; /* just to keep the compiler quiet */ + + negate_result = 0; + looking_for_tag = 1; + while (expr->index < expr->length) { + uid = expr->uids[expr->index++]; + if (looking_for_tag) { + if (uid == tagvalUid) { +/* + * assert(expr->index < expr->length); + */ + uid = expr->uids[expr->index++]; + result = 0; + /* + * set result 1 if tag is found in item's tags + */ + for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + result = 1; + break; + } + } + + } else if (uid == negtagvalUid) { + negate_result = ! negate_result; +/* + * assert(expr->index < expr->length); + */ + uid = expr->uids[expr->index++]; + result = 0; + /* + * set result 1 if tag is found in item's tags + */ + for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + result = 1; + break; + } + } + + } else if (uid == parenUid) { + /* + * evaluate subexpressions with recursion + */ + result = TagSearchEvalExpr(expr, itemPtr); + + } else if (uid == negparenUid) { + negate_result = ! negate_result; + /* + * evaluate subexpressions with recursion + */ + result = TagSearchEvalExpr(expr, itemPtr); +/* + * } else { + * assert(0); + */ + } + if (negate_result) { + result = ! result; + negate_result = 0; + } + looking_for_tag = 0; + } else { /* ! looking_for_tag */ + if (((uid == andUid) && (!result)) || ((uid == orUid) && result)) { + /* + * short circuit expression evaluation + * + * if result before && is 0, or result before || is 1, + * then the expression is decided and no further + * evaluation is needed. + */ + + parendepth = 0; + while (expr->index < expr->length) { + uid = expr->uids[expr->index++]; + if (uid == tagvalUid || uid == negtagvalUid) { + expr->index++; + continue; + } + if (uid == parenUid || uid == negparenUid) { + parendepth++; + continue; + } + if (uid == endparenUid) { + parendepth--; + if (parendepth < 0) { + break; + } + } + } + return result; + + } else if (uid == xorUid) { + /* + * if the previous result was 1 + * then negate the next result + */ + negate_result = result; + + } else if (uid == endparenUid) { + return result; +/* + * } else { + * assert(0); + */ + } + looking_for_tag = 1; + } + } +/* + * assert(! looking_for_tag); + */ + return result; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchFirst -- + * + * This procedure is called to get the first item + * item that matches a preestablished search predicate + * that was set by TagSearchScan. + * + * Results: + * The return value is a pointer to the first item, or NULL + * if there is no such item. The information at *searchPtr + * is updated such that successive calls to TagSearchNext + * will return successive items. + * + * Side effects: + * SearchPtr is linked into a list of searches in progress + * on canvasPtr, so that elements can safely be deleted + * while the search is in progress. + * + *-------------------------------------------------------------- + */ + +static Tk_Item * +TagSearchFirst(searchPtr) + TagSearch *searchPtr; /* Record describing tag search */ +{ + Tk_Item *itemPtr, *lastPtr; + Tk_Uid uid, *tagPtr; + int count; + + /* short circuit impossible searches for null tags */ + if (searchPtr->stringLength == 0) { + return NULL; + } + + /* + * Find the first matching item in one of several ways. If the tag + * is a number then it selects the single item with the matching + * identifier. In this case see if the item being requested is the + * hot item, in which case the search can be skipped. + */ + + if (searchPtr->type == 1) { + Tcl_HashEntry *entryPtr; + + itemPtr = searchPtr->canvasPtr->hotPtr; + lastPtr = searchPtr->canvasPtr->hotPrevPtr; + if ((itemPtr == NULL) || (itemPtr->id != searchPtr->id) || (lastPtr == NULL) + || (lastPtr->nextPtr != itemPtr)) { + entryPtr = Tcl_FindHashEntry(&searchPtr->canvasPtr->idTable, + (char *) searchPtr->id); + if (entryPtr != NULL) { + itemPtr = (Tk_Item *)Tcl_GetHashValue(entryPtr); + lastPtr = itemPtr->prevPtr; + } else { + lastPtr = itemPtr = NULL; + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + searchPtr->canvasPtr->hotPtr = itemPtr; + searchPtr->canvasPtr->hotPrevPtr = lastPtr; + return itemPtr; + } + + if (searchPtr->type == 2) { + + /* + * All items match. + */ + + searchPtr->lastPtr = NULL; + searchPtr->currentPtr = searchPtr->canvasPtr->firstItemPtr; + return searchPtr->canvasPtr->firstItemPtr; + } + + if (searchPtr->type == 3) { + + /* + * Optimized single-tag search + */ + + uid = searchPtr->expr->uid; + for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->firstItemPtr; + itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) { + for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + } + } else { + + /* + * None of the above. Search for an item matching the tag expression. + */ + + for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->firstItemPtr; + itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) { + searchPtr->expr->index = 0; + if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + return NULL; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchNext -- + * + * This procedure returns successive items that match a given + * tag; it should be called only after TagSearchFirst has been + * used to begin a search. + * + * Results: + * The return value is a pointer to the next item that matches + * the tag expr specified to TagSearchScan, or NULL if no such + * item exists. *SearchPtr is updated so that the next call + * to this procedure will return the next item. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static Tk_Item * +TagSearchNext(searchPtr) + TagSearch *searchPtr; /* Record describing search in + * progress. */ +{ + Tk_Item *itemPtr, *lastPtr; + Tk_Uid uid, *tagPtr; + int count; + + /* + * Find next item in list (this may not actually be a suitable + * one to return), and return if there are no items left. + */ + + lastPtr = searchPtr->lastPtr; + if (lastPtr == NULL) { + itemPtr = searchPtr->canvasPtr->firstItemPtr; + } else { + itemPtr = lastPtr->nextPtr; + } + if ((itemPtr == NULL) || (searchPtr->searchOver)) { + searchPtr->searchOver = 1; + return NULL; + } + if (itemPtr != searchPtr->currentPtr) { + /* + * The structure of the list has changed. Probably the + * previously-returned item was removed from the list. + * In this case, don't advance lastPtr; just return + * its new successor (i.e. do nothing here). + */ + } else { + lastPtr = itemPtr; + itemPtr = lastPtr->nextPtr; + } + + if (searchPtr->type == 2) { + + /* + * All items match. + */ + + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + + if (searchPtr->type == 3) { + + /* + * Optimized single-tag search + */ + + uid = searchPtr->expr->uid; + for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) { + for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + return NULL; + } + + /* + * Else.... evaluate tag expression + */ + + for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) { + searchPtr->expr->index = 0; + if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + return NULL; +} +#endif /* USE_OLD_TAG_SEARCH */ + /* *-------------------------------------------------------------- * @@ -2363,7 +3852,7 @@ NextItem(searchPtr) * * Side effects: * If tag is NULL then itemPtr's id is added as a list element - * to interp->result; otherwise tag is added to itemPtr's + * to the interp's result; otherwise tag is added to itemPtr's * list of tags. * *-------------------------------------------------------------- @@ -2385,7 +3874,8 @@ DoItem(interp, itemPtr, tag) */ if (tag == NULL) { - char msg[30]; + char msg[TCL_INTEGER_SPACE]; + sprintf(msg, "%d", itemPtr->id); Tcl_AppendElement(interp, msg); return; @@ -2439,9 +3929,9 @@ DoItem(interp, itemPtr, tag) * Results: * A standard Tcl return value. If newTag is NULL, then a * list of ids from all the items that match argc/argv is - * returned in interp->result. If newTag is NULL, then - * the normal interp->result is an empty string. If an error - * occurs, then interp->result will hold an error message. + * returned in the interp's result. If newTag is NULL, then + * the normal the interp's result is an empty string. If an error + * occurs, then the interp's result will hold an error message. * * Side effects: * If newTag is non-NULL, then all the items that match the @@ -2452,58 +3942,81 @@ DoItem(interp, itemPtr, tag) */ static int -FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) +#ifdef USE_OLD_TAG_SEARCH +FindItems(interp, canvasPtr, argc, argv, newTag, first) +#else /* USE_OLD_TAG_SEARCH */ +FindItems(interp, canvasPtr, argc, argv, newTag, first, searchPtrPtr) +#endif /* USE_OLD_TAG_SEARCH */ Tcl_Interp *interp; /* Interpreter for error reporting. */ TkCanvas *canvasPtr; /* Canvas whose items are to be * searched. */ int argc; /* Number of entries in argv. Must be * greater than zero. */ - char **argv; /* Arguments that describe what items + Tcl_Obj *CONST *argv; /* Arguments that describe what items * to search for (see user doc on * "find" and "addtag" options). */ - char *newTag; /* If non-NULL, gives new tag to set + Tcl_Obj *newTag; /* If non-NULL, gives new tag to set * on all found items; if NULL, then * ids of found items are returned - * in interp->result. */ - char *cmdName; /* Name of original Tcl command, for - * use in error messages. */ - char *option; /* For error messages: gives option - * from Tcl command and other stuff - * up to what's in argc/argv. */ + * in the interp's result. */ + int first; /* For error messages: gives number + * of elements of argv which are already + * handled. */ +#ifndef USE_OLD_TAG_SEARCH + TagSearch **searchPtrPtr; /* From CanvasWidgetCmd local vars*/ +#endif /* not USE_OLD_TAG_SEARCH */ { - int c; - size_t length; +#ifdef USE_OLD_TAG_SEARCH TagSearch search; +#endif /* USE_OLD_TAG_SEARCH */ Tk_Item *itemPtr; Tk_Uid uid; + int index; + static char *optionStrings[] = { + "above", "all", "below", "closest", + "enclosed", "overlapping", "withtag", NULL + }; + enum options { + CANV_ABOVE, CANV_ALL, CANV_BELOW, CANV_CLOSEST, + CANV_ENCLOSED, CANV_OVERLAPPING, CANV_WITHTAG + }; if (newTag != NULL) { - uid = Tk_GetUid(newTag); + uid = Tk_GetUid(Tcl_GetStringFromObj(newTag, NULL)); } else { uid = NULL; } - c = argv[0][0]; - length = strlen(argv[0]); - if ((c == 'a') && (strncmp(argv[0], "above", length) == 0) - && (length >= 2)) { + if (Tcl_GetIndexFromObj(interp, argv[first], optionStrings, "search command", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + switch ((enum options) index) { + case CANV_ABOVE: { Tk_Item *lastPtr = NULL; - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " above tagOrId", (char *) NULL); + if (argc != first+2) { + Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId"); return TCL_ERROR; } - for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search); +#ifdef USE_OLD_TAG_SEARCH + for (itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) { + return TCL_ERROR; + } + for (itemPtr = TagSearchFirst(*searchPtrPtr); + itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ lastPtr = itemPtr; } if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) { DoItem(interp, lastPtr->nextPtr, uid); } - } else if ((c == 'a') && (strncmp(argv[0], "all", length) == 0) - && (length >= 2)) { - if (argc != 1) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " all", (char *) NULL); + break; + } + case CANV_ALL: { + if (argc != first+1) { + Tcl_WrongNumArgs(interp, first+1, argv, (char *) NULL); return TCL_ERROR; } @@ -2511,43 +4024,53 @@ FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) itemPtr = itemPtr->nextPtr) { DoItem(interp, itemPtr, uid); } - } else if ((c == 'b') && (strncmp(argv[0], "below", length) == 0)) { + break; + } + case CANV_BELOW: { Tk_Item *itemPtr; - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " below tagOrId", (char *) NULL); + if (argc != first+2) { + Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId"); return TCL_ERROR; } - itemPtr = StartTagSearch(canvasPtr, argv[1], &search); - if (itemPtr->prevPtr != NULL) { - DoItem(interp, itemPtr->prevPtr, uid); +#ifdef USE_OLD_TAG_SEARCH + itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search); +#else /* USE_OLD_TAG_SEARCH */ + if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) { + return TCL_ERROR; + } + itemPtr = TagSearchFirst(*searchPtrPtr); +#endif /* USE_OLD_TAG_SEARCH */ + if (itemPtr != NULL) { + if (itemPtr->prevPtr != NULL) { + DoItem(interp, itemPtr->prevPtr, uid); + } } - } else if ((c == 'c') && (strncmp(argv[0], "closest", length) == 0)) { + break; + } + case CANV_CLOSEST: { double closestDist; Tk_Item *startPtr, *closestPtr; double coords[2], halo; int x1, y1, x2, y2; - if ((argc < 3) || (argc > 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " closest x y ?halo? ?start?", - (char *) NULL); + if ((argc < first+3) || (argc > first+5)) { + Tcl_WrongNumArgs(interp, first+1, argv, "x y ?halo? ?start?"); return TCL_ERROR; } - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[1], - &coords[0]) != TCL_OK) || (Tk_CanvasGetCoord(interp, - (Tk_Canvas) canvasPtr, argv[2], &coords[1]) != TCL_OK)) { + if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[first+1], + &coords[0]) != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp, + (Tk_Canvas) canvasPtr, argv[first+2], &coords[1]) != TCL_OK)) { return TCL_ERROR; } - if (argc > 3) { - if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], + if (argc > first+3) { + if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[first+3], &halo) != TCL_OK) { return TCL_ERROR; } if (halo < 0.0) { Tcl_AppendResult(interp, "can't have negative halo value \"", - argv[3], "\"", (char *) NULL); + Tcl_GetString(argv[3]), "\"", (char *) NULL); return TCL_ERROR; } } else { @@ -2559,8 +4082,15 @@ FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) */ startPtr = canvasPtr->firstItemPtr; - if (argc == 5) { - itemPtr = StartTagSearch(canvasPtr, argv[4], &search); + if (argc == first+5) { +#ifdef USE_OLD_TAG_SEARCH + itemPtr = StartTagSearch(canvasPtr, argv[first+4], &search); +#else /* USE_OLD_TAG_SEARCH */ + if (TagSearchScan(canvasPtr, argv[first+4], searchPtrPtr) != TCL_OK) { + return TCL_ERROR; + } + itemPtr = TagSearchFirst(*searchPtrPtr); +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr != NULL) { startPtr = itemPtr; } @@ -2575,6 +4105,10 @@ FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) */ itemPtr = startPtr; + while(itemPtr && (itemPtr->state == TK_STATE_HIDDEN || + (itemPtr->state == TK_STATE_NULL && canvasPtr->canvas_state == TK_STATE_HIDDEN))) { + itemPtr = itemPtr->nextPtr; + } if (itemPtr == NULL) { return TCL_OK; } @@ -2612,6 +4146,10 @@ FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) DoItem(interp, closestPtr, uid); return TCL_OK; } + if (itemPtr->state == TK_STATE_HIDDEN || (itemPtr->state == TK_STATE_NULL && + canvasPtr->canvas_state == TK_STATE_HIDDEN)) { + continue; + } if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1) || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) { continue; @@ -2627,36 +4165,40 @@ FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) } } } - } else if ((c == 'e') && (strncmp(argv[0], "enclosed", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " enclosed x1 y1 x2 y2", (char *) NULL); + break; + } + case CANV_ENCLOSED: { + if (argc != first+5) { + Tcl_WrongNumArgs(interp, first+1, argv, "x1 y1 x2 y2"); return TCL_ERROR; } - return FindArea(interp, canvasPtr, argv+1, uid, 1); - } else if ((c == 'o') && (strncmp(argv[0], "overlapping", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " overlapping x1 y1 x2 y2", - (char *) NULL); + return FindArea(interp, canvasPtr, argv+first+1, uid, 1); + } + case CANV_OVERLAPPING: { + if (argc != first+5) { + Tcl_WrongNumArgs(interp, first+1, argv, "x1 y1 x2 y2"); return TCL_ERROR; } - return FindArea(interp, canvasPtr, argv+1, uid, 0); - } else if ((c == 'w') && (strncmp(argv[0], "withtag", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - cmdName, option, " withtag tagOrId", (char *) NULL); + return FindArea(interp, canvasPtr, argv+first+1, uid, 0); + } + case CANV_WITHTAG: { + if (argc != first+2) { + Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId"); return TCL_ERROR; } - for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search); +#ifdef USE_OLD_TAG_SEARCH + for (itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) { + return TCL_ERROR; + } + for (itemPtr = TagSearchFirst(*searchPtrPtr); + itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ DoItem(interp, itemPtr, uid); } - } else { - Tcl_AppendResult(interp, "bad search command \"", argv[0], - "\": must be above, all, below, closest, enclosed, ", - "overlapping, or withtag", (char *) NULL); - return TCL_ERROR; + } } return TCL_OK; } @@ -2672,9 +4214,9 @@ FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option) * Results: * A standard Tcl return value. If newTag is NULL, then a * list of ids from all the items overlapping or enclosed - * by the rectangle given by argc is returned in interp->result. - * If newTag is NULL, then the normal interp->result is an - * empty string. If an error occurs, then interp->result will + * by the rectangle given by argc is returned in the interp's result. + * If newTag is NULL, then the normal the interp's result is an + * empty string. If an error occurs, then the interp's result will * hold an error message. * * Side effects: @@ -2691,13 +4233,13 @@ FindArea(interp, canvasPtr, argv, uid, enclosed) * and result storing. */ TkCanvas *canvasPtr; /* Canvas whose items are to be * searched. */ - char **argv; /* Array of four arguments that + Tcl_Obj *CONST *argv; /* Array of four arguments that * give the coordinates of the * rectangular area to search. */ Tk_Uid uid; /* If non-NULL, gives new tag to set * on all found items; if NULL, then * ids of found items are returned - * in interp->result. */ + * in the interp's result. */ int enclosed; /* 0 means overlapping or enclosed * items are OK, 1 means only enclosed * items are OK. */ @@ -2706,13 +4248,13 @@ FindArea(interp, canvasPtr, argv, uid, enclosed) int x1, y1, x2, y2; Tk_Item *itemPtr; - if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[0], + if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[0], &rect[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[1], + || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[1], &rect[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[2], + || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[2], &rect[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3], + || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3], &rect[3]) != TCL_OK)) { return TCL_ERROR; } @@ -2734,6 +4276,10 @@ FindArea(interp, canvasPtr, argv, uid, enclosed) y2 = (int) (rect[3]+1.0); for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; itemPtr = itemPtr->nextPtr) { + if (itemPtr->state == TK_STATE_HIDDEN || (itemPtr->state == TK_STATE_NULL && + canvasPtr->canvas_state == TK_STATE_HIDDEN)) { + continue; + } if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1) || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) { continue; @@ -2766,17 +4312,27 @@ FindArea(interp, canvasPtr, argv, uid, enclosed) *-------------------------------------------------------------- */ +#ifdef USE_OLD_TAG_SEARCH static void RelinkItems(canvasPtr, tag, prevPtr) +#else /* USE_OLD_TAG_SEARCH */ +static int +RelinkItems(canvasPtr, tag, prevPtr, searchPtrPtr) +#endif /* USE_OLD_TAG_SEARCH */ TkCanvas *canvasPtr; /* Canvas to be modified. */ - char *tag; /* Tag identifying items to be moved + Tcl_Obj *tag; /* Tag identifying items to be moved * in the redisplay list. */ Tk_Item *prevPtr; /* Reposition the items so that they * go just after this item (NULL means * put at beginning of list). */ +#ifndef USE_OLD_TAG_SEARCH + TagSearch **searchPtrPtr; /* From CanvasWidgetCmd local vars */ +#endif /* not USE_OLD_TAG_SEARCH */ { Tk_Item *itemPtr; +#ifdef USE_OLD_TAG_SEARCH TagSearch search; +#endif /* USE_OLD_TAG_SEARCH */ Tk_Item *firstMovePtr, *lastMovePtr; /* @@ -2786,8 +4342,16 @@ RelinkItems(canvasPtr, tag, prevPtr) */ firstMovePtr = lastMovePtr = NULL; +#ifdef USE_OLD_TAG_SEARCH for (itemPtr = StartTagSearch(canvasPtr, tag, &search); itemPtr != NULL; itemPtr = NextItem(&search)) { +#else /* USE_OLD_TAG_SEARCH */ + if (TagSearchScan(canvasPtr, tag, searchPtrPtr) != TCL_OK) { + return TCL_ERROR; + } + for (itemPtr = TagSearchFirst(*searchPtrPtr); + itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) { +#endif /* USE_OLD_TAG_SEARCH */ if (itemPtr == prevPtr) { /* * Item after which insertion is to occur is being @@ -2818,8 +4382,7 @@ RelinkItems(canvasPtr, tag, prevPtr) lastMovePtr->nextPtr = itemPtr; } lastMovePtr = itemPtr; - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1, itemPtr->y1, - itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); canvasPtr->flags |= REPICK_NEEDED; } @@ -2829,7 +4392,11 @@ RelinkItems(canvasPtr, tag, prevPtr) */ if (firstMovePtr == NULL) { +#ifdef USE_OLD_TAG_SEARCH return; +#else /* USE_OLD_TAG_SEARCH */ + return TCL_OK; +#endif /* USE_OLD_TAG_SEARCH */ } if (prevPtr == NULL) { if (canvasPtr->firstItemPtr != NULL) { @@ -2850,6 +4417,9 @@ RelinkItems(canvasPtr, tag, prevPtr) if (canvasPtr->lastItemPtr == prevPtr) { canvasPtr->lastItemPtr = lastMovePtr; } +#ifndef USE_OLD_TAG_SEARCH + return TCL_OK; +#endif /* not USE_OLD_TAG_SEARCH */ } /* @@ -2967,8 +4537,9 @@ CanvasBindProc(clientData, eventPtr) * Find the topmost item in a canvas that contains a given * location and mark the the current item. If the current * item has changed, generate a fake exit event on the old - * current item and a fake enter event on the new current - * item. + * current item, a fake enter event on the new current item + * item and force a redraw of the two items. Canvas items + * that are hidden or disabled are ignored. * * Results: * None. @@ -2994,6 +4565,7 @@ PickCurrentItem(canvasPtr, eventPtr) { double coords[2]; int buttonDown; + Tk_Item *prevItemPtr; /* * Check whether or not a button is down. If so, we'll log entry @@ -3115,7 +4687,11 @@ PickCurrentItem(canvasPtr, eventPtr) if ((itemPtr == canvasPtr->currentItemPtr) && !buttonDown) { for (i = itemPtr->numTags-1; i >= 0; i--) { +#ifdef USE_OLD_TAG_SEARCH + if (itemPtr->tagPtr[i] == Tk_GetUid("current")) { +#else /* USE_OLD_TAG_SEARCH */ if (itemPtr->tagPtr[i] == currentUid) { +#endif /* USE_OLD_TAG_SEARCH */ itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1]; itemPtr->numTags--; break; @@ -3140,12 +4716,33 @@ PickCurrentItem(canvasPtr, eventPtr) * if LEFT_GRABBED_ITEM was set. */ + prevItemPtr = canvasPtr->currentItemPtr; canvasPtr->flags &= ~LEFT_GRABBED_ITEM; canvasPtr->currentItemPtr = canvasPtr->newCurrentPtr; + if (prevItemPtr != NULL && prevItemPtr != canvasPtr->currentItemPtr && + (prevItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT)) { + EventuallyRedrawItem((Tk_Canvas) canvasPtr, prevItemPtr); + (*prevItemPtr->typePtr->configProc)(canvasPtr->interp, + (Tk_Canvas) canvasPtr, prevItemPtr, 0, (Tcl_Obj **) NULL, + TK_CONFIG_ARGV_ONLY); + } if (canvasPtr->currentItemPtr != NULL) { XEvent event; +#ifdef USE_OLD_TAG_SEARCH + DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr, + Tk_GetUid("current")); +#else /* USE_OLD_TAG_SEARCH */ DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr, currentUid); +#endif /* USE_OLD_TAG_SEA */ + if ((canvasPtr->currentItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT && + prevItemPtr != canvasPtr->currentItemPtr)) { + (*canvasPtr->currentItemPtr->typePtr->configProc)(canvasPtr->interp, + (Tk_Canvas) canvasPtr, canvasPtr->currentItemPtr, 0, (Tcl_Obj **) NULL, + TK_CONFIG_ARGV_ONLY); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->currentItemPtr); + } event = canvasPtr->pickEvent; event.type = EnterNotify; event.xcrossing.detail = NotifyAncestor; @@ -3159,7 +4756,8 @@ PickCurrentItem(canvasPtr, eventPtr) * CanvasFindClosest -- * * Given x and y coordinates, find the topmost canvas item that - * is "close" to the coordinates. + * is "close" to the coordinates. Canvas items that are hidden + * or disabled are ignored. * * Results: * The return value is a pointer to the topmost item that is @@ -3189,6 +4787,11 @@ CanvasFindClosest(canvasPtr, coords) bestPtr = NULL; for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; itemPtr = itemPtr->nextPtr) { + if (itemPtr->state == TK_STATE_HIDDEN || itemPtr->state==TK_STATE_DISABLED || + (itemPtr->state == TK_STATE_NULL && (canvasPtr->canvas_state == TK_STATE_HIDDEN || + canvasPtr->canvas_state == TK_STATE_DISABLED))) { + continue; + } if ((itemPtr->x1 > x2) || (itemPtr->x2 < x1) || (itemPtr->y1 > y2) || (itemPtr->y2 < y1)) { continue; @@ -3233,6 +4836,10 @@ CanvasDoEvent(canvasPtr, eventPtr) ClientData *objectPtr; int numObjects, i; Tk_Item *itemPtr; +#ifndef USE_OLD_TAG_SEARCH + TagSearchExpr *expr; + int numExprs; +#endif /* not USE_OLD_TAG_SEARCH */ if (canvasPtr->bindingTable == NULL) { return; @@ -3246,6 +4853,7 @@ CanvasDoEvent(canvasPtr, eventPtr) return; } +#ifdef USE_OLD_TAG_SEARCH /* * Set up an array with all the relevant objects for processing * this event. The relevant objects are (a) the event's item, @@ -3255,17 +4863,63 @@ CanvasDoEvent(canvasPtr, eventPtr) */ numObjects = itemPtr->numTags + 2; +#else /* USE_OLD_TAG_SEARCH */ + /* + * Set up an array with all the relevant objects for processing + * this event. The relevant objects are: + * (a) the event's item, + * (b) the tags associated with the event's item, + * (c) the expressions that are true for the event's item's tags, and + * (d) the tag "all". + * + * If there are a lot of tags then malloc an array to hold all of + * the objects. + */ + + /* + * flag and count all expressions that match item's tags + */ + numExprs = 0; + expr = canvasPtr->bindTagExprs; + while (expr) { + expr->index = 0; + expr->match = TagSearchEvalExpr(expr, itemPtr); + if (expr->match) { + numExprs++; + } + expr = expr->next; + } + + numObjects = itemPtr->numTags + numExprs + 2; +#endif /* not USE_OLD_TAG_SEARCH */ if (numObjects <= NUM_STATIC) { objectPtr = staticObjects; } else { objectPtr = (ClientData *) ckalloc((unsigned) (numObjects * sizeof(ClientData))); } +#ifdef USE_OLD_TAG_SEARCH + objectPtr[0] = (ClientData) Tk_GetUid("all"); +#else /* USE_OLD_TAG_SEARCH */ objectPtr[0] = (ClientData) allUid; +#endif /* USE_OLD_TAG_SEARCH */ for (i = itemPtr->numTags-1; i >= 0; i--) { objectPtr[i+1] = (ClientData) itemPtr->tagPtr[i]; } objectPtr[itemPtr->numTags+1] = (ClientData) itemPtr; +#ifndef USE_OLD_TAG_SEARCH + /* + * copy uids of matching expressions into object array + */ + i = itemPtr->numTags+2; + expr = canvasPtr->bindTagExprs; + while (expr) { + if (expr->match) { + objectPtr[i++] = (int *) expr->uid; + } + expr = expr->next; + } +#endif /* not USE_OLD_TAG_SEARCH */ /* * Invoke the binding system, then free up the object array if @@ -3320,11 +4974,8 @@ CanvasBlinkProc(clientData) (ClientData) canvasPtr); } if (canvasPtr->textInfo.focusItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.focusItemPtr->x1, - canvasPtr->textInfo.focusItemPtr->y1, - canvasPtr->textInfo.focusItemPtr->x2, - canvasPtr->textInfo.focusItemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->textInfo.focusItemPtr); } } @@ -3367,11 +5018,8 @@ CanvasFocusProc(canvasPtr, gotFocus) canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; } if (canvasPtr->textInfo.focusItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.focusItemPtr->x1, - canvasPtr->textInfo.focusItemPtr->y1, - canvasPtr->textInfo.focusItemPtr->x2, - canvasPtr->textInfo.focusItemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->textInfo.focusItemPtr); } if (canvasPtr->highlightWidth > 0) { canvasPtr->flags |= REDRAW_BORDERS; @@ -3421,11 +5069,8 @@ CanvasSelectTo(canvasPtr, itemPtr, index) Tk_OwnSelection(canvasPtr->tkwin, XA_PRIMARY, CanvasLostSelection, (ClientData) canvasPtr); } else if (canvasPtr->textInfo.selItemPtr != itemPtr) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.selItemPtr->x1, - canvasPtr->textInfo.selItemPtr->y1, - canvasPtr->textInfo.selItemPtr->x2, - canvasPtr->textInfo.selItemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->textInfo.selItemPtr); } canvasPtr->textInfo.selItemPtr = itemPtr; @@ -3443,8 +5088,7 @@ CanvasSelectTo(canvasPtr, itemPtr, index) if ((canvasPtr->textInfo.selectFirst != oldFirst) || (canvasPtr->textInfo.selectLast != oldLast) || (itemPtr != oldSelPtr)) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr); } } @@ -3518,11 +5162,8 @@ CanvasLostSelection(clientData) TkCanvas *canvasPtr = (TkCanvas *) clientData; if (canvasPtr->textInfo.selItemPtr != NULL) { - Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, - canvasPtr->textInfo.selItemPtr->x1, - canvasPtr->textInfo.selItemPtr->y1, - canvasPtr->textInfo.selItemPtr->x2, - canvasPtr->textInfo.selItemPtr->y2); + EventuallyRedrawItem((Tk_Canvas) canvasPtr, + canvasPtr->textInfo.selItemPtr); } canvasPtr->textInfo.selItemPtr = NULL; } @@ -3827,3 +5468,237 @@ CanvasSetOrigin(canvasPtr, xOrigin, yOrigin) canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); } + +/* + *---------------------------------------------------------------------- + * + * GetStringsFromObjs + * + * Results: + * Converts object list into string list. + * + * Side effects: + * Memory is allocated for the argv array, which must + * be freed using ckfree() when no longer needed. + * + *---------------------------------------------------------------------- + */ +/* ARGSUSED */ +static char ** +GetStringsFromObjs(argc, objv) + int argc; + Tcl_Obj *CONST objv[]; +{ + register int i; + char **argv; + if (argc <= 0) { + return NULL; + } + argv = (char **) ckalloc((argc+1) * sizeof(char *)); + for (i = 0; i < argc; i++) { + argv[i]=Tcl_GetStringFromObj(objv[i], (int *) NULL); + } + argv[argc] = 0; + return argv; +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsColor -- + * + * This procedure is called by individual canvas items when + * they want to set a color value for output. Given information + * about an X color, this procedure will generate Postscript + * commands to set up an appropriate color in Postscript. + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasPsColor(interp, canvas, colorPtr) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Tk_Canvas canvas; /* Information about canvas. */ + XColor *colorPtr; /* Information about color. */ +{ + return Tk_PostscriptColor(interp, ((TkCanvas *) canvas)->psInfo, + colorPtr); +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsFont -- + * + * This procedure is called by individual canvas items when + * they want to output text. Given information about an X + * font, this procedure will generate Postscript commands + * to set up an appropriate font in Postscript. + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to the interp->result. + * + * Side effects: + * The Postscript font name is entered into psInfoPtr->fontTable + * if it wasn't already there. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasPsFont(interp, canvas, tkfont) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Tk_Canvas canvas; /* Information about canvas. */ + Tk_Font tkfont; /* Information about font in which text + * is to be printed. */ +{ + return Tk_PostscriptFont(interp, ((TkCanvas *) canvas)->psInfo, tkfont); +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsBitmap -- + * + * This procedure is called to output the contents of a + * sub-region of a bitmap in proper image data format for + * Postscript (i.e. data between angle brackets, one bit + * per pixel). + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Tk_Canvas canvas; /* Information about canvas. */ + Pixmap bitmap; /* Bitmap for which to generate + * Postscript. */ + int startX, startY; /* Coordinates of upper-left corner + * of rectangular region to output. */ + int width, height; /* Height of rectangular region. */ +{ + return Tk_PostscriptBitmap(interp, ((TkCanvas *) canvas)->tkwin, + ((TkCanvas *) canvas)->psInfo, bitmap, startX, startY, + width, height); +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsStipple -- + * + * This procedure is called by individual canvas items when + * they have created a path that they'd like to be filled with + * a stipple pattern. Given information about an X bitmap, + * this procedure will generate Postscript commands to fill + * the current clip region using a stipple pattern defined by the + * bitmap. + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_CanvasPsStipple(interp, canvas, bitmap) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Tk_Canvas canvas; /* Information about canvas. */ + Pixmap bitmap; /* Bitmap to use for stippling. */ +{ + return Tk_PostscriptStipple(interp, ((TkCanvas *) canvas)->tkwin, + ((TkCanvas *) canvas)->psInfo, bitmap); +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsY -- + * + * Given a y-coordinate in canvas coordinates, this procedure + * returns a y-coordinate to use for Postscript output. + * + * Results: + * Returns the Postscript coordinate that corresponds to + * "y". + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +double +Tk_CanvasPsY(canvas, y) + Tk_Canvas canvas; /* Token for canvas on whose behalf + * Postscript is being generated. */ + double y; /* Y-coordinate in canvas coords. */ +{ + return Tk_PostscriptY(y, ((TkCanvas *) canvas)->psInfo); +} + +/* + *-------------------------------------------------------------- + * + * Tk_CanvasPsPath -- + * + * Given an array of points for a path, generate Postscript + * commands to create the path. + * + * Results: + * Postscript commands get appended to what's in interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +Tk_CanvasPsPath(interp, canvas, coordPtr, numPoints) + Tcl_Interp *interp; /* Put generated Postscript in this + * interpreter's result field. */ + Tk_Canvas canvas; /* Canvas on whose behalf Postscript + * is being generated. */ + double *coordPtr; /* Pointer to first in array of + * 2*numPoints coordinates giving + * points for path. */ + int numPoints; /* Number of points at *coordPtr. */ +{ + Tk_PostscriptPath(interp, ((TkCanvas *) canvas)->psInfo, + coordPtr, numPoints); +} + + diff --git a/tk/generic/tkCanvas.h b/tk/generic/tkCanvas.h index 3899225a5fd..103c874aee1 100644 --- a/tk/generic/tkCanvas.h +++ b/tk/generic/tkCanvas.h @@ -21,6 +21,20 @@ #include "tk.h" #endif +#ifndef USE_OLD_TAG_SEARCH +typedef struct TagSearchExpr_s TagSearchExpr; + +struct TagSearchExpr_s { + TagSearchExpr *next; /* for linked lists of expressions - used in bindings */ + Tk_Uid uid; /* the uid of the whole expression */ + Tk_Uid *uids; /* expresion compiled to an array of uids */ + int allocated; /* available space for array of uids */ + int length; /* length of expression */ + int index; /* current position in expression evaluation */ + int match; /* this expression matches event's item's tags*/ +}; +#endif /* not USE_OLD_TAG_SEARCH */ + /* * The record below describes a canvas widget. It is made available * to the item procedures so they can access certain shared fields such @@ -204,12 +218,23 @@ typedef struct TkCanvas { * definitions. */ int nextId; /* Number to use as id for next item * created in widget. */ - struct TkPostscriptInfo *psInfoPtr; + Tk_PostscriptInfo psInfo; /* Pointer to information used for generating * Postscript for the canvas. NULL means * no Postscript is currently being * generated. */ Tcl_HashTable idTable; /* Table of integer indices. */ + /* + * Additional information, added by the 'dash'-patch + */ + VOID *reserved1; + Tk_State canvas_state; /* state of canvas */ + VOID *reserved2; + VOID *reserved3; + Tk_TSOffset tsoffset; +#ifndef USE_OLD_TAG_SEARCH + TagSearchExpr *bindTagExprs; /* linked list of tag expressions used in bindings */ +#endif } TkCanvas; /* @@ -237,6 +262,8 @@ typedef struct TkCanvas { * REPICK_IN_PROGRESS - 1 means PickCurrentItem is currently * executing. If it should be called recursively, * it should simply return immediately. + * BBOX_NOT_EMPTY - 1 means that the bounding box of the area + * that should be redrawn is not empty. */ #define REDRAW_PENDING 1 @@ -247,6 +274,18 @@ typedef struct TkCanvas { #define UPDATE_SCROLLBARS 0x20 #define LEFT_GRABBED_ITEM 0x40 #define REPICK_IN_PROGRESS 0x100 +#define BBOX_NOT_EMPTY 0x200 + +/* + * Flag bits for canvas items (redraw_flags): + * + * FORCE_REDRAW - 1 means that the new coordinates of some + * item are not yet registered using + * Tk_CanvasEventuallyRedraw(). It should still + * be done by the general canvas code. + */ + +#define FORCE_REDRAW 8 /* * Canvas-related procedures that are shared among Tk modules but not @@ -256,4 +295,19 @@ typedef struct TkCanvas { extern int TkCanvPostscriptCmd _ANSI_ARGS_((TkCanvas *canvasPtr, Tcl_Interp *interp, int argc, char **argv)); +/* + * The following definition is shared between tkCanvPs.c and tkCanvImg.c, + * and is used in generating postscript for images and windows. + */ + +typedef struct TkColormapData { /* Hold color information for a window */ + int separated; /* Whether to use separate color bands */ + int color; /* Whether window is color or black/white */ + int ncolors; /* Number of color values stored */ + XColor *colors; /* Pixel value -> RGB mappings */ + int red_mask, green_mask, blue_mask; /* Masks and shifts for each */ + int red_shift, green_shift, blue_shift; /* color band */ +} TkColormapData; + #endif /* _TKCANVAS */ + diff --git a/tk/generic/tkClipboard.c b/tk/generic/tkClipboard.c index c50a80e7c8a..c1a8c81ba5f 100644 --- a/tk/generic/tkClipboard.c +++ b/tk/generic/tkClipboard.c @@ -6,7 +6,7 @@ * supplied on demand to requesting applications. * * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -222,18 +222,18 @@ ClipboardLostSel(clientData) * * Take control of the clipboard and clear out the previous * contents. This procedure must be invoked before any - * calls to Tk_AppendToClipboard. + * calls to Tk_ClipboardAppend. * * Results: * A standard Tcl result. If an error occurs, an error message is - * left in interp->result. + * left in the interp's result. * * Side effects: * From now on, requests for the CLIPBOARD selection will be * directed to the clipboard manager routines associated with * clipWindow for the display of tkwin. In order to guarantee * atomicity, no event handling should occur between - * Tk_ClipboardClear and the following Tk_AppendToClipboard + * Tk_ClipboardClear and the following Tk_ClipboardAppend * calls. This procedure may cause a user-defined LostSel command * to be invoked when the CLIPBOARD is claimed, so any calling * function should be reentrant at the point Tk_ClipboardClear is @@ -307,11 +307,11 @@ Tk_ClipboardClear(interp, tkwin) * be returned. Tk_ClipboardClear must be called before a sequence * of Tk_ClipboardAppend calls can be issued. In order to guarantee * atomicity, no event handling should occur between Tk_ClipboardClear - * and the following Tk_AppendToClipboard calls. + * and the following Tk_ClipboardAppend calls. * * Results: * A standard Tcl result. If an error is returned, an error message - * is left in interp->result. + * is left in the interp's result. * * Side effects: * The specified buffer will be copied onto the end of the clipboard. @@ -528,9 +528,10 @@ Tk_ClipboardCmd(clientData, interp, argc, argv) } return Tk_ClipboardClear(interp, tkwin); } else { - sprintf(interp->result, - "bad option \"%.50s\": must be clear or append", - argv[1]); + char buf[100 + TCL_INTEGER_SPACE]; + + sprintf(buf, "bad option \"%.50s\": must be clear or append", argv[1]); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } } @@ -546,8 +547,8 @@ Tk_ClipboardCmd(clientData, interp, argc, argv) * * Results: * The result is a standard Tcl return value, which is normally TCL_OK. - * If an error occurs then an error message is left in interp->result - * and TCL_ERROR is returned. + * If an error occurs then an error message is left in the interp's + * result and TCL_ERROR is returned. * * Side effects: * Sets up the clipWindow and related data structures. @@ -604,3 +605,4 @@ TkClipInit(interp, dispPtr) (ClientData) dispPtr, XA_STRING); return TCL_OK; } + diff --git a/tk/generic/tkCmds.c b/tk/generic/tkCmds.c index b64c9809f03..78f44ca294a 100644 --- a/tk/generic/tkCmds.c +++ b/tk/generic/tkCmds.c @@ -5,8 +5,7 @@ * that didn't fit in any particular file of the toolkit. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. - * Copyright (c) 1998 by Scriptics Corporation. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -18,6 +17,14 @@ #include "tkInt.h" #include <errno.h> +#if defined(__WIN32__) +#include "tkWinInt.h" +#elif defined(MAC_TCL) +#include "tkMacInt.h" +#else +#include "tkUnixInt.h" +#endif + /* * Forward declarations for procedures defined later in this file: */ @@ -55,12 +62,10 @@ Tk_BellObjCmd(clientData, interp, objc, objv) int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { + static char *bellOptions[] = {"-displayof", (char *) NULL}; Tk_Window tkwin = (Tk_Window) clientData; + char *displayName; int index; - char *string; - static char *optionStrings[] = { - "-displayof", NULL - }; if ((objc != 1) && (objc != 3)) { Tcl_WrongNumArgs(interp, 1, objv, "?-displayof window?"); @@ -68,12 +73,13 @@ Tk_BellObjCmd(clientData, interp, objc, objv) } if (objc == 3) { - if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, + if (Tcl_GetIndexFromObj(interp, objv[1], bellOptions, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } - string = Tcl_GetStringFromObj(objv[2], NULL); - tkwin = Tk_NameToWindow(interp, string, tkwin); + displayName = Tcl_GetStringFromObj(objv[2], (int *) NULL); + + tkwin = Tk_NameToWindow(interp, displayName, tkwin); if (tkwin == NULL) { return TCL_ERROR; } @@ -154,7 +160,7 @@ Tk_BindCmd(clientData, interp, argc, argv) Tcl_ResetResult(interp); return TCL_OK; } - interp->result = command; + Tcl_SetResult(interp, command, TCL_STATIC); } else { Tk_GetAllBindings(interp, winPtr->mainPtr->bindingTable, object); } @@ -186,7 +192,6 @@ TkBindEventProc(winPtr, eventPtr) { #define MAX_OBJS 20 ClientData objects[MAX_OBJS], *objPtr; - static Tk_Uid allUid = NULL; TkWindow *topLevPtr; int i, count; char *p; @@ -234,10 +239,7 @@ TkBindEventProc(winPtr, eventPtr) } else { count = 3; } - if (allUid == NULL) { - allUid = Tk_GetUid("all"); - } - objPtr[count-1] = (ClientData) allUid; + objPtr[count-1] = (ClientData) Tk_GetUid("all"); } Tk_BindEvent(winPtr->mainPtr->bindingTable, eventPtr, (Tk_Window) winPtr, count, objPtr); @@ -383,7 +385,7 @@ TkFreeBindingTags(winPtr) /* *---------------------------------------------------------------------- * - * Tk_DestroyCmd -- + * Tk_DestroyObjCmd -- * * This procedure is invoked to process the "destroy" Tcl command. * See the user documentation for details on what it does. @@ -398,19 +400,19 @@ TkFreeBindingTags(winPtr) */ int -Tk_DestroyCmd(clientData, interp, argc, argv) +Tk_DestroyObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tk_Window window; Tk_Window tkwin = (Tk_Window) clientData; int i; - for (i = 1; i < argc; i++) { - window = Tk_NameToWindow(interp, argv[i], tkwin); + for (i = 1; i < objc; i++) { + window = Tk_NameToWindow(interp, Tcl_GetString(objv[i]), tkwin); if (window == NULL) { Tcl_ResetResult(interp); continue; @@ -432,7 +434,7 @@ Tk_DestroyCmd(clientData, interp, argc, argv) /* *---------------------------------------------------------------------- * - * Tk_LowerCmd -- + * Tk_LowerObjCmd -- * * This procedure is invoked to process the "lower" Tcl command. * See the user documentation for details on what it does. @@ -448,37 +450,37 @@ Tk_DestroyCmd(clientData, interp, argc, argv) /* ARGSUSED */ int -Tk_LowerCmd(clientData, interp, argc, argv) +Tk_LowerObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tk_Window mainwin = (Tk_Window) clientData; Tk_Window tkwin, other; - if ((argc != 2) && (argc != 3)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " window ?belowThis?\"", (char *) NULL); + if ((objc != 2) && (objc != 3)) { + Tcl_WrongNumArgs(interp, 1, objv, "window ?belowThis?"); return TCL_ERROR; } - tkwin = Tk_NameToWindow(interp, argv[1], mainwin); + tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[1]), mainwin); if (tkwin == NULL) { return TCL_ERROR; } - if (argc == 2) { + if (objc == 2) { other = NULL; } else { - other = Tk_NameToWindow(interp, argv[2], mainwin); + other = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), mainwin); if (other == NULL) { return TCL_ERROR; } } if (Tk_RestackWindow(tkwin, Below, other) != TCL_OK) { - Tcl_AppendResult(interp, "can't lower \"", argv[1], "\" below \"", - argv[2], "\"", (char *) NULL); + Tcl_AppendResult(interp, "can't lower \"", Tcl_GetString(objv[1]), + "\" below \"", (other ? Tcl_GetString(objv[2]) : ""), + "\"", (char *) NULL); return TCL_ERROR; } return TCL_OK; @@ -487,7 +489,7 @@ Tk_LowerCmd(clientData, interp, argc, argv) /* *---------------------------------------------------------------------- * - * Tk_RaiseCmd -- + * Tk_RaiseObjCmd -- * * This procedure is invoked to process the "raise" Tcl command. * See the user documentation for details on what it does. @@ -503,37 +505,37 @@ Tk_LowerCmd(clientData, interp, argc, argv) /* ARGSUSED */ int -Tk_RaiseCmd(clientData, interp, argc, argv) +Tk_RaiseObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tk_Window mainwin = (Tk_Window) clientData; Tk_Window tkwin, other; - if ((argc != 2) && (argc != 3)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " window ?aboveThis?\"", (char *) NULL); + if ((objc != 2) && (objc != 3)) { + Tcl_WrongNumArgs(interp, 1, objv, "window ?aboveThis?"); return TCL_ERROR; } - tkwin = Tk_NameToWindow(interp, argv[1], mainwin); + tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[1]), mainwin); if (tkwin == NULL) { return TCL_ERROR; } - if (argc == 2) { + if (objc == 2) { other = NULL; } else { - other = Tk_NameToWindow(interp, argv[2], mainwin); + other = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), mainwin); if (other == NULL) { return TCL_ERROR; } } if (Tk_RestackWindow(tkwin, Above, other) != TCL_OK) { - Tcl_AppendResult(interp, "can't raise \"", argv[1], "\" above \"", - argv[2], "\"", (char *) NULL); + Tcl_AppendResult(interp, "can't raise \"", Tcl_GetString(objv[1]), + "\" above \"", (other ? Tcl_GetString(objv[2]) : ""), + "\"", (char *) NULL); return TCL_ERROR; } return TCL_OK; @@ -566,10 +568,10 @@ Tk_TkObjCmd(clientData, interp, objc, objv) int index; Tk_Window tkwin; static char *optionStrings[] = { - "appname", "scaling", NULL + "appname", "scaling", "useinputmethods", NULL }; enum options { - TK_APPNAME, TK_SCALING + TK_APPNAME, TK_SCALING, TK_USE_IM }; tkwin = (Tk_Window) clientData; @@ -598,14 +600,14 @@ Tk_TkObjCmd(clientData, interp, objc, objv) string = Tcl_GetStringFromObj(objv[2], NULL); winPtr->nameUid = Tk_GetUid(Tk_SetAppName(tkwin, string)); } - Tcl_SetStringObj(Tcl_GetObjResult(interp), winPtr->nameUid, -1); + Tcl_AppendResult(interp, winPtr->nameUid, NULL); break; } case TK_SCALING: { Screen *screenPtr; int skip, width, height; double d; - + screenPtr = Tk_Screen(tkwin); skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin); @@ -618,7 +620,7 @@ Tk_TkObjCmd(clientData, interp, objc, objv) d /= WidthMMOfScreen(screenPtr); Tcl_SetDoubleObj(Tcl_GetObjResult(interp), d); } else if (objc - skip == 3) { - if (Tcl_GetDoubleFromObj(interp, objv[2 + skip], &d) != TCL_OK) { + if (Tcl_GetDoubleFromObj(interp, objv[2+skip], &d) != TCL_OK) { return TCL_ERROR; } d = (25.4 / 72) / d; @@ -639,6 +641,40 @@ Tk_TkObjCmd(clientData, interp, objc, objv) } break; } + case TK_USE_IM: { + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + int skip; + + skip = TkGetDisplayOf(interp, objc-2, objv+2, &tkwin); + if (skip < 0) { + return TCL_ERROR; + } else if (skip) { + dispPtr = ((TkWindow *) tkwin)->dispPtr; + } + if ((objc - skip) == 3) { + /* + * In the case where TK_USE_INPUT_METHODS is not defined, + * this will be ignored and we will always return 0. + * That will indicate to the user that input methods + * are just not available. + */ + int bool; + if (Tcl_GetBooleanFromObj(interp, objv[2+skip], &bool) + != TCL_OK) { + return TCL_ERROR; + } +#ifdef TK_USE_INPUT_METHODS + dispPtr->useInputMethods = bool; +#endif /* TK_USE_INPUT_METHODS */ + } else if ((objc - skip) != 2) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-displayof window? ?boolean?"); + return TCL_ERROR; + } + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), + dispPtr->useInputMethods); + break; + } } return TCL_OK; } @@ -800,7 +836,7 @@ WaitWindowProc(clientData, eventPtr) /* *---------------------------------------------------------------------- * - * Tk_UpdateCmd -- + * Tk_UpdateObjCmd -- * * This procedure is invoked to process the "update" Tcl command. * See the user documentation for details on what it does. @@ -816,28 +852,27 @@ WaitWindowProc(clientData, eventPtr) /* ARGSUSED */ int -Tk_UpdateCmd(clientData, interp, argc, argv) +Tk_UpdateObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - int flags; + static char *updateOptions[] = {"idletasks", (char *) NULL}; + int flags, index; TkDisplay *dispPtr; - if (argc == 1) { + if (objc == 1) { flags = TCL_DONT_WAIT; - } else if (argc == 2) { - if (strncmp(argv[1], "idletasks", strlen(argv[1])) != 0) { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be idletasks", (char *) NULL); + } else if (objc == 2) { + if (Tcl_GetIndexFromObj(interp, objv[1], updateOptions, "option", 0, + &index) != TCL_OK) { return TCL_ERROR; } flags = TCL_IDLE_EVENTS; } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " ?idletasks?\"", (char *) NULL); + Tcl_WrongNumArgs(interp, 1, objv, "?idletasks?"); return TCL_ERROR; } @@ -849,12 +884,12 @@ Tk_UpdateCmd(clientData, interp, argc, argv) * Thus, don't use any information from tkwin after calling * Tcl_DoOneEvent. */ - + while (1) { while (Tcl_DoOneEvent(flags) != 0) { /* Empty loop body */ } - for (dispPtr = tkDisplayList; dispPtr != NULL; + for (dispPtr = TkGetDisplayList(); dispPtr != NULL; dispPtr = dispPtr->nextPtr) { XSync(dispPtr->display, False); } @@ -898,10 +933,10 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) Tcl_Obj *CONST objv[]; /* Argument objects. */ { int index, x, y, width, height, useX, useY, class, skip; - char buf[128]; char *string; TkWindow *winPtr; Tk_Window tkwin; + Tcl_Obj *resultPtr; static TkStateMap visualMap[] = { {PseudoColor, "pseudocolor"}, @@ -974,85 +1009,73 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) } } winPtr = (TkWindow *) tkwin; + resultPtr = Tcl_GetObjResult(interp); switch ((enum options) index) { case WIN_CELLS: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - Tk_Visual(tkwin)->map_entries); + Tcl_SetIntObj(resultPtr, Tk_Visual(tkwin)->map_entries); break; } case WIN_CHILDREN: { Tcl_Obj *strPtr; - Tcl_ResetResult(interp); winPtr = winPtr->childList; for ( ; winPtr != NULL; winPtr = winPtr->nextPtr) { strPtr = Tcl_NewStringObj(winPtr->pathName, -1); - Tcl_ListObjAppendElement(NULL, - Tcl_GetObjResult(interp), strPtr); + Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); } break; } case WIN_CLASS: { - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), Tk_Class(tkwin), -1); + Tcl_SetStringObj(resultPtr, Tk_Class(tkwin), -1); break; } case WIN_COLORMAPFULL: { - Tcl_ResetResult(interp); - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), + Tcl_SetBooleanObj(resultPtr, TkpCmapStressed(tkwin, Tk_Colormap(tkwin))); break; } case WIN_DEPTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_Depth(tkwin)); + Tcl_SetIntObj(resultPtr, Tk_Depth(tkwin)); break; } case WIN_GEOMETRY: { - Tcl_ResetResult(interp); + char buf[16 + TCL_INTEGER_SPACE * 4]; + sprintf(buf, "%dx%d+%d+%d", Tk_Width(tkwin), Tk_Height(tkwin), Tk_X(tkwin), Tk_Y(tkwin)); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); + Tcl_SetStringObj(resultPtr, buf, -1); break; } case WIN_HEIGHT: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_Height(tkwin)); + Tcl_SetIntObj(resultPtr, Tk_Height(tkwin)); break; } case WIN_ID: { + char buf[TCL_INTEGER_SPACE]; + Tk_MakeWindowExist(tkwin); TkpPrintWindowId(buf, Tk_WindowId(tkwin)); - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); + Tcl_SetStringObj(resultPtr, buf, -1); break; } case WIN_ISMAPPED: { - Tcl_ResetResult(interp); - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), - (int) Tk_IsMapped(tkwin)); + Tcl_SetBooleanObj(resultPtr, (int) Tk_IsMapped(tkwin)); break; } case WIN_MANAGER: { - Tcl_ResetResult(interp); if (winPtr->geomMgrPtr != NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), - winPtr->geomMgrPtr->name, -1); + Tcl_SetStringObj(resultPtr, winPtr->geomMgrPtr->name, -1); } break; } case WIN_NAME: { - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), Tk_Name(tkwin), -1); + Tcl_SetStringObj(resultPtr, Tk_Name(tkwin), -1); break; } case WIN_PARENT: { - Tcl_ResetResult(interp); if (winPtr->parentPtr != NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), - winPtr->parentPtr->pathName, -1); + Tcl_SetStringObj(resultPtr, winPtr->parentPtr->pathName, -1); } break; } @@ -1078,80 +1101,66 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) } else { TkGetPointerCoords((Tk_Window) winPtr, &x, &y); } - Tcl_ResetResult(interp); if (useX & useY) { + char buf[TCL_INTEGER_SPACE * 2]; + sprintf(buf, "%d %d", x, y); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); + Tcl_SetStringObj(resultPtr, buf, -1); } else if (useX) { - Tcl_SetIntObj(Tcl_GetObjResult(interp), x); + Tcl_SetIntObj(resultPtr, x); } else { - Tcl_SetIntObj(Tcl_GetObjResult(interp), y); + Tcl_SetIntObj(resultPtr, y); } break; } case WIN_REQHEIGHT: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_ReqHeight(tkwin)); + Tcl_SetIntObj(resultPtr, Tk_ReqHeight(tkwin)); break; } case WIN_REQWIDTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_ReqWidth(tkwin)); + Tcl_SetIntObj(resultPtr, Tk_ReqWidth(tkwin)); break; } case WIN_ROOTX: { Tk_GetRootCoords(tkwin, &x, &y); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), x); + Tcl_SetIntObj(resultPtr, x); break; } case WIN_ROOTY: { Tk_GetRootCoords(tkwin, &x, &y); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), y); + Tcl_SetIntObj(resultPtr, y); break; } case WIN_SCREEN: { + char buf[TCL_INTEGER_SPACE]; + sprintf(buf, "%d", Tk_ScreenNumber(tkwin)); - Tcl_ResetResult(interp); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - Tk_DisplayName(tkwin), ".", buf, NULL); + Tcl_AppendStringsToObj(resultPtr, Tk_DisplayName(tkwin), ".", + buf, NULL); break; } case WIN_SCREENCELLS: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - CellsOfScreen(Tk_Screen(tkwin))); + Tcl_SetIntObj(resultPtr, CellsOfScreen(Tk_Screen(tkwin))); break; } case WIN_SCREENDEPTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - DefaultDepthOfScreen(Tk_Screen(tkwin))); + Tcl_SetIntObj(resultPtr, DefaultDepthOfScreen(Tk_Screen(tkwin))); break; } case WIN_SCREENHEIGHT: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - HeightOfScreen(Tk_Screen(tkwin))); + Tcl_SetIntObj(resultPtr, HeightOfScreen(Tk_Screen(tkwin))); break; } case WIN_SCREENWIDTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - WidthOfScreen(Tk_Screen(tkwin))); + Tcl_SetIntObj(resultPtr, WidthOfScreen(Tk_Screen(tkwin))); break; } case WIN_SCREENMMHEIGHT: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - HeightMMOfScreen(Tk_Screen(tkwin))); + Tcl_SetIntObj(resultPtr, HeightMMOfScreen(Tk_Screen(tkwin))); break; } case WIN_SCREENMMWIDTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), - WidthMMOfScreen(Tk_Screen(tkwin))); + Tcl_SetIntObj(resultPtr, WidthMMOfScreen(Tk_Screen(tkwin))); break; } case WIN_SCREENVISUAL: { @@ -1165,16 +1174,12 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) case WIN_TOPLEVEL: { winPtr = GetToplevel(tkwin); if (winPtr != NULL) { - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), - winPtr->pathName, -1); + Tcl_SetStringObj(resultPtr, winPtr->pathName, -1); } break; } case WIN_VIEWABLE: { - int viewable; - - viewable = 0; + int viewable = 0; for ( ; ; winPtr = winPtr->parentPtr) { if ((winPtr == NULL) || !(winPtr->flags & TK_MAPPED)) { break; @@ -1184,8 +1189,8 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) break; } } - Tcl_ResetResult(interp); - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), viewable); + + Tcl_SetBooleanObj(resultPtr, viewable); break; } case WIN_VISUAL: { @@ -1196,54 +1201,47 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) if (string == NULL) { string = "unknown"; } - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), string, -1); + Tcl_SetStringObj(resultPtr, string, -1); break; } case WIN_VISUALID: { - Tcl_ResetResult(interp); + char buf[TCL_INTEGER_SPACE]; + sprintf(buf, "0x%x", (unsigned int) XVisualIDFromVisual(Tk_Visual(tkwin))); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); + Tcl_SetStringObj(resultPtr, buf, -1); break; } case WIN_VROOTHEIGHT: { Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), height); + Tcl_SetIntObj(resultPtr, height); break; } case WIN_VROOTWIDTH: { Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), width); + Tcl_SetIntObj(resultPtr, width); break; } case WIN_VROOTX: { Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), x); + Tcl_SetIntObj(resultPtr, x); break; } case WIN_VROOTY: { Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), y); + Tcl_SetIntObj(resultPtr, y); break; } case WIN_WIDTH: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_Width(tkwin)); + Tcl_SetIntObj(resultPtr, Tk_Width(tkwin)); break; } case WIN_X: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_X(tkwin)); + Tcl_SetIntObj(resultPtr, Tk_X(tkwin)); break; } case WIN_Y: { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_Y(tkwin)); + Tcl_SetIntObj(resultPtr, Tk_Y(tkwin)); break; } @@ -1262,9 +1260,7 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) } objv += skip; string = Tcl_GetStringFromObj(objv[2], NULL); - Tcl_ResetResult(interp); - Tcl_SetLongObj(Tcl_GetObjResult(interp), - (long) Tk_InternAtom(tkwin, string)); + Tcl_SetLongObj(resultPtr, (long) Tk_InternAtom(tkwin, string)); break; } case WIN_ATOMNAME: { @@ -1283,15 +1279,14 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) if (Tcl_GetLongFromObj(interp, objv[2], &id) != TCL_OK) { return TCL_ERROR; } - Tcl_ResetResult(interp); name = Tk_GetAtomName(tkwin, (Atom) id); if (strcmp(name, "?bad atom?") == 0) { string = Tcl_GetStringFromObj(objv[2], NULL); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + Tcl_AppendStringsToObj(resultPtr, "no atom exists with id \"", string, "\"", NULL); return TCL_ERROR; } - Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1); + Tcl_SetStringObj(resultPtr, name, -1); break; } case WIN_CONTAINING: { @@ -1315,9 +1310,7 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) } tkwin = Tk_CoordsToWindow(x, y, tkwin); if (tkwin != NULL) { - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), - Tk_PathName(tkwin), -1); + Tcl_SetStringObj(resultPtr, Tk_PathName(tkwin), -1); } break; } @@ -1354,9 +1347,7 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) Tk_IdToWindow(Tk_Display(tkwin), (Window) id); if ((winPtr == NULL) || (winPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr)) { - Tcl_ResetResult(interp); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "window id \"", string, + Tcl_AppendStringsToObj(resultPtr, "window id \"", string, "\" doesn't exist in this application", (char *) NULL); return TCL_ERROR; } @@ -1369,9 +1360,7 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) tkwin = (Tk_Window) winPtr; if (Tk_PathName(tkwin) != NULL) { - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), - Tk_PathName(tkwin), -1); + Tcl_SetStringObj(resultPtr, Tk_PathName(tkwin), -1); } break; } @@ -1389,12 +1378,14 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) } string = Tcl_GetStringFromObj(objv[2], NULL); winPtr = (TkWindow *) Tk_NameToWindow(interp, string, tkwin); + Tcl_ResetResult(interp); + resultPtr = Tcl_GetObjResult(interp); + alive = 1; if ((winPtr == NULL) || (winPtr->flags & TK_ALREADY_DEAD)) { alive = 0; } - Tcl_ResetResult(interp); /* clear any error msg */ - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), alive); + Tcl_SetBooleanObj(resultPtr, alive); break; } case WIN_FPIXELS: { @@ -1414,9 +1405,8 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) return TCL_ERROR; } pixels = mm * WidthOfScreen(Tk_Screen(tkwin)) - / WidthMMOfScreen(Tk_Screen(tkwin)); - Tcl_ResetResult(interp); - Tcl_SetDoubleObj(Tcl_GetObjResult(interp), pixels); + / WidthMMOfScreen(Tk_Screen(tkwin)); + Tcl_SetDoubleObj(resultPtr, pixels); break; } case WIN_PIXELS: { @@ -1435,12 +1425,12 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) if (Tk_GetPixels(interp, tkwin, string, &pixels) != TCL_OK) { return TCL_ERROR; } - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), pixels); + Tcl_SetIntObj(resultPtr, pixels); break; } case WIN_RGB: { XColor *colorPtr; + char buf[TCL_INTEGER_SPACE * 3]; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "window colorName"); @@ -1459,16 +1449,16 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) sprintf(buf, "%d %d %d", colorPtr->red, colorPtr->green, colorPtr->blue); Tk_FreeColor(colorPtr); - Tcl_ResetResult(interp); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); + Tcl_SetStringObj(resultPtr, buf, -1); break; } case WIN_VISUALSAVAILABLE: { XVisualInfo template, *visInfoPtr; int count, i; - char visualIdString[16]; int includeVisualId; Tcl_Obj *strPtr; + char buf[16 + TCL_INTEGER_SPACE]; + char visualIdString[TCL_INTEGER_SPACE]; if (objc == 3) { includeVisualId = 0; @@ -1490,9 +1480,8 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) template.screen = Tk_ScreenNumber(tkwin); visInfoPtr = XGetVisualInfo(Tk_Display(tkwin), VisualScreenMask, &template, &count); - Tcl_ResetResult(interp); if (visInfoPtr == NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), + Tcl_SetStringObj(resultPtr, "can't find any visuals for screen", -1); return TCL_ERROR; } @@ -1509,8 +1498,7 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) strcat(buf, visualIdString); } strPtr = Tcl_NewStringObj(buf, -1); - Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), - strPtr); + Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); } XFree((char *) visInfoPtr); break; @@ -1519,6 +1507,221 @@ Tk_WinfoObjCmd(clientData, interp, objc, objv) return TCL_OK; } +#if 0 +/* + *---------------------------------------------------------------------- + * + * Tk_WmObjCmd -- + * + * This procedure is invoked to process the "wm" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tk_WmObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Main window associated with + * interpreter. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + Tk_Window tkwin; + TkWindow *winPtr; + + static char *optionStrings[] = { + "aspect", "client", "command", "deiconify", + "focusmodel", "frame", "geometry", "grid", + "group", "iconbitmap", "iconify", "iconmask", + "iconname", "iconposition", "iconwindow", "maxsize", + "minsize", "overrideredirect", "positionfrom", "protocol", + "resizable", "sizefrom", "state", "title", + "tracing", "transient", "withdraw", (char *) NULL + }; + enum options { + TKWM_ASPECT, TKWM_CLIENT, TKWM_COMMAND, TKWM_DEICONIFY, + TKWM_FOCUSMOD, TKWM_FRAME, TKWM_GEOMETRY, TKWM_GRID, + TKWM_GROUP, TKWM_ICONBMP, TKWM_ICONIFY, TKWM_ICONMASK, + TKWM_ICONNAME, TKWM_ICONPOS, TKWM_ICONWIN, TKWM_MAXSIZE, + TKWM_MINSIZE, TKWM_OVERRIDE, TKWM_POSFROM, TKWM_PROTOCOL, + TKWM_RESIZABLE, TKWM_SIZEFROM, TKWM_STATE, TKWM_TITLE, + TKWM_TRACING, TKWM_TRANSIENT, TKWM_WITHDRAW + }; + + tkwin = (Tk_Window) clientData; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option window ?arg?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + + if (index == TKWM_TRACING) { + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + + if ((objc != 2) && (objc != 3)) { + Tcl_WrongNumArgs(interp, 1, objv, "tracing ?boolean?"); + return TCL_ERROR; + } + if (objc == 2) { + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(dispPtr->wmTracing)); + return TCL_OK; + } + return Tcl_GetBooleanFromObj(interp, objv[2], &dispPtr->wmTracing); + } + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "window ?arg?"); + return TCL_ERROR; + } + + winPtr = (TkWindow *) Tk_NameToWindow(interp, + Tcl_GetString(objv[2]), tkwin); + if (winPtr == NULL) { + return TCL_ERROR; + } + if (!(winPtr->flags & TK_TOP_LEVEL)) { + Tcl_AppendResult(interp, "window \"", winPtr->pathName, + "\" isn't a top-level window", (char *) NULL); + return TCL_ERROR; + } + + switch ((enum options) index) { + case TKWM_ASPECT: { + TkpWmAspectCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_CLIENT: { + TkpWmClientCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_COMMAND: { + TkpWmCommandCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_DEICONIFY: { + TkpWmDeiconifyCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_FOCUSMOD: { + TkpWmFocusmodCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_FRAME: { + TkpWmFrameCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_GEOMETRY: { + TkpWmGeometryCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_GRID: { + TkpWmGridCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_GROUP: { + TkpWmGroupCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_ICONBMP: { + TkpWmIconbitmapCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_ICONIFY: { + TkpWmIconifyCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_ICONMASK: { + TkpWmIconmaskCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_ICONNAME: { + /* slight Unix variation */ + TkpWmIconnameCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_ICONPOS: { + /* nearly same - 1 line more on Unix */ + TkpWmIconpositionCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_ICONWIN: { + TkpWmIconwindowCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_MAXSIZE: { + /* nearly same, win diffs */ + TkpWmMaxsizeCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_MINSIZE: { + /* nearly same, win diffs */ + TkpWmMinsizeCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_OVERRIDE: { + /* almost same */ + TkpWmOverrideCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_POSFROM: { + /* Equal across platforms */ + TkpWmPositionfromCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_PROTOCOL: { + /* Equal across platforms */ + TkpWmProtocolCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_RESIZABLE: { + /* almost same */ + TkpWmResizableCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_SIZEFROM: { + /* Equal across platforms */ + TkpWmSizefromCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_STATE: { + TkpWmStateCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_TITLE: { + TkpWmTitleCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_TRANSIENT: { + TkpWmTransientCmd(interp, tkwin, winPtr, objc, objv); + break; + } + case TKWM_WITHDRAW: { + TkpWmWithdrawCmd(interp, tkwin, winPtr, objc, objv); + break; + } + } + + updateGeom: + if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { + Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); + wmPtr->flags |= WM_UPDATE_PENDING; + } + return TCL_OK; +} +#endif + /* *---------------------------------------------------------------------- * @@ -1567,7 +1770,8 @@ TkGetDisplayOf(interp, objc, objv, tkwinPtr) return 0; } string = Tcl_GetStringFromObj(objv[0], &length); - if ((length >= 2) && (strncmp(string, "-displayof", (unsigned) length) == 0)) { + if ((length >= 2) && + (strncmp(string, "-displayof", (unsigned) length) == 0)) { if (objc < 2) { Tcl_SetStringObj(Tcl_GetObjResult(interp), "value for \"-displayof\" missing", -1); @@ -1647,3 +1851,5 @@ GetToplevel(tkwin) } return winPtr; } + + diff --git a/tk/generic/tkColor.c b/tk/generic/tkColor.c index c5844781015..19659fcf159 100644 --- a/tk/generic/tkColor.c +++ b/tk/generic/tkColor.c @@ -6,7 +6,7 @@ * map color names to pixel values. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -14,72 +14,149 @@ * RCS: @(#) $Id$ */ -#include <tkColor.h> +#include "tkColor.h" /* - * A two-level data structure is used to manage the color database. - * The top level consists of one entry for each color name that is - * currently active, and the bottom level contains one entry for each - * pixel value that is still in use. The distinction between - * levels is necessary because the same pixel may have several - * different names. There are two hash tables, one used to index into - * each of the data structures. The name hash table is used when - * allocating colors, and the pixel hash table is used when freeing - * colors. + * Structures of the following following type are used as keys for + * colorValueTable (in TkDisplay). */ - -/* - * Hash table for name -> TkColor mapping, and key structure used to - * index into that table: - */ - -static Tcl_HashTable nameTable; typedef struct { - Tk_Uid name; /* Name of desired color. */ + int red, green, blue; /* Values for desired color. */ Colormap colormap; /* Colormap from which color will be * allocated. */ Display *display; /* Display for colormap. */ -} NameKey; +} ValueKey; + /* - * Hash table for value -> TkColor mapping, and key structure used to - * index into that table: + * The structure below is used to allocate thread-local data. */ -static Tcl_HashTable valueTable; -typedef struct { - int red, green, blue; /* Values for desired color. */ - Colormap colormap; /* Colormap from which color will be - * allocated. */ - Display *display; /* Display for colormap. */ -} ValueKey; - -static int initialized = 0; /* 0 means static structures haven't been - * initialized yet. */ +typedef struct ThreadSpecificData { + char rgbString[20]; /* */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; /* * Forward declarations for procedures defined in this file: */ -static void ColorInit _ANSI_ARGS_((void)); +static void ColorInit _ANSI_ARGS_((TkDisplay *dispPtr)); +static void DupColorObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr, + Tcl_Obj *dupObjPtr)); +static void FreeColorObjProc _ANSI_ARGS_((Tcl_Obj *objPtr)); +static void InitColorObj _ANSI_ARGS_((Tcl_Obj *objPtr)); -/* CYGNUS LOCAL. */ - -/* A linked list of GC structures. */ +/* + * The following structure defines the implementation of the "color" Tcl + * object, which maps a string color name to a TkColor object. The + * ptr1 field of the Tcl_Obj points to a TkColor object. + */ -struct TkGCList { - /* Next item on list. */ - TkGCList *next; - /* The display for the GC. */ - Display *display; - /* The GC. */ - GC gc; - /* GCForeground or GCBackground. */ - unsigned long mask; +static Tcl_ObjType colorObjType = { + "color", /* name */ + FreeColorObjProc, /* freeIntRepProc */ + DupColorObjProc, /* dupIntRepProc */ + NULL, /* updateStringProc */ + NULL /* setFromAnyProc */ }; + +/* + *---------------------------------------------------------------------- + * + * Tk_AllocColorFromObj -- + * + * Given a Tcl_Obj *, map the value to a corresponding + * XColor structure based on the tkwin given. + * + * Results: + * The return value is a pointer to an XColor structure that + * indicates the red, blue, and green intensities for the color + * given by the string in objPtr, and also specifies a pixel value + * to use to draw in that color. If an error occurs, NULL is + * returned and an error message will be left in interp's result + * (unless interp is NULL). + * + * Side effects: + * The color is added to an internal database with a reference count. + * For each call to this procedure, there should eventually be a call + * to Tk_FreeColorFromObj so that the database is cleaned up when colors + * aren't in use anymore. + * + *---------------------------------------------------------------------- + */ -/* END CYGNUS LOCAL */ +XColor * +Tk_AllocColorFromObj(interp, tkwin, objPtr) + Tcl_Interp *interp; /* Used only for error reporting. If NULL, + * then no messages are provided. */ + Tk_Window tkwin; /* Window in which the color will be used.*/ + Tcl_Obj *objPtr; /* Object that describes the color; string + * value is a color name such as "red" or + * "#ff0000".*/ +{ + TkColor *tkColPtr; + + if (objPtr->typePtr != &colorObjType) { + InitColorObj(objPtr); + } + tkColPtr = (TkColor *) objPtr->internalRep.twoPtrValue.ptr1; + + /* + * If the object currently points to a TkColor, see if it's the + * one we want. If so, increment its reference count and return. + */ + + if (tkColPtr != NULL) { + if (tkColPtr->resourceRefCount == 0) { + /* + * This is a stale reference: it refers to a TkColor that's + * no longer in use. Clear the reference. + */ + + FreeColorObjProc(objPtr); + tkColPtr = NULL; + } else if ((Tk_Screen(tkwin) == tkColPtr->screen) + && (Tk_Colormap(tkwin) == tkColPtr->colormap)) { + tkColPtr->resourceRefCount++; + return (XColor *) tkColPtr; + } + } + + /* + * The object didn't point to the TkColor that we wanted. Search + * the list of TkColors with the same name to see if one of the + * other TkColors is the right one. + */ + + if (tkColPtr != NULL) { + TkColor *firstColorPtr = + (TkColor *) Tcl_GetHashValue(tkColPtr->hashPtr); + FreeColorObjProc(objPtr); + for (tkColPtr = firstColorPtr; tkColPtr != NULL; + tkColPtr = tkColPtr->nextPtr) { + if ((Tk_Screen(tkwin) == tkColPtr->screen) + && (Tk_Colormap(tkwin) == tkColPtr->colormap)) { + tkColPtr->resourceRefCount++; + tkColPtr->objRefCount++; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) tkColPtr; + return (XColor *) tkColPtr; + } + } + } + + /* + * Still no luck. Call Tk_GetColor to allocate a new TkColor object. + */ + + tkColPtr = (TkColor *) Tk_GetColor(interp, tkwin, Tcl_GetString(objPtr)); + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) tkColPtr; + if (tkColPtr != NULL) { + tkColPtr->objRefCount++; + } + return (XColor *) tkColPtr; +} /* *---------------------------------------------------------------------- @@ -94,7 +171,7 @@ struct TkGCList { * indicates the red, blue, and green intensities for the color * given by "name", and also specifies a pixel value to use to * draw in that color. If an error occurs, NULL is returned and - * an error message will be left in interp->result. + * an error message will be left in the interp's result. * * Side effects: * The color is added to an internal database with a reference count. @@ -110,17 +187,17 @@ Tk_GetColor(interp, tkwin, name) Tcl_Interp *interp; /* Place to leave error message if * color can't be found. */ Tk_Window tkwin; /* Window in which color will be used. */ - Tk_Uid name; /* Name of color to allocated (in form + char *name; /* Name of color to be allocated (in form * suitable for passing to XParseColor). */ { - NameKey nameKey; Tcl_HashEntry *nameHashPtr; int new; TkColor *tkColPtr; - Display *display = Tk_Display(tkwin); + TkColor *existingColPtr; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - if (!initialized) { - ColorInit(); + if (!dispPtr->colorInit) { + ColorInit(dispPtr); } /* @@ -128,14 +205,19 @@ Tk_GetColor(interp, tkwin, name) * name. */ - nameKey.name = name; - nameKey.colormap = Tk_Colormap(tkwin); - nameKey.display = display; - nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new); + nameHashPtr = Tcl_CreateHashEntry(&dispPtr->colorNameTable, name, &new); if (!new) { - tkColPtr = (TkColor *) Tcl_GetHashValue(nameHashPtr); - tkColPtr->refCount++; - return &tkColPtr->color; + existingColPtr = (TkColor *) Tcl_GetHashValue(nameHashPtr); + for (tkColPtr = existingColPtr; tkColPtr != NULL; + tkColPtr = tkColPtr->nextPtr) { + if ((tkColPtr->screen == Tk_Screen(tkwin)) + && (Tk_Colormap(tkwin) == tkColPtr->colormap)) { + tkColPtr->resourceRefCount++; + return &tkColPtr->color; + } + } + } else { + existingColPtr = NULL; } /* @@ -154,22 +236,27 @@ Tk_GetColor(interp, tkwin, name) "\"", (char *) NULL); } } - Tcl_DeleteHashEntry(nameHashPtr); + if (new) { + Tcl_DeleteHashEntry(nameHashPtr); + } return (XColor *) NULL; } /* - * Now create a new TkColor structure and add it to nameTable. + * Now create a new TkColor structure and add it to colorNameTable + * (in TkDisplay). */ tkColPtr->magic = COLOR_MAGIC; tkColPtr->gc = None; tkColPtr->screen = Tk_Screen(tkwin); - tkColPtr->colormap = nameKey.colormap; + tkColPtr->colormap = Tk_Colormap(tkwin); tkColPtr->visual = Tk_Visual(tkwin); - tkColPtr->refCount = 1; - tkColPtr->tablePtr = &nameTable; + tkColPtr->resourceRefCount = 1; + tkColPtr->objRefCount = 0; + tkColPtr->type = TK_COLOR_BY_NAME; tkColPtr->hashPtr = nameHashPtr; + tkColPtr->nextPtr = existingColPtr; tkColPtr->gcList = NULL; Tcl_SetHashValue(nameHashPtr, tkColPtr); @@ -211,9 +298,10 @@ Tk_GetColorByValue(tkwin, colorPtr) int new; TkColor *tkColPtr; Display *display = Tk_Display(tkwin); + TkDisplay *dispPtr = TkGetDisplay(display); - if (!initialized) { - ColorInit(); + if (!dispPtr->colorInit) { + ColorInit(dispPtr); } /* @@ -226,16 +314,17 @@ Tk_GetColorByValue(tkwin, colorPtr) valueKey.blue = colorPtr->blue; valueKey.colormap = Tk_Colormap(tkwin); valueKey.display = display; - valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &valueKey, &new); + valueHashPtr = Tcl_CreateHashEntry(&dispPtr->colorValueTable, + (char *) &valueKey, &new); if (!new) { tkColPtr = (TkColor *) Tcl_GetHashValue(valueHashPtr); - tkColPtr->refCount++; + tkColPtr->resourceRefCount++; return &tkColPtr->color; } /* * The name isn't currently known. Find a pixel value for this - * color and add a new structure to valueTable. + * color and add a new structure to colorValueTable (in TkDisplay). */ tkColPtr = TkpGetColorByValue(tkwin, colorPtr); @@ -244,9 +333,11 @@ Tk_GetColorByValue(tkwin, colorPtr) tkColPtr->screen = Tk_Screen(tkwin); tkColPtr->colormap = valueKey.colormap; tkColPtr->visual = Tk_Visual(tkwin); - tkColPtr->refCount = 1; - tkColPtr->tablePtr = &valueTable; + tkColPtr->resourceRefCount = 1; + tkColPtr->objRefCount = 0; + tkColPtr->type = TK_COLOR_BY_VALUE; tkColPtr->hashPtr = valueHashPtr; + tkColPtr->nextPtr = NULL; tkColPtr->gcList = NULL; Tcl_SetHashValue(valueHashPtr, tkColPtr); return &tkColPtr->color; @@ -279,15 +370,17 @@ Tk_NameOfColor(colorPtr) XColor *colorPtr; /* Color whose name is desired. */ { register TkColor *tkColPtr = (TkColor *) colorPtr; - static char string[20]; - - if ((tkColPtr->magic == COLOR_MAGIC) - && (tkColPtr->tablePtr == &nameTable)) { - return ((NameKey *) tkColPtr->hashPtr->key.words)->name; + + if ((tkColPtr->magic == COLOR_MAGIC) && + (tkColPtr->type == TK_COLOR_BY_NAME)) { + return tkColPtr->hashPtr->key.string; + } else { + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + sprintf(tsdPtr->rgbString, "#%04x%04x%04x", colorPtr->red, + colorPtr->green, colorPtr->blue); + return tsdPtr->rgbString; } - sprintf(string, "#%04x%04x%04x", colorPtr->red, colorPtr->green, - colorPtr->blue); - return string; } /* @@ -314,8 +407,7 @@ Tk_NameOfColor(colorPtr) GC Tk_GCForColor(colorPtr, drawable) XColor *colorPtr; /* Color for which a GC is desired. Must - * have been allocated by Tk_GetColor or - * Tk_GetColorByName. */ + * have been allocated by Tk_GetColor. */ Drawable drawable; /* Drawable in which the color will be * used (must have same screen and depth * as the one for which the color was @@ -366,8 +458,9 @@ Tk_FreeColor(colorPtr) * allocated by Tk_GetColor or * Tk_GetColorByValue. */ { - register TkColor *tkColPtr = (TkColor *) colorPtr; + TkColor *tkColPtr = (TkColor *) colorPtr; Screen *screen = tkColPtr->screen; + TkColor *prevPtr; /* * Do a quick sanity check to make sure this color was really @@ -378,15 +471,45 @@ Tk_FreeColor(colorPtr) panic("Tk_FreeColor called with bogus color"); } - tkColPtr->refCount--; - if (tkColPtr->refCount == 0) { - if (tkColPtr->gc != None) { - XFreeGC(DisplayOfScreen(screen), tkColPtr->gc); - tkColPtr->gc = None; + tkColPtr->resourceRefCount--; + if (tkColPtr->resourceRefCount > 0) { + return; + } + + /* + * This color is no longer being actively used, so free the color + * resources associated with it and remove it from the hash table. + * no longer any objects referencing it. + */ + + if (tkColPtr->gc != None) { + XFreeGC(DisplayOfScreen(screen), tkColPtr->gc); + tkColPtr->gc = None; + } + TkpFreeColor(tkColPtr); + + prevPtr = (TkColor *) Tcl_GetHashValue(tkColPtr->hashPtr); + if (prevPtr == tkColPtr) { + if (tkColPtr->nextPtr == NULL) { + Tcl_DeleteHashEntry(tkColPtr->hashPtr); + } else { + Tcl_SetHashValue(tkColPtr->hashPtr, tkColPtr->nextPtr); + } + } else { + while (prevPtr->nextPtr != tkColPtr) { + prevPtr = prevPtr->nextPtr; } - TkpFreeColor(tkColPtr); - Tcl_DeleteHashEntry(tkColPtr->hashPtr); - tkColPtr->magic = 0; + prevPtr->nextPtr = tkColPtr->nextPtr; + } + + /* + * Free the TkColor structure if there are no objects referencing + * it. However, if there are objects referencing it then keep the + * structure around; it will get freed when the last reference is + * cleared + */ + + if (tkColPtr->objRefCount == 0) { ckfree((char *) tkColPtr); } } @@ -394,131 +517,300 @@ Tk_FreeColor(colorPtr) /* *---------------------------------------------------------------------- * - * ColorInit -- + * Tk_FreeColorFromObj -- * - * Initialize the structure used for color management. + * This procedure is called to release a color allocated by + * Tk_AllocColorFromObj. It does not throw away the Tcl_Obj *; + * it only gets rid of the hash table entry for this color + * and clears the cached value that is normally stored in the object. * * Results: * None. * * Side effects: - * Read the code. + * The reference count associated with the color represented by + * objPtr is decremented, and the color is released to X if there are + * no remaining uses for it. * *---------------------------------------------------------------------- */ -static void -ColorInit() +void +Tk_FreeColorFromObj(tkwin, objPtr) + Tk_Window tkwin; /* The window this color lives in. Needed + * for the screen and colormap values. */ + Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */ { - initialized = 1; - Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int)); - Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int)); + Tk_FreeColor(Tk_GetColorFromObj(tkwin, objPtr)); + FreeColorObjProc(objPtr); } -/* CYGNUS LOCAL: Call a function on every named color. This is used - on Windows to change the colors when the user changes them via the - control panel. */ +/* + *--------------------------------------------------------------------------- + * + * FreeColorObjProc -- + * + * This proc is called to release an object reference to a color. + * Called when the object's internal rep is released or when + * the cached tkColPtr needs to be changed. + * + * Results: + * None. + * + * Side effects: + * The object reference count is decremented. When both it + * and the hash ref count go to zero, the color's resources + * are released. + * + *--------------------------------------------------------------------------- + */ -void -TkMapOverColors(func) - void (*func) _ANSI_ARGS_((TkColor *)); +static void +FreeColorObjProc(objPtr) + Tcl_Obj *objPtr; /* The object we are releasing. */ { - Tcl_HashEntry *nameHashPtr; - Tcl_HashSearch search; - TkColor *tkColPtr; + TkColor *tkColPtr = (TkColor *) objPtr->internalRep.twoPtrValue.ptr1; - nameHashPtr = Tcl_FirstHashEntry(&nameTable, &search); - while (nameHashPtr != NULL) { - tkColPtr = (TkColor *) Tcl_GetHashValue(nameHashPtr); - (*func)(tkColPtr); - nameHashPtr = Tcl_NextHashEntry(&search); + if (tkColPtr != NULL) { + tkColPtr->objRefCount--; + if ((tkColPtr->objRefCount == 0) + && (tkColPtr->resourceRefCount == 0)) { + ckfree((char *) tkColPtr); + } + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL; } } + +/* + *--------------------------------------------------------------------------- + * + * DupColorObjProc -- + * + * When a cached color object is duplicated, this is called to + * update the internal reps. + * + * Results: + * None. + * + * Side effects: + * The color's objRefCount is incremented and the internal rep + * of the copy is set to point to it. + * + *--------------------------------------------------------------------------- + */ -/* CYGNUS LOCAL: For each color, we keep a list of GCs that use that - color as the foreground or background. This is so that we can - change them on Windows when the user changes the system colors. */ - -void -TkRegisterColorGC(colorPtr, display, gc, valueMask) - XColor *colorPtr; - Display *display; - GC gc; - unsigned long valueMask; +static void +DupColorObjProc(srcObjPtr, dupObjPtr) + Tcl_Obj *srcObjPtr; /* The object we are copying from. */ + Tcl_Obj *dupObjPtr; /* The object we are copying to. */ { - TkColor *tkColPtr = (TkColor *) colorPtr; - TkGCList *gcListPtr; + TkColor *tkColPtr = (TkColor *) srcObjPtr->internalRep.twoPtrValue.ptr1; + + dupObjPtr->typePtr = srcObjPtr->typePtr; + dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) tkColPtr; - if (tkColPtr->magic != COLOR_MAGIC) { - return; + if (tkColPtr != NULL) { + tkColPtr->objRefCount++; } - - gcListPtr = (TkGCList *) ckalloc(sizeof(TkGCList)); - gcListPtr->display = display; - gcListPtr->gc = gc; - gcListPtr->mask = valueMask; - gcListPtr->next = tkColPtr->gcList; - tkColPtr->gcList = gcListPtr; - - /* Each GC added to the list counts as a reference to the color, - so that we don't free the color before freeing the GC. */ - - tkColPtr->refCount++; } + +/* + *---------------------------------------------------------------------- + * + * Tk_GetColorFromObj -- + * + * Returns the color referred to by a Tcl object. The color must + * already have been allocated via a call to Tk_AllocColorFromObj + * or Tk_GetColor. + * + * Results: + * Returns the XColor * that matches the tkwin and the string rep + * of objPtr. + * + * Side effects: + * If the object is not already a color, the conversion will free + * any old internal representation. + * + *---------------------------------------------------------------------- + */ -/* This is called when a GC with a registered color is deleted. */ - -void -TkDeregisterColorGC(colorPtr, gc, valueMask) - XColor *colorPtr; - GC gc; - unsigned long valueMask; +XColor * +Tk_GetColorFromObj(tkwin, objPtr) + Tk_Window tkwin; /* The window in which the color will be + * used. */ + Tcl_Obj *objPtr; /* String value contains the name of the + * desired color. */ { - TkColor *tkColPtr = (TkColor *) colorPtr; - TkGCList **gcListPtrPtr, *gcListPtr; + TkColor *tkColPtr; + Tcl_HashEntry *hashPtr; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - if (tkColPtr->magic != COLOR_MAGIC) { - return; + if (objPtr->typePtr != &colorObjType) { + InitColorObj(objPtr); + } + + /* + * First check to see if the internal representation of the object + * is defined and is a color that is valid for the current screen + * and color map. If it is, we are done. + */ + tkColPtr = (TkColor *) objPtr->internalRep.twoPtrValue.ptr1; + if ((tkColPtr != NULL) + && (tkColPtr->resourceRefCount > 0) + && (Tk_Screen(tkwin) == tkColPtr->screen) + && (Tk_Colormap(tkwin) == tkColPtr->colormap)) { + /* + * The object already points to the right TkColor structure. + * Just return it. + */ + + return (XColor *) tkColPtr; } - for (gcListPtrPtr = &tkColPtr->gcList; - *gcListPtrPtr != NULL; - gcListPtrPtr = &(*gcListPtrPtr)->next) { - if ((*gcListPtrPtr)->gc == gc && (*gcListPtrPtr)->mask == valueMask) { - gcListPtr = *gcListPtrPtr; - *gcListPtrPtr = gcListPtr->next; - ckfree((char *) gcListPtr); - Tk_FreeColor((XColor *) tkColPtr); - break; + /* + * If we reach this point, it means that the TkColor structure + * that we have cached in the internal representation is not valid + * for the current screen and colormap. But there is a list of + * other TkColor structures attached to the TkDisplay. Walk this + * list looking for the right TkColor structure. + */ + + hashPtr = Tcl_FindHashEntry(&dispPtr->colorNameTable, + Tcl_GetString(objPtr)); + if (hashPtr == NULL) { + goto error; + } + for (tkColPtr = (TkColor *) Tcl_GetHashValue(hashPtr); + (tkColPtr != NULL); tkColPtr = tkColPtr->nextPtr) { + if ((Tk_Screen(tkwin) == tkColPtr->screen) + && (Tk_Colormap(tkwin) == tkColPtr->colormap)) { + FreeColorObjProc(objPtr); + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) tkColPtr; + tkColPtr->objRefCount++; + return (XColor *) tkColPtr; } } -} -/* This is called when a color is changed by the user on Windows. */ + error: + panic(" Tk_GetColorFromObj called with non-existent color!"); + /* + * The following code isn't reached; it's just there to please compilers. + */ + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * InitColorObj -- + * + * Bookeeping procedure to change an objPtr to a color type. + * + * Results: + * None. + * + * Side effects: + * The old internal rep of the object is freed. The object's + * type is set to color with a NULL TkColor pointer (the pointer + * will be set later by either Tk_AllocColorFromObj or + * Tk_GetColorFromObj). + * + *---------------------------------------------------------------------- + */ -void -TkColorChanged(tkColPtr) - TkColor *tkColPtr; +static void +InitColorObj(objPtr) + Tcl_Obj *objPtr; /* The object to convert. */ { - TkGCList *gcListPtr; - XGCValues gcValues; + Tcl_ObjType *typePtr; - for (gcListPtr = tkColPtr->gcList; - gcListPtr != NULL; - gcListPtr = gcListPtr->next) { - if (gcListPtr->mask == GCForeground) { - gcValues.foreground = tkColPtr->color.pixel; - } else { - gcValues.background = tkColPtr->color.pixel; - } + /* + * Free the old internalRep before setting the new one. + */ - XChangeGC(gcListPtr->display, gcListPtr->gc, gcListPtr->mask, - &gcValues); + Tcl_GetString(objPtr); + typePtr = objPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(objPtr); } + objPtr->typePtr = &colorObjType; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL; +} + +/* + *---------------------------------------------------------------------- + * + * ColorInit -- + * + * Initialize the structure used for color management. + * + * Results: + * None. + * + * Side effects: + * Read the code. + * + *---------------------------------------------------------------------- + */ - if (tkColPtr->gc != None) { - gcValues.foreground = tkColPtr->color.pixel; - XChangeGC(DisplayOfScreen(tkColPtr->screen), tkColPtr->gc, - GCForeground, &gcValues); +static void +ColorInit(dispPtr) + TkDisplay *dispPtr; +{ + if (!dispPtr->colorInit) { + dispPtr->colorInit = 1; + Tcl_InitHashTable(&dispPtr->colorNameTable, TCL_STRING_KEYS); + Tcl_InitHashTable(&dispPtr->colorValueTable, + sizeof(ValueKey)/sizeof(int)); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkDebugColor -- + * + * This procedure returns debugging information about a color. + * + * Results: + * The return value is a list with one sublist for each TkColor + * corresponding to "name". Each sublist has two elements that + * contain the resourceRefCount and objRefCount fields from the + * TkColor structure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_Obj * +TkDebugColor(tkwin, name) + Tk_Window tkwin; /* The window in which the color will be + * used (not currently used). */ + char *name; /* Name of the desired color. */ +{ + TkColor *tkColPtr; + Tcl_HashEntry *hashPtr; + Tcl_Obj *resultPtr, *objPtr; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + + resultPtr = Tcl_NewObj(); + hashPtr = Tcl_FindHashEntry(&dispPtr->colorNameTable, name); + if (hashPtr != NULL) { + tkColPtr = (TkColor *) Tcl_GetHashValue(hashPtr); + if (tkColPtr == NULL) { + panic("TkDebugColor found empty hash table entry"); + } + for ( ; (tkColPtr != NULL); tkColPtr = tkColPtr->nextPtr) { + objPtr = Tcl_NewObj(); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewIntObj(tkColPtr->resourceRefCount)); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewIntObj(tkColPtr->objRefCount)); + Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); + } } + return resultPtr; } + diff --git a/tk/generic/tkColor.h b/tk/generic/tkColor.h index 8a72d7eb9e3..2f38ac4db65 100644 --- a/tk/generic/tkColor.h +++ b/tk/generic/tkColor.h @@ -4,7 +4,7 @@ * Declarations of data types and functions used by the * Tk color module. * - * Copyright (c) 1996 by Sun Microsystems, Inc. + * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -23,14 +23,31 @@ #endif /* CYGNUS LOCAL. */ -typedef struct TkGCList TkGCList; + +/* A linked list of GC structures. */ + +typedef struct TkGCList { + /* Next item on list. */ + struct TkGCList *next; + /* The display for the GC. */ + Display *display; + /* The GC. */ + GC gc; + /* GCForeground or GCBackground. */ + unsigned long mask; +} TkGCList; + +/* END CYGNUS LOCAL */ /* * One of the following data structures is used to keep track of - * each color that the color module has allocated from the X display - * server. + * each color that is being used by the application; typically there + * is a colormap entry allocated for each of these colors. */ +#define TK_COLOR_BY_NAME 1 +#define TK_COLOR_BY_VALUE 2 + #define COLOR_MAGIC ((unsigned int) 0x46140277) typedef struct TkColor { @@ -46,11 +63,29 @@ typedef struct TkColor { Colormap colormap; /* Colormap from which this entry was * allocated. */ Visual *visual; /* Visual associated with colormap. */ - int refCount; /* Number of uses of this structure. */ - Tcl_HashTable *tablePtr; /* Hash table that indexes this structure - * (needed when deleting structure). */ + int resourceRefCount; /* Number of active uses of this color (each + * active use corresponds to a call to + * Tk_AllocColorFromObj or Tk_GetColor). + * If this count is 0, then this TkColor + * structure is no longer valid and it isn't + * present in a hash table: it is being + * kept around only because there are objects + * referring to it. The structure is freed + * when resourceRefCount and objRefCount + * are both 0. */ + int objRefCount; /* The number of Tcl objects that reference + * this structure. */ + int type; /* TK_COLOR_BY_NAME or TK_COLOR_BY_VALUE */ Tcl_HashEntry *hashPtr; /* Pointer to hash table entry for this * structure. (for use in deleting entry). */ + struct TkColor *nextPtr; /* Points to the next TkColor structure with + * the same color name. Colors with the + * same name but different screens or + * colormaps are chained together off a + * single entry in nameTable. For colors in + * valueTable (those allocated by + * Tk_GetColorByValue) this field is always + * NULL. */ /* CYGNUS LOCAL */ TkGCList *gcList; /* List of GCs which use this color. */ } TkColor; @@ -75,3 +110,4 @@ EXTERN void TkColorChanged _ANSI_ARGS_((TkColor *)); # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TKCOLOR */ + diff --git a/tk/generic/tkConfig.c b/tk/generic/tkConfig.c index 4efac5e9089..f12893607c7 100644 --- a/tk/generic/tkConfig.c +++ b/tk/generic/tkConfig.c @@ -1,10 +1,10 @@ /* * tkConfig.c -- * - * This file contains the Tk_ConfigureWidget procedure. + * This file contains procedures that manage configuration options + * for widgets and other things. * - * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1997-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -12,568 +12,1625 @@ * RCS: @(#) $Id$ */ -#include "tkPort.h" +/* + * Temporary flag for working on new config package. + */ + +#if 0 + +/* + * used only for removing the old config code + */ + +#define __NO_OLD_CONFIG +#endif + #include "tk.h" +#include "tkInt.h" +#include "tkPort.h" +#include "tkFont.h" /* - * Values for "flags" field of Tk_ConfigSpec structures. Be sure - * to coordinate these values with those defined in tk.h - * (TK_CONFIG_COLOR_ONLY, etc.). There must not be overlap! + * The following definition is an AssocData key used to keep track of + * all of the option tables that have been created for an interpreter. + */ + +#define OPTION_HASH_KEY "TkOptionTable" + +/* + * The following two structures are used along with Tk_OptionSpec + * structures to manage configuration options. Tk_OptionSpec is + * static templates that are compiled into the code of a widget + * or other object manager. However, to look up options efficiently + * we need to supplement the static information with additional + * dynamic information, and this dynamic information may be different + * for each application. Thus we create structures of the following + * two types to hold all of the dynamic information; this is done + * by Tk_CreateOptionTable. + * + * One of the following structures corresponds to each Tk_OptionSpec. + * These structures exist as arrays inside TkOptionTable structures. + */ + +typedef struct TkOption { + CONST Tk_OptionSpec *specPtr; /* The original spec from the template + * passed to Tk_CreateOptionTable.*/ + Tk_Uid dbNameUID; /* The Uid form of the option database + * name. */ + Tk_Uid dbClassUID; /* The Uid form of the option database + * class name. */ + Tcl_Obj *defaultPtr; /* Default value for this option. */ + union { + Tcl_Obj *monoColorPtr; /* For color and border options, this + * is an alternate default value to + * use on monochrome displays. */ + struct TkOption *synonymPtr; /* For synonym options, this points to + * the master entry. */ + } extra; + int flags; /* Miscellaneous flag values; see + * below for definitions. */ +} Option; + +/* + * Flag bits defined for Option structures: * - * INIT - Non-zero means (char *) things have been - * converted to Tk_Uid's. + * OPTION_NEEDS_FREEING - 1 means that FreeResources must be + * invoke to free resources associated with + * the option when it is no longer needed. */ -#define INIT 0x20 +#define OPTION_NEEDS_FREEING 1 + +/* + * One of the following exists for each Tk_OptionSpec array that has + * been passed to Tk_CreateOptionTable. + */ + +typedef struct OptionTable { + int refCount; /* Counts the number of uses of this + * table (the number of times + * Tk_CreateOptionTable has returned + * it). This can be greater than 1 if + * it is shared along several option + * table chains, or if the same table + * is used for multiple purposes. */ + Tcl_HashEntry *hashEntryPtr; /* Hash table entry that refers to this + * table; used to delete the entry. */ + struct OptionTable *nextPtr; /* If templatePtr was part of a chain + * of templates, this points to the + * table corresponding to the next + * template in the chain. */ + int numOptions; /* The number of items in the options + * array below. */ + Option options[1]; /* Information about the individual + * options in the table. This must be + * the last field in the structure: + * the actual size of the array will + * be numOptions, not 1. */ +} OptionTable; /* * Forward declarations for procedures defined later in this file: */ -static int DoConfig _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specPtr, - Tk_Uid value, int valueIsUid, char *widgRec)); -static Tk_ConfigSpec * FindConfigSpec _ANSI_ARGS_((Tcl_Interp *interp, - Tk_ConfigSpec *specs, char *argvName, - int needFlags, int hateFlags)); -static char * FormatConfigInfo _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specPtr, - char *widgRec)); -static char * FormatConfigValue _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_ConfigSpec *specPtr, - char *widgRec, char *buffer, - Tcl_FreeProc **freeProcPtr)); +static int DoObjConfig _ANSI_ARGS_((Tcl_Interp *interp, + char *recordPtr, Option *optionPtr, + Tcl_Obj *valuePtr, Tk_Window tkwin, + Tk_SavedOption *savePtr)); +static void DestroyOptionHashTable _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp)); +static void FreeResources _ANSI_ARGS_((Option *optionPtr, + Tcl_Obj *objPtr, char *internalPtr, + Tk_Window tkwin)); +static Tcl_Obj * GetConfigList _ANSI_ARGS_((char *recordPtr, + Option *optionPtr, Tk_Window tkwin)); +static Tcl_Obj * GetObjectForOption _ANSI_ARGS_((char *recordPtr, + Option *optionPtr, Tk_Window tkwin)); +static Option * GetOptionFromObj _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr, OptionTable *tablePtr)); +static int ObjectIsEmpty _ANSI_ARGS_((Tcl_Obj *objPtr)); +static int SetOptionFromAny _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr)); + +/* + * The structure below defines an object type that is used to cache the + * result of looking up an option name. If an object has this type, then + * its internalPtr1 field points to the OptionTable in which it was looked up, + * and the internalPtr2 field points to the entry that matched. + */ + +Tcl_ObjType optionType = { + "option", /* name */ + (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */ + (Tcl_DupInternalRepProc *) NULL, /* dupIntRepProc */ + (Tcl_UpdateStringProc *) NULL, /* updateStringProc */ + SetOptionFromAny /* setFromAnyProc */ +}; /* *-------------------------------------------------------------- * - * Tk_ConfigureWidget -- + * Tk_CreateOptionTable -- * - * Process command-line options and database options to - * fill in fields of a widget record with resources and - * other parameters. + * Given a template for configuration options, this procedure + * creates a table that may be used to look up options efficiently. * * Results: - * A standard Tcl return value. In case of an error, - * interp->result will hold an error message. + * Returns a token to a structure that can be passed to procedures + * such as Tk_InitOptions, Tk_SetOptions, and Tk_FreeConfigOptions. * * Side effects: - * The fields of widgRec get filled in with information - * from argc/argv and the option database. Old information - * in widgRec's fields gets recycled. + * Storage is allocated. * *-------------------------------------------------------------- */ -int -Tk_ConfigureWidget(interp, tkwin, specs, argc, argv, widgRec, flags) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Window tkwin; /* Window containing widget (needed to - * set up X resources). */ - Tk_ConfigSpec *specs; /* Describes legal options. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Command-line options. */ - char *widgRec; /* Record whose fields are to be - * modified. Values must be properly - * initialized. */ - int flags; /* Used to specify additional flags - * that must be present in config specs - * for them to be considered. Also, - * may have TK_CONFIG_ARGV_ONLY set. */ +Tk_OptionTable +Tk_CreateOptionTable(interp, templatePtr) + Tcl_Interp *interp; /* Interpreter associated with the + * application in which this table + * will be used. */ + CONST Tk_OptionSpec *templatePtr; /* Static information about the + * configuration options. */ { - register Tk_ConfigSpec *specPtr; - Tk_Uid value; /* Value of option from database. */ - int needFlags; /* Specs must contain this set of flags - * or else they are not considered. */ - int hateFlags; /* If a spec contains any bits here, it's - * not considered. */ - - needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); - if (Tk_Depth(tkwin) <= 1) { - hateFlags = TK_CONFIG_COLOR_ONLY; - } else { - hateFlags = TK_CONFIG_MONO_ONLY; + Tcl_HashTable *hashTablePtr; + Tcl_HashEntry *hashEntryPtr; + int newEntry; + OptionTable *tablePtr; + CONST Tk_OptionSpec *specPtr, *specPtr2; + Option *optionPtr; + int numOptions, i; + + /* + * We use an AssocData value in the interpreter to keep a hash + * table of all the option tables we've created for this application. + * This is used for two purposes. First, it allows us to share the + * tables (e.g. in several chains) and second, we use the deletion + * callback for the AssocData to delete all the option tables when + * the interpreter is deleted. The code below finds the hash table + * or creates a new one if it doesn't already exist. + */ + + hashTablePtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, OPTION_HASH_KEY, + NULL); + if (hashTablePtr == NULL) { + hashTablePtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); + Tcl_InitHashTable(hashTablePtr, TCL_ONE_WORD_KEYS); + Tcl_SetAssocData(interp, OPTION_HASH_KEY, DestroyOptionHashTable, + (ClientData) hashTablePtr); } /* - * Pass one: scan through all the option specs, replacing strings - * with Tk_Uids (if this hasn't been done already) and clearing - * the TK_CONFIG_OPTION_SPECIFIED flags. + * See if a table has already been created for this template. If + * so, just reuse the existing table. */ - for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { - if (!(specPtr->specFlags & INIT) && (specPtr->argvName != NULL)) { + hashEntryPtr = Tcl_CreateHashEntry(hashTablePtr, (char *) templatePtr, + &newEntry); + if (!newEntry) { + tablePtr = (OptionTable *) Tcl_GetHashValue(hashEntryPtr); + tablePtr->refCount++; + return (Tk_OptionTable) tablePtr; + } + + /* + * Count the number of options in the template, then create the + * table structure. + */ + + numOptions = 0; + for (specPtr = templatePtr; specPtr->type != TK_OPTION_END; specPtr++) { + numOptions++; + } + tablePtr = (OptionTable *) (ckalloc(sizeof(OptionTable) + + ((numOptions - 1) * sizeof(Option)))); + tablePtr->refCount = 1; + tablePtr->hashEntryPtr = hashEntryPtr; + tablePtr->nextPtr = NULL; + tablePtr->numOptions = numOptions; + + /* + * Initialize all of the Option structures in the table. + */ + + for (specPtr = templatePtr, optionPtr = tablePtr->options; + specPtr->type != TK_OPTION_END; specPtr++, optionPtr++) { + optionPtr->specPtr = specPtr; + optionPtr->dbNameUID = NULL; + optionPtr->dbClassUID = NULL; + optionPtr->defaultPtr = NULL; + optionPtr->extra.monoColorPtr = NULL; + optionPtr->flags = 0; + + if (specPtr->type == TK_OPTION_SYNONYM) { + /* + * This is a synonym option; find the master option that it + * refers to and create a pointer from the synonym to the + * master. + */ + + for (specPtr2 = templatePtr, i = 0; ; specPtr2++, i++) { + if (specPtr2->type == TK_OPTION_END) { + panic("Tk_CreateOptionTable couldn't find synonym"); + } + if (strcmp(specPtr2->optionName, + (char *) specPtr->clientData) == 0) { + optionPtr->extra.synonymPtr = tablePtr->options + i; + break; + } + } + } else { if (specPtr->dbName != NULL) { - specPtr->dbName = Tk_GetUid(specPtr->dbName); + optionPtr->dbNameUID = Tk_GetUid(specPtr->dbName); } if (specPtr->dbClass != NULL) { - specPtr->dbClass = Tk_GetUid(specPtr->dbClass); + optionPtr->dbClassUID = + Tk_GetUid(specPtr->dbClass); } if (specPtr->defValue != NULL) { - specPtr->defValue = Tk_GetUid(specPtr->defValue); + optionPtr->defaultPtr = + Tcl_NewStringObj(specPtr->defValue, -1); + Tcl_IncrRefCount(optionPtr->defaultPtr); + } + if (((specPtr->type == TK_OPTION_COLOR) + || (specPtr->type == TK_OPTION_BORDER)) + && (specPtr->clientData != NULL)) { + optionPtr->extra.monoColorPtr = + Tcl_NewStringObj((char *) specPtr->clientData, -1); + Tcl_IncrRefCount(optionPtr->extra.monoColorPtr); } } - specPtr->specFlags = (specPtr->specFlags & ~TK_CONFIG_OPTION_SPECIFIED) - | INIT; + if (((specPtr->type == TK_OPTION_STRING) + && (specPtr->internalOffset >= 0)) + || (specPtr->type == TK_OPTION_COLOR) + || (specPtr->type == TK_OPTION_FONT) + || (specPtr->type == TK_OPTION_BITMAP) + || (specPtr->type == TK_OPTION_BORDER) + || (specPtr->type == TK_OPTION_CURSOR)) { + optionPtr->flags |= OPTION_NEEDS_FREEING; + } } + tablePtr->hashEntryPtr = hashEntryPtr; + Tcl_SetHashValue(hashEntryPtr, tablePtr); /* - * Pass two: scan through all of the arguments, processing those - * that match entries in the specs. + * Finally, check to see if this template chains to another template + * with additional options. If so, call ourselves recursively to + * create the next table(s). */ - for ( ; argc > 0; argc -= 2, argv += 2) { - specPtr = FindConfigSpec(interp, specs, *argv, needFlags, hateFlags); - if (specPtr == NULL) { - return TCL_ERROR; + if (specPtr->clientData != NULL) { + tablePtr->nextPtr = (OptionTable *) Tk_CreateOptionTable(interp, + (Tk_OptionSpec *) specPtr->clientData); + } + + return (Tk_OptionTable) tablePtr; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_DeleteOptionTable -- + * + * Called to release resources used by an option table when + * the table is no longer needed. + * + * Results: + * None. + * + * Side effects: + * The option table and associated resources (such as additional + * option tables chained off it) are destroyed. + * + *---------------------------------------------------------------------- + */ + +void +Tk_DeleteOptionTable(optionTable) + Tk_OptionTable optionTable; /* The option table to delete. */ +{ + OptionTable *tablePtr = (OptionTable *) optionTable; + Option *optionPtr; + int count; + + tablePtr->refCount--; + if (tablePtr->refCount > 0) { + return; + } + + if (tablePtr->nextPtr != NULL) { + Tk_DeleteOptionTable((Tk_OptionTable) tablePtr->nextPtr); + } + + for (count = tablePtr->numOptions - 1, optionPtr = tablePtr->options; + count > 0; count--, optionPtr++) { + if (optionPtr->defaultPtr != NULL) { + Tcl_DecrRefCount(optionPtr->defaultPtr); } + if (((optionPtr->specPtr->type == TK_OPTION_COLOR) + || (optionPtr->specPtr->type == TK_OPTION_BORDER)) + && (optionPtr->extra.monoColorPtr != NULL)) { + Tcl_DecrRefCount(optionPtr->extra.monoColorPtr); + } + } + Tcl_DeleteHashEntry(tablePtr->hashEntryPtr); + ckfree((char *) tablePtr); +} + +/* + *---------------------------------------------------------------------- + * + * DestroyOptionHashTable -- + * + * This procedure is the deletion callback associated with the + * AssocData entry created by Tk_CreateOptionTable. It is + * invoked when an interpreter is deleted, and deletes all of + * the option tables associated with that interpreter. + * + * Results: + * None. + * + * Side effects: + * The option hash table is destroyed along with all of the + * OptionTable structures that it refers to. + * + *---------------------------------------------------------------------- + */ + +static void +DestroyOptionHashTable(clientData, interp) + ClientData clientData; /* The hash table we are destroying */ + Tcl_Interp *interp; /* The interpreter we are destroying */ +{ + Tcl_HashTable *hashTablePtr = (Tcl_HashTable *) clientData; + Tcl_HashSearch search; + Tcl_HashEntry *hashEntryPtr; + OptionTable *tablePtr; + + for (hashEntryPtr = Tcl_FirstHashEntry(hashTablePtr, &search); + hashEntryPtr != NULL; + hashEntryPtr = Tcl_NextHashEntry(&search)) { + tablePtr = (OptionTable *) Tcl_GetHashValue(hashEntryPtr); /* - * Process the entry. + * The following statements do two tricky things: + * 1. They ensure that the option table is deleted, even if + * there are outstanding references to it. + * 2. They ensure that Tk_DeleteOptionTable doesn't delete + * other tables chained from this one; we'll do it when + * we come across the hash table entry for the chained + * table (in fact, the chained table may already have + * been deleted). */ - if (argc < 2) { - Tcl_AppendResult(interp, "value for \"", *argv, - "\" missing", (char *) NULL); - return TCL_ERROR; - } - if (DoConfig(interp, tkwin, specPtr, argv[1], 0, widgRec) != TCL_OK) { - char msg[100]; + tablePtr->refCount = 1; + tablePtr->nextPtr = NULL; + Tk_DeleteOptionTable((Tk_OptionTable) tablePtr); + } + Tcl_DeleteHashTable(hashTablePtr); + ckfree((char *) hashTablePtr); +} + +/* + *-------------------------------------------------------------- + * + * Tk_InitOptions -- + * + * This procedure is invoked when an object such as a widget + * is created. It supplies an initial value for each configuration + * option (the value may come from the option database, a system + * default, or the default in the option table). + * + * Results: + * The return value is TCL_OK if the procedure completed + * successfully, and TCL_ERROR if one of the initial values was + * bogus. If an error occurs and interp isn't NULL, then an + * error message will be left in its result. + * + * Side effects: + * Fields of recordPtr are filled in with initial values. + * + *-------------------------------------------------------------- + */ - sprintf(msg, "\n (processing \"%.40s\" option)", - specPtr->argvName); - Tcl_AddErrorInfo(interp, msg); +int +Tk_InitOptions(interp, recordPtr, optionTable, tkwin) + Tcl_Interp *interp; /* Interpreter for error reporting. NULL + * means don't leave an error message. */ + char *recordPtr; /* Pointer to the record to configure. + * Note: the caller should have properly + * initialized the record with NULL + * pointers for each option value. */ + Tk_OptionTable optionTable; /* The token which matches the config + * specs for the widget in question. */ + Tk_Window tkwin; /* Certain options types (such as + * TK_OPTION_COLOR) need fields out + * of the window they are used in to + * be able to calculate their values. + * Not needed unless one of these + * options is in the configSpecs record. */ +{ + OptionTable *tablePtr = (OptionTable *) optionTable; + Option *optionPtr; + int count; + char *value; + Tcl_Obj *valuePtr; + enum { + OPTION_DATABASE, SYSTEM_DEFAULT, TABLE_DEFAULT + } source; + + /* + * If this table chains to other tables, handle their initialization + * first. That way, if both tables refer to the same field of the + * record, the value in the first table will win. + */ + + if (tablePtr->nextPtr != NULL) { + if (Tk_InitOptions(interp, recordPtr, + (Tk_OptionTable) tablePtr->nextPtr, tkwin) != TCL_OK) { return TCL_ERROR; } - specPtr->specFlags |= TK_CONFIG_OPTION_SPECIFIED; } /* - * Pass three: scan through all of the specs again; if no - * command-line argument matched a spec, then check for info - * in the option database. If there was nothing in the - * database, then use the default. + * Iterate over all of the options in the table, initializing each in + * turn. */ - if (!(flags & TK_CONFIG_ARGV_ONLY)) { - for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { - if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED) - || (specPtr->argvName == NULL) - || (specPtr->type == TK_CONFIG_SYNONYM)) { - continue; + for (optionPtr = tablePtr->options, count = tablePtr->numOptions; + count > 0; optionPtr++, count--) { + + /* + * If we specify TK_OPTION_DONT_SET_DEFAULT, then the user has + * processed and set a default for this already. + */ + if ((optionPtr->specPtr->type == TK_OPTION_SYNONYM) || + (optionPtr->specPtr->flags & TK_OPTION_DONT_SET_DEFAULT)) { + continue; + } + source = TABLE_DEFAULT; + + /* + * We look in three places for the initial value, using the first + * non-NULL value that we find. First, check the option database. + */ + + valuePtr = NULL; + if (optionPtr->dbNameUID != NULL) { + value = Tk_GetOption(tkwin, optionPtr->dbNameUID, + optionPtr->dbClassUID); + if (value != NULL) { + valuePtr = Tcl_NewStringObj(value, -1); + source = OPTION_DATABASE; } - if (((specPtr->specFlags & needFlags) != needFlags) - || (specPtr->specFlags & hateFlags)) { - continue; + } + + /* + * Second, check for a system-specific default value. + */ + if ((valuePtr == NULL) + && (optionPtr->dbNameUID != NULL)) { + valuePtr = TkpGetSystemDefault(tkwin, optionPtr->dbNameUID, + optionPtr->dbClassUID); + if (valuePtr != NULL) { + source = SYSTEM_DEFAULT; } - value = NULL; - if (specPtr->dbName != NULL) { - value = Tk_GetOption(tkwin, specPtr->dbName, specPtr->dbClass); + } + + /* + * Third and last, use the default value supplied by the option + * table. In the case of color objects, we pick one of two + * values depending on whether the screen is mono or color. + */ + + if (valuePtr == NULL) { + if ((tkwin != NULL) + && ((optionPtr->specPtr->type == TK_OPTION_COLOR) + || (optionPtr->specPtr->type == TK_OPTION_BORDER)) + && (Tk_Depth(tkwin) <= 1) + && (optionPtr->extra.monoColorPtr != NULL)) { + valuePtr = optionPtr->extra.monoColorPtr; + } else { + valuePtr = optionPtr->defaultPtr; } - if (value != NULL) { - if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) != - TCL_OK) { - char msg[200]; + } + + if (valuePtr == NULL) { + continue; + } + + if (DoObjConfig(interp, recordPtr, optionPtr, valuePtr, tkwin, + (Tk_SavedOption *) NULL) != TCL_OK) { + if (interp != NULL) { + char msg[200]; - sprintf(msg, "\n (%s \"%.50s\" in widget \"%.50s\")", - "database entry for", - specPtr->dbName, Tk_PathName(tkwin)); - Tcl_AddErrorInfo(interp, msg); - return TCL_ERROR; + switch (source) { + case OPTION_DATABASE: + sprintf(msg, "\n (database entry for \"%.50s\")", + optionPtr->specPtr->optionName); + break; + case SYSTEM_DEFAULT: + sprintf(msg, "\n (system default for \"%.50s\")", + optionPtr->specPtr->optionName); + break; + case TABLE_DEFAULT: + sprintf(msg, "\n (default value for \"%.50s\")", + optionPtr->specPtr->optionName); } - } else { - value = specPtr->defValue; - if ((value != NULL) && !(specPtr->specFlags - & TK_CONFIG_DONT_SET_DEFAULT)) { - if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) != - TCL_OK) { - char msg[200]; - - sprintf(msg, - "\n (%s \"%.50s\" in widget \"%.50s\")", - "default value for", - specPtr->dbName, Tk_PathName(tkwin)); - Tcl_AddErrorInfo(interp, msg); - return TCL_ERROR; - } + if (tkwin != NULL) { + sprintf(msg + strlen(msg) - 1, " in widget \"%.50s\")", + Tk_PathName(tkwin)); } + Tcl_AddErrorInfo(interp, msg); } + return TCL_ERROR; } } - return TCL_OK; } /* *-------------------------------------------------------------- * - * FindConfigSpec -- + * DoObjConfig -- * - * Search through a table of configuration specs, looking for - * one that matches a given argvName. + * This procedure applies a new value for a configuration option + * to the record being configured. * * Results: - * The return value is a pointer to the matching entry, or NULL - * if nothing matched. In that case an error message is left - * in interp->result. + * The return value is TCL_OK if the procedure completed + * successfully. If an error occurred then TCL_ERROR is + * returned and an error message is left in interp's result, if + * interp isn't NULL. In addition, if oldValuePtrPtr isn't + * NULL then it *oldValuePtrPtr is filled in with a pointer + * to the option's old value. * * Side effects: - * None. + * RecordPtr gets modified to hold the new value in the form of + * a Tcl_Obj, an internal representation, or both. The old + * value is freed if oldValuePtrPtr is NULL. * *-------------------------------------------------------------- */ -static Tk_ConfigSpec * -FindConfigSpec(interp, specs, argvName, needFlags, hateFlags) - Tcl_Interp *interp; /* Used for reporting errors. */ - Tk_ConfigSpec *specs; /* Pointer to table of configuration - * specifications for a widget. */ - char *argvName; /* Name (suitable for use in a "config" - * command) identifying particular option. */ - int needFlags; /* Flags that must be present in matching - * entry. */ - int hateFlags; /* Flags that must NOT be present in - * matching entry. */ +static int +DoObjConfig(interp, recordPtr, optionPtr, valuePtr, tkwin, savedOptionPtr) + Tcl_Interp *interp; /* Interpreter for error reporting. If + * NULL, then no message is left if an error + * occurs. */ + char *recordPtr; /* The record to modify to hold the new + * option value. */ + Option *optionPtr; /* Pointer to information about the + * option. */ + Tcl_Obj *valuePtr; /* New value for option. */ + Tk_Window tkwin; /* Window in which option will be used (needed + * to allocate resources for some options). + * May be NULL if the option doesn't + * require window-related resources. */ + Tk_SavedOption *savedOptionPtr; + /* If NULL, the old value for the option will + * be freed. If non-NULL, the old value will + * be stored here, and it becomes the property + * of the caller (the caller must eventually + * free the old value). */ { - register Tk_ConfigSpec *specPtr; - register char c; /* First character of current argument. */ - Tk_ConfigSpec *matchPtr; /* Matching spec, or NULL. */ - size_t length; - - c = argvName[1]; - length = strlen(argvName); - matchPtr = NULL; - for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { - if (specPtr->argvName == NULL) { - continue; + Tcl_Obj **slotPtrPtr, *oldPtr; + char *internalPtr; /* Points to location in record where + * internal representation of value should + * be stored, or NULL. */ + char *oldInternalPtr; /* Points to location in which to save old + * internal representation of value. */ + Tk_SavedOption internal; /* Used to save the old internal representation + * of the value if savedOptionPtr is NULL. */ + CONST Tk_OptionSpec *specPtr; + int nullOK; + + /* + * Save the old object form for the value, if there is one. + */ + + specPtr = optionPtr->specPtr; + if (specPtr->objOffset >= 0) { + slotPtrPtr = (Tcl_Obj **) (recordPtr + specPtr->objOffset); + oldPtr = *slotPtrPtr; + } else { + slotPtrPtr = NULL; + oldPtr = NULL; + } + + /* + * Apply the new value in a type-specific way. Also remember the + * old object and internal forms, if they exist. + */ + + if (specPtr->internalOffset >= 0) { + internalPtr = recordPtr + specPtr->internalOffset; + } else { + internalPtr = NULL; + } + if (savedOptionPtr != NULL) { + savedOptionPtr->optionPtr = optionPtr; + savedOptionPtr->valuePtr = oldPtr; + oldInternalPtr = (char *) &savedOptionPtr->internalForm; + } else { + oldInternalPtr = (char *) &internal.internalForm; + } + nullOK = (optionPtr->specPtr->flags & TK_OPTION_NULL_OK); + switch (optionPtr->specPtr->type) { + case TK_OPTION_BOOLEAN: { + int new; + + if (Tcl_GetBooleanFromObj(interp, valuePtr, &new) + != TCL_OK) { + return TCL_ERROR; + } + if (internalPtr != NULL) { + *((int *) oldInternalPtr) = *((int *) internalPtr); + *((int *) internalPtr) = new; + } + break; } - if ((specPtr->argvName[1] != c) - || (strncmp(specPtr->argvName, argvName, length) != 0)) { - continue; + case TK_OPTION_INT: { + int new; + + if (Tcl_GetIntFromObj(interp, valuePtr, &new) != TCL_OK) { + return TCL_ERROR; + } + if (internalPtr != NULL) { + *((int *) oldInternalPtr) = *((int *) internalPtr); + *((int *) internalPtr) = new; + } + break; } - if (((specPtr->specFlags & needFlags) != needFlags) - || (specPtr->specFlags & hateFlags)) { - continue; + case TK_OPTION_DOUBLE: { + double new; + + if (Tcl_GetDoubleFromObj(interp, valuePtr, &new) + != TCL_OK) { + return TCL_ERROR; + } + if (internalPtr != NULL) { + *((double *) oldInternalPtr) = *((double *) internalPtr); + *((double *) internalPtr) = new; + } + break; } - if (specPtr->argvName[length] == 0) { - matchPtr = specPtr; - goto gotMatch; + case TK_OPTION_STRING: { + char *new, *value; + int length; + + if (nullOK && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + } + if (internalPtr != NULL) { + if (valuePtr != NULL) { + value = Tcl_GetStringFromObj(valuePtr, &length); + new = ckalloc((unsigned) (length + 1)); + strcpy(new, value); + } else { + new = NULL; + } + *((char **) oldInternalPtr) = *((char **) internalPtr); + *((char **) internalPtr) = new; + } + break; } - if (matchPtr != NULL) { - Tcl_AppendResult(interp, "ambiguous option \"", argvName, - "\"", (char *) NULL); - return (Tk_ConfigSpec *) NULL; + case TK_OPTION_STRING_TABLE: { + int new; + + if (Tcl_GetIndexFromObj(interp, valuePtr, + (char **) optionPtr->specPtr->clientData, + optionPtr->specPtr->optionName+1, 0, &new) != TCL_OK) { + return TCL_ERROR; + } + if (internalPtr != NULL) { + *((int *) oldInternalPtr) = *((int *) internalPtr); + *((int *) internalPtr) = new; + } + break; } - matchPtr = specPtr; - } + case TK_OPTION_COLOR: { + XColor *newPtr; - if (matchPtr == NULL) { - Tcl_AppendResult(interp, "unknown option \"", argvName, - "\"", (char *) NULL); - return (Tk_ConfigSpec *) NULL; + if (nullOK && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + newPtr = NULL; + } else { + newPtr = Tk_AllocColorFromObj(interp, tkwin, valuePtr); + if (newPtr == NULL) { + return TCL_ERROR; + } + } + if (internalPtr != NULL) { + *((XColor **) oldInternalPtr) = *((XColor **) internalPtr); + *((XColor **) internalPtr) = newPtr; + } + break; + } + case TK_OPTION_FONT: { + Tk_Font new; + + if (nullOK && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + new = NULL; + } else { + new = Tk_AllocFontFromObj(interp, tkwin, valuePtr); + if (new == NULL) { + return TCL_ERROR; + } + } + if (internalPtr != NULL) { + *((Tk_Font *) oldInternalPtr) = *((Tk_Font *) internalPtr); + *((Tk_Font *) internalPtr) = new; + } + break; + } + case TK_OPTION_BITMAP: { + Pixmap new; + + if (nullOK && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + new = None; + } else { + new = Tk_AllocBitmapFromObj(interp, tkwin, valuePtr); + if (new == None) { + return TCL_ERROR; + } + } + if (internalPtr != NULL) { + *((Pixmap *) oldInternalPtr) = *((Pixmap *) internalPtr); + *((Pixmap *) internalPtr) = new; + } + break; + } + case TK_OPTION_BORDER: { + Tk_3DBorder new; + + if (nullOK && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + new = NULL; + } else { + new = Tk_Alloc3DBorderFromObj(interp, tkwin, valuePtr); + if (new == NULL) { + return TCL_ERROR; + } + } + if (internalPtr != NULL) { + *((Tk_3DBorder *) oldInternalPtr) = + *((Tk_3DBorder *) internalPtr); + *((Tk_3DBorder *) internalPtr) = new; + } + break; + } + case TK_OPTION_RELIEF: { + int new; + + if (Tk_GetReliefFromObj(interp, valuePtr, &new) != TCL_OK) { + return TCL_ERROR; + } + if (internalPtr != NULL) { + *((int *) oldInternalPtr) = *((int *) internalPtr); + *((int *) internalPtr) = new; + } + break; + } + case TK_OPTION_CURSOR: { + Tk_Cursor new; + + if (nullOK && ObjectIsEmpty(valuePtr)) { + new = None; + valuePtr = NULL; + } else { + new = Tk_AllocCursorFromObj(interp, tkwin, valuePtr); + if (new == None) { + return TCL_ERROR; + } + } + if (internalPtr != NULL) { + *((Tk_Cursor *) oldInternalPtr) = *((Tk_Cursor *) internalPtr); + *((Tk_Cursor *) internalPtr) = new; + } + Tk_DefineCursor(tkwin, new); + break; + } + case TK_OPTION_JUSTIFY: { + Tk_Justify new; + + if (Tk_GetJustifyFromObj(interp, valuePtr, &new) != TCL_OK) { + return TCL_ERROR; + } + if (internalPtr != NULL) { + *((Tk_Justify *) oldInternalPtr) + = *((Tk_Justify *) internalPtr); + *((Tk_Justify *) internalPtr) = new; + } + break; + } + case TK_OPTION_ANCHOR: { + Tk_Anchor new; + + if (Tk_GetAnchorFromObj(interp, valuePtr, &new) != TCL_OK) { + return TCL_ERROR; + } + if (internalPtr != NULL) { + *((Tk_Anchor *) oldInternalPtr) + = *((Tk_Anchor *) internalPtr); + *((Tk_Anchor *) internalPtr) = new; + } + break; + } + case TK_OPTION_PIXELS: { + int new; + + if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, + &new) != TCL_OK) { + return TCL_ERROR; + } + if (internalPtr != NULL) { + *((int *) oldInternalPtr) = *((int *) internalPtr); + *((int *) internalPtr) = new; + } + break; + } + case TK_OPTION_WINDOW: { + Tk_Window new; + + if (nullOK && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + new = None; + } else { + if (TkGetWindowFromObj(interp, tkwin, valuePtr, &new) + != TCL_OK) { + return TCL_ERROR; + } + } + if (internalPtr != NULL) { + *((Tk_Window *) oldInternalPtr) = *((Tk_Window *) internalPtr); + *((Tk_Window *) internalPtr) = new; + } + break; + } + default: { + char buf[40+TCL_INTEGER_SPACE]; + sprintf(buf, "bad config table: unknown type %d", + optionPtr->specPtr->type); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } } /* - * Found a matching entry. If it's a synonym, then find the - * entry that it's a synonym for. + * Release resources associated with the old value, if we're not + * returning it to the caller, then install the new object value into + * the record. */ - gotMatch: - specPtr = matchPtr; - if (specPtr->type == TK_CONFIG_SYNONYM) { - for (specPtr = specs; ; specPtr++) { - if (specPtr->type == TK_CONFIG_END) { - Tcl_AppendResult(interp, - "couldn't find synonym for option \"", - argvName, "\"", (char *) NULL); - return (Tk_ConfigSpec *) NULL; - } - if ((specPtr->dbName == matchPtr->dbName) - && (specPtr->type != TK_CONFIG_SYNONYM) - && ((specPtr->specFlags & needFlags) == needFlags) - && !(specPtr->specFlags & hateFlags)) { - break; - } + if (savedOptionPtr == NULL) { + if (optionPtr->flags & OPTION_NEEDS_FREEING) { + FreeResources(optionPtr, oldPtr, oldInternalPtr, tkwin); + } + if (oldPtr != NULL) { + Tcl_DecrRefCount(oldPtr); + } + } + if (slotPtrPtr != NULL) { + *slotPtrPtr = valuePtr; + if (valuePtr != NULL) { + Tcl_IncrRefCount(valuePtr); } } - return specPtr; + return TCL_OK; } /* - *-------------------------------------------------------------- + *---------------------------------------------------------------------- * - * DoConfig -- + * ObjectIsEmpty -- * - * This procedure applies a single configuration option - * to a widget record. + * This procedure tests whether the string value of an object is + * empty. * * Results: - * A standard Tcl return value. + * The return value is 1 if the string value of objPtr has length + * zero, and 0 otherwise. * * Side effects: - * WidgRec is modified as indicated by specPtr and value. - * The old value is recycled, if that is appropriate for - * the value type. + * None. * - *-------------------------------------------------------------- + *---------------------------------------------------------------------- */ static int -DoConfig(interp, tkwin, specPtr, value, valueIsUid, widgRec) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Window tkwin; /* Window containing widget (needed to - * set up X resources). */ - Tk_ConfigSpec *specPtr; /* Specifier to apply. */ - char *value; /* Value to use to fill in widgRec. */ - int valueIsUid; /* Non-zero means value is a Tk_Uid; - * zero means it's an ordinary string. */ - char *widgRec; /* Record whose fields are to be - * modified. Values must be properly - * initialized. */ +ObjectIsEmpty(objPtr) + Tcl_Obj *objPtr; /* Object to test. May be NULL. */ { - char *ptr; - Tk_Uid uid; - int nullValue; + int length; - nullValue = 0; - if ((*value == 0) && (specPtr->specFlags & TK_CONFIG_NULL_OK)) { - nullValue = 1; + if (objPtr == NULL) { + return 1; + } + if (objPtr->bytes != NULL) { + return (objPtr->length == 0); } + Tcl_GetStringFromObj(objPtr, &length); + return (length == 0); +} + +/* + *---------------------------------------------------------------------- + * + * GetOptionFromObj -- + * + * This procedure searches through a chained option table to find + * the entry for a particular option name. + * + * Results: + * The return value is a pointer to the matching entry, or NULL + * if no matching entry could be found. If NULL is returned and + * interp is not NULL than an error message is left in its result. + * Note: if the matching entry is a synonym then this procedure + * returns a pointer to the synonym entry, *not* the "real" entry + * that the synonym refers to. + * + * Side effects: + * Information about the matching entry is cached in the object + * containing the name, so that future lookups can proceed more + * quickly. + * + *---------------------------------------------------------------------- + */ - do { - ptr = widgRec + specPtr->offset; - switch (specPtr->type) { - case TK_CONFIG_BOOLEAN: - if (Tcl_GetBoolean(interp, value, (int *) ptr) != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_INT: - if (Tcl_GetInt(interp, value, (int *) ptr) != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_DOUBLE: - if (Tcl_GetDouble(interp, value, (double *) ptr) != TCL_OK) { - return TCL_ERROR; - } - break; - case TK_CONFIG_STRING: { - char *old, *new; +static Option * +GetOptionFromObj(interp, objPtr, tablePtr) + Tcl_Interp *interp; /* Used only for error reporting; if NULL + * no message is left after an error. */ + Tcl_Obj *objPtr; /* Object whose string value is to be + * looked up in the option table. */ + OptionTable *tablePtr; /* Table in which to look up objPtr. */ +{ + Option *bestPtr, *optionPtr; + OptionTable *tablePtr2; + char *p1, *p2, *name; + int count; - if (nullValue) { - new = NULL; - } else { - new = (char *) ckalloc((unsigned) (strlen(value) + 1)); - strcpy(new, value); - } - old = *((char **) ptr); - if (old != NULL) { - ckfree(old); + /* + * First, check to see if the object already has the answer cached. + */ + + if (objPtr->typePtr == &optionType) { + if (objPtr->internalRep.twoPtrValue.ptr1 == (VOID *) tablePtr) { + return (Option *) objPtr->internalRep.twoPtrValue.ptr2; + } + } + + /* + * The answer isn't cached. Search through all of the option tables + * in the chain to find the best match. Some tricky aspects: + * + * 1. We have to accept unique abbreviations. + * 2. The same name could appear in different tables in the chain. + * If this happens, we use the entry from the first table. We + * have to be careful to distinguish this case from an ambiguous + * abbreviation. + */ + + bestPtr = NULL; + name = Tcl_GetStringFromObj(objPtr, (int *) NULL); + for (tablePtr2 = tablePtr; tablePtr2 != NULL; + tablePtr2 = tablePtr2->nextPtr) { + for (optionPtr = tablePtr2->options, count = tablePtr2->numOptions; + count > 0; optionPtr++, count--) { + for (p1 = name, p2 = optionPtr->specPtr->optionName; + *p1 == *p2; p1++, p2++) { + if (*p1 == 0) { + /* + * This is an exact match. We're done. + */ + + bestPtr = optionPtr; + goto done; } - *((char **) ptr) = new; - break; } - case TK_CONFIG_UID: - if (nullValue) { - *((Tk_Uid *) ptr) = NULL; - } else { - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - *((Tk_Uid *) ptr) = uid; - } - break; - case TK_CONFIG_COLOR: { - XColor *newPtr, *oldPtr; + if (*p1 == 0) { + /* + * The name is an abbreviation for this option. Keep + * to make sure that the abbreviation only matches one + * option name. If we've already found a match in the + * past, then it is an error unless the full names for + * the two options are identical; in this case, the first + * option overrides the second. + */ - if (nullValue) { - newPtr = NULL; + if (bestPtr == NULL) { + bestPtr = optionPtr; } else { - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - newPtr = Tk_GetColor(interp, tkwin, uid); - if (newPtr == NULL) { - return TCL_ERROR; + if (strcmp(bestPtr->specPtr->optionName, + optionPtr->specPtr->optionName) != 0) { + goto error; } } - oldPtr = *((XColor **) ptr); - if (oldPtr != NULL) { - Tk_FreeColor(oldPtr); - } - *((XColor **) ptr) = newPtr; - break; } - case TK_CONFIG_FONT: { - Tk_Font new; + } + } + if (bestPtr == NULL) { + goto error; + } - if (nullValue) { - new = NULL; - } else { - new = Tk_GetFont(interp, tkwin, value); - if (new == NULL) { - return TCL_ERROR; - } - } - Tk_FreeFont(*((Tk_Font *) ptr)); - *((Tk_Font *) ptr) = new; - break; + done: + if ((objPtr->typePtr != NULL) + && (objPtr->typePtr->freeIntRepProc != NULL)) { + objPtr->typePtr->freeIntRepProc(objPtr); + } + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) tablePtr; + objPtr->internalRep.twoPtrValue.ptr2 = (VOID *) bestPtr; + objPtr->typePtr = &optionType; + return bestPtr; + + error: + if (interp != NULL) { + Tcl_AppendResult(interp, "unknown option \"", name, + "\"", (char *) NULL); + } + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * SetOptionFromAny -- + * + * This procedure is called to convert a Tcl object to option + * internal form. However, this doesn't make sense (need to have a + * table of options in order to do the conversion) so the + * procedure always generates an error. + * + * Results: + * The return value is always TCL_ERROR, and an error message is + * left in interp's result if interp isn't NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +SetOptionFromAny(interp, objPtr) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + register Tcl_Obj *objPtr; /* The object to convert. */ +{ + Tcl_AppendToObj(Tcl_GetObjResult(interp), + "can't convert value to option except via GetOptionFromObj API", + -1); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * Tk_SetOptions -- + * + * Process one or more name-value pairs for configuration options + * and fill in fields of a record with new values. + * + * Results: + * If all goes well then TCL_OK is returned and the old values of + * any modified objects are saved in *savePtr, if it isn't NULL (the + * caller must eventually call Tk_RestoreSavedOptions or + * Tk_FreeSavedOptions to free the contents of *savePtr). In + * addition, if maskPtr isn't NULL then *maskPtr is filled in with + * the OR of the typeMask bits from all modified options. If an + * error occurs then TCL_ERROR is returned and a message + * is left in interp's result unless interp is NULL; nothing is + * saved in *savePtr or *maskPtr in this case. + * + * Side effects: + * The fields of recordPtr get filled in with object pointers + * from objc/objv. Old information in widgRec's fields gets + * recycled. Information may be left at *savePtr. + * + *-------------------------------------------------------------- + */ + +int +Tk_SetOptions(interp, recordPtr, optionTable, objc, objv, tkwin, savePtr, + maskPtr) + Tcl_Interp *interp; /* Interpreter for error reporting. + * If NULL, then no error message is + * returned.*/ + char *recordPtr; /* The record to configure. */ + Tk_OptionTable optionTable; /* Describes valid options. */ + int objc; /* The number of elements in objv. */ + Tcl_Obj *CONST objv[]; /* Contains one or more name-value + * pairs. */ + Tk_Window tkwin; /* Window associated with the thing + * being configured; needed for some + * options (such as colors). */ + Tk_SavedOptions *savePtr; /* If non-NULL, the old values of + * modified options are saved here + * so that they can be restored + * after an error. */ + int *maskPtr; /* It non-NULL, this word is modified + * on a successful return to hold the + * bit-wise OR of the typeMask fields + * of all options that were modified + * by this call. Used by the caller + * to figure out which options + * actually changed. */ +{ + OptionTable *tablePtr = (OptionTable *) optionTable; + Option *optionPtr; + Tk_SavedOptions *lastSavePtr, *newSavePtr; + int mask; + + if (savePtr != NULL) { + savePtr->recordPtr = recordPtr; + savePtr->tkwin = tkwin; + savePtr->numItems = 0; + savePtr->nextPtr = NULL; + } + lastSavePtr = savePtr; + + /* + * Scan through all of the arguments, processing those + * that match entries in the option table. + */ + + mask = 0; + for ( ; objc > 0; objc -= 2, objv += 2) { + optionPtr = GetOptionFromObj(interp, objv[0], tablePtr); + if (optionPtr == NULL) { + goto error; + } + if (optionPtr->specPtr->type == TK_OPTION_SYNONYM) { + optionPtr = optionPtr->extra.synonymPtr; + } + + if (objc < 2) { + if (interp != NULL) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "value for \"", Tcl_GetStringFromObj(*objv, NULL), + "\" missing", (char *) NULL); + goto error; } - case TK_CONFIG_BITMAP: { - Pixmap new, old; + } + if ((savePtr != NULL) + && (lastSavePtr->numItems >= TK_NUM_SAVED_OPTIONS)) { + /* + * We've run out of space for saving old option values. Allocate + * more space. + */ - if (nullValue) { - new = None; - } else { - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - new = Tk_GetBitmap(interp, tkwin, uid); - if (new == None) { - return TCL_ERROR; - } + newSavePtr = (Tk_SavedOptions *) ckalloc(sizeof( + Tk_SavedOptions)); + newSavePtr->recordPtr = recordPtr; + newSavePtr->tkwin = tkwin; + newSavePtr->numItems = 0; + newSavePtr->nextPtr = NULL; + lastSavePtr->nextPtr = newSavePtr; + lastSavePtr = newSavePtr; + } + if (DoObjConfig(interp, recordPtr, optionPtr, objv[1], tkwin, + (savePtr != NULL) ? &lastSavePtr->items[lastSavePtr->numItems] + : (Tk_SavedOption *) NULL) != TCL_OK) { + char msg[100]; + + sprintf(msg, "\n (processing \"%.40s\" option)", + Tcl_GetStringFromObj(*objv, NULL)); + Tcl_AddErrorInfo(interp, msg); + goto error; + } + if (savePtr != NULL) { + lastSavePtr->numItems++; + } + mask |= optionPtr->specPtr->typeMask; + } + if (maskPtr != NULL) { + *maskPtr = mask; + } + return TCL_OK; + + error: + if (savePtr != NULL) { + Tk_RestoreSavedOptions(savePtr); + } + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_RestoreSavedOptions -- + * + * This procedure undoes the effect of a previous call to + * Tk_SetOptions by restoring all of the options to their value + * before the call to Tk_SetOptions. + * + * Results: + * None. + * + * Side effects: + * The configutation record is restored and all the information + * stored in savePtr is freed. + * + *---------------------------------------------------------------------- + */ + +void +Tk_RestoreSavedOptions(savePtr) + Tk_SavedOptions *savePtr; /* Holds saved option information; must + * have been passed to Tk_SetOptions. */ +{ + int i; + Option *optionPtr; + Tcl_Obj *newPtr; /* New object value of option, which we + * replace with old value and free. Taken + * from record. */ + char *internalPtr; /* Points to internal value of option in + * record. */ + CONST Tk_OptionSpec *specPtr; + + /* + * Be sure to restore the options in the opposite order they were + * set. This is important because it's possible that the same + * option name was used twice in a single call to Tk_SetOptions. + */ + + if (savePtr->nextPtr != NULL) { + Tk_RestoreSavedOptions(savePtr->nextPtr); + ckfree((char *) savePtr->nextPtr); + savePtr->nextPtr = NULL; + } + for (i = savePtr->numItems - 1; i >= 0; i--) { + optionPtr = savePtr->items[i].optionPtr; + specPtr = optionPtr->specPtr; + + /* + * First free the new value of the option, which is currently + * in the record. + */ + + if (specPtr->objOffset >= 0) { + newPtr = *((Tcl_Obj **) (savePtr->recordPtr + specPtr->objOffset)); + } else { + newPtr = NULL; + } + if (specPtr->internalOffset >= 0) { + internalPtr = savePtr->recordPtr + specPtr->internalOffset; + } else { + internalPtr = NULL; + } + if (optionPtr->flags & OPTION_NEEDS_FREEING) { + FreeResources(optionPtr, newPtr, internalPtr, savePtr->tkwin); + } + if (newPtr != NULL) { + Tcl_DecrRefCount(newPtr); + } + + /* + * Now restore the old value of the option. + */ + + if (specPtr->objOffset >= 0) { + *((Tcl_Obj **) (savePtr->recordPtr + specPtr->objOffset)) + = savePtr->items[i].valuePtr; + } + if (specPtr->internalOffset >= 0) { + switch (specPtr->type) { + case TK_OPTION_BOOLEAN: { + *((int *) internalPtr) + = *((int *) &savePtr->items[i].internalForm); + break; } - old = *((Pixmap *) ptr); - if (old != None) { - Tk_FreeBitmap(Tk_Display(tkwin), old); + case TK_OPTION_INT: { + *((int *) internalPtr) + = *((int *) &savePtr->items[i].internalForm); + break; } - *((Pixmap *) ptr) = new; - break; - } - case TK_CONFIG_BORDER: { - Tk_3DBorder new, old; - - if (nullValue) { - new = NULL; - } else { - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - new = Tk_Get3DBorder(interp, tkwin, uid); - if (new == NULL) { - return TCL_ERROR; - } + case TK_OPTION_DOUBLE: { + *((double *) internalPtr) + = *((double *) &savePtr->items[i].internalForm); + break; } - old = *((Tk_3DBorder *) ptr); - if (old != NULL) { - Tk_Free3DBorder(old); + case TK_OPTION_STRING: { + *((char **) internalPtr) + = *((char **) &savePtr->items[i].internalForm); + break; } - *((Tk_3DBorder *) ptr) = new; - break; - } - case TK_CONFIG_RELIEF: - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - if (Tk_GetRelief(interp, uid, (int *) ptr) != TCL_OK) { - return TCL_ERROR; + case TK_OPTION_STRING_TABLE: { + *((int *) internalPtr) + = *((int *) &savePtr->items[i].internalForm); + break; } - break; - case TK_CONFIG_CURSOR: - case TK_CONFIG_ACTIVE_CURSOR: { - Tk_Cursor new, old; - - if (nullValue) { - new = None; - } else { - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - new = Tk_GetCursor(interp, tkwin, uid); - if (new == None) { - return TCL_ERROR; - } + case TK_OPTION_COLOR: { + *((XColor **) internalPtr) + = *((XColor **) &savePtr->items[i].internalForm); + break; } - old = *((Tk_Cursor *) ptr); - if (old != None) { - Tk_FreeCursor(Tk_Display(tkwin), old); + case TK_OPTION_FONT: { + *((Tk_Font *) internalPtr) + = *((Tk_Font *) &savePtr->items[i].internalForm); + break; } - *((Tk_Cursor *) ptr) = new; - if (specPtr->type == TK_CONFIG_ACTIVE_CURSOR) { - Tk_DefineCursor(tkwin, new); + case TK_OPTION_BITMAP: { + *((Pixmap *) internalPtr) + = *((Pixmap *) &savePtr->items[i].internalForm); + break; } - break; - } - case TK_CONFIG_JUSTIFY: - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - if (Tk_GetJustify(interp, uid, (Tk_Justify *) ptr) != TCL_OK) { - return TCL_ERROR; + case TK_OPTION_BORDER: { + *((Tk_3DBorder *) internalPtr) + = *((Tk_3DBorder *) &savePtr->items[i].internalForm); + break; } - break; - case TK_CONFIG_ANCHOR: - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - if (Tk_GetAnchor(interp, uid, (Tk_Anchor *) ptr) != TCL_OK) { - return TCL_ERROR; + case TK_OPTION_RELIEF: { + *((int *) internalPtr) + = *((int *) &savePtr->items[i].internalForm); + break; } - break; - case TK_CONFIG_CAP_STYLE: - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - if (Tk_GetCapStyle(interp, uid, (int *) ptr) != TCL_OK) { - return TCL_ERROR; + case TK_OPTION_CURSOR: { + *((Tk_Cursor *) internalPtr) + = *((Tk_Cursor *) &savePtr->items[i].internalForm); + Tk_DefineCursor(savePtr->tkwin, + *((Tk_Cursor *) internalPtr)); + break; } - break; - case TK_CONFIG_JOIN_STYLE: - uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); - if (Tk_GetJoinStyle(interp, uid, (int *) ptr) != TCL_OK) { - return TCL_ERROR; + case TK_OPTION_JUSTIFY: { + *((Tk_Justify *) internalPtr) + = *((Tk_Justify *) &savePtr->items[i].internalForm); + break; } - break; - case TK_CONFIG_PIXELS: - if (Tk_GetPixels(interp, tkwin, value, (int *) ptr) - != TCL_OK) { - return TCL_ERROR; + case TK_OPTION_ANCHOR: { + *((Tk_Anchor *) internalPtr) + = *((Tk_Anchor *) &savePtr->items[i].internalForm); + break; } - break; - case TK_CONFIG_MM: - if (Tk_GetScreenMM(interp, tkwin, value, (double *) ptr) - != TCL_OK) { - return TCL_ERROR; + case TK_OPTION_PIXELS: { + *((int *) internalPtr) + = *((int *) &savePtr->items[i].internalForm); + break; + } + case TK_OPTION_WINDOW: { + *((Tk_Window *) internalPtr) + = *((Tk_Window *) &savePtr->items[i].internalForm); + break; + } + default: { + panic("bad option type in Tk_RestoreSavedOptions"); } - break; - case TK_CONFIG_WINDOW: { - Tk_Window tkwin2; + } + } + } + savePtr->numItems = 0; +} + +/* + *-------------------------------------------------------------- + * + * Tk_FreeSavedOptions -- + * + * Free all of the saved configuration option values from a + * previous call to Tk_SetOptions. + * + * Results: + * None. + * + * Side effects: + * Storage and system resources are freed. + * + *-------------------------------------------------------------- + */ - if (nullValue) { - tkwin2 = NULL; - } else { - tkwin2 = Tk_NameToWindow(interp, value, tkwin); - if (tkwin2 == NULL) { - return TCL_ERROR; - } +void +Tk_FreeSavedOptions(savePtr) + Tk_SavedOptions *savePtr; /* Contains options saved in a previous + * call to Tk_SetOptions. */ +{ + int count; + Tk_SavedOption *savedOptionPtr; + + if (savePtr->nextPtr != NULL) { + Tk_FreeSavedOptions(savePtr->nextPtr); + ckfree((char *) savePtr->nextPtr); + } + for (count = savePtr->numItems, + savedOptionPtr = &savePtr->items[savePtr->numItems-1]; + count > 0; count--, savedOptionPtr--) { + if (savedOptionPtr->optionPtr->flags & OPTION_NEEDS_FREEING) { + FreeResources(savedOptionPtr->optionPtr, savedOptionPtr->valuePtr, + (char *) &savedOptionPtr->internalForm, savePtr->tkwin); + } + if (savedOptionPtr->valuePtr != NULL) { + Tcl_DecrRefCount(savedOptionPtr->valuePtr); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_FreeConfigOptions -- + * + * Free all resources associated with configuration options. + * + * Results: + * None. + * + * Side effects: + * All of the Tcl_Obj's in recordPtr that are controlled by + * configuration options in optionTable are freed. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +void +Tk_FreeConfigOptions(recordPtr, optionTable, tkwin) + char *recordPtr; /* Record whose fields contain current + * values for options. */ + Tk_OptionTable optionTable; /* Describes legal options. */ + Tk_Window tkwin; /* Window associated with recordPtr; needed + * for freeing some options. */ +{ + OptionTable *tablePtr; + Option *optionPtr; + int count; + Tcl_Obj **oldPtrPtr, *oldPtr; + char *oldInternalPtr; + CONST Tk_OptionSpec *specPtr; + + for (tablePtr = (OptionTable *) optionTable; tablePtr != NULL; + tablePtr = tablePtr->nextPtr) { + for (optionPtr = tablePtr->options, count = tablePtr->numOptions; + count > 0; optionPtr++, count--) { + specPtr = optionPtr->specPtr; + if (specPtr->type == TK_OPTION_SYNONYM) { + continue; + } + if (specPtr->objOffset >= 0) { + oldPtrPtr = (Tcl_Obj **) (recordPtr + specPtr->objOffset); + oldPtr = *oldPtrPtr; + *oldPtrPtr = NULL; + } else { + oldPtr = NULL; + } + if (specPtr->internalOffset >= 0) { + oldInternalPtr = recordPtr + specPtr->internalOffset; + } else { + oldInternalPtr = NULL; + } + if (optionPtr->flags & OPTION_NEEDS_FREEING) { + FreeResources(optionPtr, oldPtr, oldInternalPtr, tkwin); + } + if (oldPtr != NULL) { + Tcl_DecrRefCount(oldPtr); + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * FreeResources -- + * + * Free system resources associated with a configuration option, + * such as colors or fonts. + * + * Results: + * None. + * + * Side effects: + * Any system resources associated with objPtr are released. However, + * objPtr itself is not freed. + * + *---------------------------------------------------------------------- + */ + +static void +FreeResources(optionPtr, objPtr, internalPtr, tkwin) + Option *optionPtr; /* Description of the configuration option. */ + Tcl_Obj *objPtr; /* The current value of the option, specified + * as an object. */ + char *internalPtr; /* A pointer to an internal representation for + * the option's value, such as an int or + * (XColor *). Only valid if + * optionPtr->specPtr->internalOffset >= 0. */ + Tk_Window tkwin; /* The window in which this option is used. */ +{ + int internalFormExists; + + /* + * If there exists an internal form for the value, use it to free + * resources (also zero out the internal form). If there is no + * internal form, then use the object form. + */ + + internalFormExists = optionPtr->specPtr->internalOffset >= 0; + switch (optionPtr->specPtr->type) { + case TK_OPTION_STRING: + if (internalFormExists) { + if (*((char **) internalPtr) != NULL) { + ckfree(*((char **) internalPtr)); + *((char **) internalPtr) = NULL; } - *((Tk_Window *) ptr) = tkwin2; - break; } - case TK_CONFIG_CUSTOM: - if ((*specPtr->customPtr->parseProc)( - specPtr->customPtr->clientData, interp, tkwin, - value, widgRec, specPtr->offset) != TCL_OK) { - return TCL_ERROR; + break; + case TK_OPTION_COLOR: + if (internalFormExists) { + if (*((XColor **) internalPtr) != NULL) { + Tk_FreeColor(*((XColor **) internalPtr)); + *((XColor **) internalPtr) = NULL; } - break; - default: { - sprintf(interp->result, "bad config table: unknown type %d", - specPtr->type); - return TCL_ERROR; + } else if (objPtr != NULL) { + Tk_FreeColorFromObj(tkwin, objPtr); } - } - specPtr++; - } while ((specPtr->argvName == NULL) && (specPtr->type != TK_CONFIG_END)); - return TCL_OK; + break; + case TK_OPTION_FONT: + if (internalFormExists) { + Tk_FreeFont(*((Tk_Font *) internalPtr)); + *((Tk_Font *) internalPtr) = NULL; + } else if (objPtr != NULL) { + Tk_FreeFontFromObj(tkwin, objPtr); + } + break; + case TK_OPTION_BITMAP: + if (internalFormExists) { + if (*((Pixmap *) internalPtr) != None) { + Tk_FreeBitmap(Tk_Display(tkwin), *((Pixmap *) internalPtr)); + *((Pixmap *) internalPtr) = None; + } + } else if (objPtr != NULL) { + Tk_FreeBitmapFromObj(tkwin, objPtr); + } + break; + case TK_OPTION_BORDER: + if (internalFormExists) { + if (*((Tk_3DBorder *) internalPtr) != NULL) { + Tk_Free3DBorder(*((Tk_3DBorder *) internalPtr)); + *((Tk_3DBorder *) internalPtr) = NULL; + } + } else if (objPtr != NULL) { + Tk_Free3DBorderFromObj(tkwin, objPtr); + } + break; + case TK_OPTION_CURSOR: + if (internalFormExists) { + if (*((Tk_Cursor *) internalPtr) != None) { + Tk_FreeCursor(Tk_Display(tkwin), + *((Tk_Cursor *) internalPtr)); + *((Tk_Cursor *) internalPtr) = None; + } + } else if (objPtr != NULL) { + Tk_FreeCursorFromObj(tkwin, objPtr); + } + break; + default: + break; + } } /* *-------------------------------------------------------------- * - * Tk_ConfigureInfo -- + * Tk_GetOptionInfo -- * - * Return information about the configuration options - * for a window, and their current values. + * Returns a list object containing complete information about + * either a single option or all the configuration options in a + * table. * * Results: - * Always returns TCL_OK. Interp->result will be modified - * hold a description of either a single configuration option - * available for "widgRec" via "specs", or all the configuration - * options available. In the "all" case, the result will - * available for "widgRec" via "specs". The result will - * be a list, each of whose entries describes one option. - * Each entry will itself be a list containing the option's - * name for use on command lines, database name, database - * class, default value, and current value (empty string - * if none). For options that are synonyms, the list will - * contain only two values: name and synonym name. If the - * "name" argument is non-NULL, then the only information - * returned is that for the named argument (i.e. the corresponding - * entry in the overall list is returned). + * This procedure normally returns a pointer to an object. + * If namePtr isn't NULL, then the result object is a list with + * five elements: the option's name, its database name, database + * class, default value, and current value. If the option is a + * synonym then the list will contain only two values: the option + * name and the name of the option it refers to. If namePtr is + * NULL, then information is returned for every option in the + * option table: the result will have one sub-list (in the form + * described above) for each option in the table. If an error + * occurs (e.g. because namePtr isn't valid) then NULL is returned + * and an error message will be left in interp's result unless + * interp is NULL. * * Side effects: * None. @@ -581,47 +1638,40 @@ DoConfig(interp, tkwin, specPtr, value, valueIsUid, widgRec) *-------------------------------------------------------------- */ -int -Tk_ConfigureInfo(interp, tkwin, specs, widgRec, argvName, flags) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Window tkwin; /* Window corresponding to widgRec. */ - Tk_ConfigSpec *specs; /* Describes legal options. */ - char *widgRec; /* Record whose fields contain current +Tcl_Obj * +Tk_GetOptionInfo(interp, recordPtr, optionTable, namePtr, tkwin) + Tcl_Interp *interp; /* Interpreter for error reporting. If + * NULL, then no error message is created. */ + char *recordPtr; /* Record whose fields contain current * values for options. */ - char *argvName; /* If non-NULL, indicates a single option - * whose info is to be returned. Otherwise - * info is returned for all options. */ - int flags; /* Used to specify additional flags - * that must be present in config specs - * for them to be considered. */ + Tk_OptionTable optionTable; /* Describes all the legal options. */ + Tcl_Obj *namePtr; /* If non-NULL, the string value selects + * a single option whose info is to be + * returned. Otherwise info is returned for + * all options in optionTable. */ + Tk_Window tkwin; /* Window associated with recordPtr; needed + * to compute correct default value for some + * options. */ { - register Tk_ConfigSpec *specPtr; - int needFlags, hateFlags; - char *list; - char *leader = "{"; - - needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); - if (Tk_Depth(tkwin) <= 1) { - hateFlags = TK_CONFIG_COLOR_ONLY; - } else { - hateFlags = TK_CONFIG_MONO_ONLY; - } + Tcl_Obj *resultPtr; + OptionTable *tablePtr = (OptionTable *) optionTable; + Option *optionPtr; + int count; /* * If information is only wanted for a single configuration * spec, then handle that one spec specially. */ - Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); - if (argvName != NULL) { - specPtr = FindConfigSpec(interp, specs, argvName, needFlags, - hateFlags); - if (specPtr == NULL) { - return TCL_ERROR; + if (namePtr != NULL) { + optionPtr = GetOptionFromObj(interp, namePtr, tablePtr); + if (optionPtr == NULL) { + return (Tcl_Obj *) NULL; + } + if (optionPtr->specPtr->type == TK_OPTION_SYNONYM) { + optionPtr = optionPtr->extra.synonymPtr; } - interp->result = FormatConfigInfo(interp, tkwin, specPtr, widgRec); - interp->freeProc = TCL_DYNAMIC; - return TCL_OK; + return GetConfigList(recordPtr, optionPtr, tkwin); } /* @@ -629,29 +1679,21 @@ Tk_ConfigureInfo(interp, tkwin, specs, widgRec, argvName, flags) * their information. */ - for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { - if ((argvName != NULL) && (specPtr->argvName != argvName)) { - continue; - } - if (((specPtr->specFlags & needFlags) != needFlags) - || (specPtr->specFlags & hateFlags)) { - continue; + resultPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); + for (; tablePtr != NULL; tablePtr = tablePtr->nextPtr) { + for (optionPtr = tablePtr->options, count = tablePtr->numOptions; + count > 0; optionPtr++, count--) { + Tcl_ListObjAppendElement(interp, resultPtr, + GetConfigList(recordPtr, optionPtr, tkwin)); } - if (specPtr->argvName == NULL) { - continue; - } - list = FormatConfigInfo(interp, tkwin, specPtr, widgRec); - Tcl_AppendResult(interp, leader, list, "}", (char *) NULL); - ckfree(list); - leader = " {"; } - return TCL_OK; + return resultPtr; } /* *-------------------------------------------------------------- * - * FormatConfigInfo -- + * GetConfigList -- * * Create a valid Tcl list holding the configuration information * for a single configuration option. @@ -666,67 +1708,78 @@ Tk_ConfigureInfo(interp, tkwin, specs, widgRec, argvName, flags) *-------------------------------------------------------------- */ -static char * -FormatConfigInfo(interp, tkwin, specPtr, widgRec) - Tcl_Interp *interp; /* Interpreter to use for things - * like floating-point precision. */ - Tk_Window tkwin; /* Window corresponding to widget. */ - register Tk_ConfigSpec *specPtr; /* Pointer to information describing - * option. */ - char *widgRec; /* Pointer to record holding current - * values of info for widget. */ +static Tcl_Obj * +GetConfigList(recordPtr, optionPtr, tkwin) + char *recordPtr; /* Pointer to record holding current + * values of configuration options. */ + Option *optionPtr; /* Pointer to information describing a + * particular option. */ + Tk_Window tkwin; /* Window corresponding to recordPtr. */ { - char *argv[6], *result; - char buffer[200]; - Tcl_FreeProc *freeProc = (Tcl_FreeProc *) NULL; - - argv[0] = specPtr->argvName; - argv[1] = specPtr->dbName; - argv[2] = specPtr->dbClass; - argv[3] = specPtr->defValue; - if (specPtr->type == TK_CONFIG_SYNONYM) { - return Tcl_Merge(2, argv); - } - argv[4] = FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, - &freeProc); - if (argv[1] == NULL) { - argv[1] = ""; - } - if (argv[2] == NULL) { - argv[2] = ""; - } - if (argv[3] == NULL) { - argv[3] = ""; - } - if (argv[4] == NULL) { - argv[4] = ""; - } - result = Tcl_Merge(5, argv); - if (freeProc != NULL) { - if ((freeProc == TCL_DYNAMIC) || (freeProc == (Tcl_FreeProc *) free)) { - ckfree(argv[4]); + Tcl_Obj *listPtr, *elementPtr; + + listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); + Tcl_ListObjAppendElement((Tcl_Interp *) NULL, listPtr, + Tcl_NewStringObj(optionPtr->specPtr->optionName, -1)); + + if (optionPtr->specPtr->type == TK_OPTION_SYNONYM) { + elementPtr = Tcl_NewStringObj( + optionPtr->extra.synonymPtr->specPtr->optionName, -1); + Tcl_ListObjAppendElement((Tcl_Interp *) NULL, listPtr, elementPtr); + } else { + if (optionPtr->dbNameUID == NULL) { + elementPtr = Tcl_NewObj(); + } else { + elementPtr = Tcl_NewStringObj(optionPtr->dbNameUID, -1); + } + Tcl_ListObjAppendElement((Tcl_Interp *) NULL, listPtr, elementPtr); + + if (optionPtr->dbClassUID == NULL) { + elementPtr = Tcl_NewObj(); } else { - (*freeProc)(argv[4]); + elementPtr = Tcl_NewStringObj(optionPtr->dbClassUID, -1); } + Tcl_ListObjAppendElement((Tcl_Interp *) NULL, listPtr, elementPtr); + + if ((tkwin != NULL) && ((optionPtr->specPtr->type == TK_OPTION_COLOR) + || (optionPtr->specPtr->type == TK_OPTION_BORDER)) + && (Tk_Depth(tkwin) <= 1) + && (optionPtr->extra.monoColorPtr != NULL)) { + elementPtr = optionPtr->extra.monoColorPtr; + } else if (optionPtr->defaultPtr != NULL) { + elementPtr = optionPtr->defaultPtr; + } else { + elementPtr = Tcl_NewObj(); + } + Tcl_ListObjAppendElement((Tcl_Interp *) NULL, listPtr, elementPtr); + + if (optionPtr->specPtr->objOffset >= 0) { + elementPtr = *((Tcl_Obj **) (recordPtr + + optionPtr->specPtr->objOffset)); + if (elementPtr == NULL) { + elementPtr = Tcl_NewObj(); + } + } else { + elementPtr = GetObjectForOption(recordPtr, optionPtr, tkwin); + } + Tcl_ListObjAppendElement((Tcl_Interp *) NULL, listPtr, elementPtr); } - return result; + return listPtr; } /* *---------------------------------------------------------------------- * - * FormatConfigValue -- + * GetObjectForOption -- * - * This procedure formats the current value of a configuration - * option. + * This procedure is called to create an object that contains the + * value for an option. It is invoked by GetConfigList and + * Tk_GetOptionValue when only the internal form of an option is + * stored in the record. * * Results: - * The return value is the formatted value of the option given - * by specPtr and widgRec. If the value is static, so that it - * need not be freed, *freeProcPtr will be set to NULL; otherwise - * *freeProcPtr will be set to the address of a procedure to - * free the result, and the caller must invoke this procedure - * when it is finished with the result. + * The return value is a pointer to a Tcl object. The caller + * must call Tcl_IncrRefCount on this object to preserve it. * * Side effects: * None. @@ -734,146 +1787,130 @@ FormatConfigInfo(interp, tkwin, specPtr, widgRec) *---------------------------------------------------------------------- */ -static char * -FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, freeProcPtr) - Tcl_Interp *interp; /* Interpreter for use in real conversions. */ - Tk_Window tkwin; /* Window corresponding to widget. */ - Tk_ConfigSpec *specPtr; /* Pointer to information describing option. - * Must not point to a synonym option. */ - char *widgRec; /* Pointer to record holding current - * values of info for widget. */ - char *buffer; /* Static buffer to use for small values. - * Must have at least 200 bytes of storage. */ - Tcl_FreeProc **freeProcPtr; /* Pointer to word to fill in with address - * of procedure to free the result, or NULL - * if result is static. */ +static Tcl_Obj * +GetObjectForOption(recordPtr, optionPtr, tkwin) + char *recordPtr; /* Pointer to record holding current + * values of configuration options. */ + Option *optionPtr; /* Pointer to information describing an + * option whose internal value is stored + * in *recordPtr. */ + Tk_Window tkwin; /* Window corresponding to recordPtr. */ { - char *ptr, *result; - - *freeProcPtr = NULL; - ptr = widgRec + specPtr->offset; - result = ""; - switch (specPtr->type) { - case TK_CONFIG_BOOLEAN: - if (*((int *) ptr) == 0) { - result = "0"; - } else { - result = "1"; - } + Tcl_Obj *objPtr; + char *internalPtr; /* Points to internal value of option in + * record. */ + + internalPtr = recordPtr + optionPtr->specPtr->internalOffset; + objPtr = NULL; + switch (optionPtr->specPtr->type) { + case TK_OPTION_BOOLEAN: { + objPtr = Tcl_NewIntObj(*((int *) internalPtr)); break; - case TK_CONFIG_INT: - sprintf(buffer, "%d", *((int *) ptr)); - result = buffer; + } + case TK_OPTION_INT: { + objPtr = Tcl_NewIntObj(*((int *) internalPtr)); break; - case TK_CONFIG_DOUBLE: - Tcl_PrintDouble(interp, *((double *) ptr), buffer); - result = buffer; + } + case TK_OPTION_DOUBLE: { + objPtr = Tcl_NewDoubleObj(*((double *) internalPtr)); break; - case TK_CONFIG_STRING: - result = (*(char **) ptr); - if (result == NULL) { - result = ""; - } + } + case TK_OPTION_STRING: { + objPtr = Tcl_NewStringObj(*((char **) internalPtr), -1); break; - case TK_CONFIG_UID: { - Tk_Uid uid = *((Tk_Uid *) ptr); - if (uid != NULL) { - result = uid; - } + } + case TK_OPTION_STRING_TABLE: { + objPtr = Tcl_NewStringObj( + ((char **) optionPtr->specPtr->clientData)[ + *((int *) internalPtr)], -1); break; } - case TK_CONFIG_COLOR: { - XColor *colorPtr = *((XColor **) ptr); + case TK_OPTION_COLOR: { + XColor *colorPtr = *((XColor **) internalPtr); if (colorPtr != NULL) { - result = Tk_NameOfColor(colorPtr); + objPtr = Tcl_NewStringObj(Tk_NameOfColor(colorPtr), -1); } break; } - case TK_CONFIG_FONT: { - Tk_Font tkfont = *((Tk_Font *) ptr); + case TK_OPTION_FONT: { + Tk_Font tkfont = *((Tk_Font *) internalPtr); if (tkfont != NULL) { - result = Tk_NameOfFont(tkfont); + objPtr = Tcl_NewStringObj(Tk_NameOfFont(tkfont), -1); } break; } - case TK_CONFIG_BITMAP: { - Pixmap pixmap = *((Pixmap *) ptr); + case TK_OPTION_BITMAP: { + Pixmap pixmap = *((Pixmap *) internalPtr); if (pixmap != None) { - result = Tk_NameOfBitmap(Tk_Display(tkwin), pixmap); + objPtr = Tcl_NewStringObj(Tk_NameOfBitmap(Tk_Display(tkwin), + pixmap), -1); } break; } - case TK_CONFIG_BORDER: { - Tk_3DBorder border = *((Tk_3DBorder *) ptr); + case TK_OPTION_BORDER: { + Tk_3DBorder border = *((Tk_3DBorder *) internalPtr); if (border != NULL) { - result = Tk_NameOf3DBorder(border); + objPtr = Tcl_NewStringObj(Tk_NameOf3DBorder(border), -1); } break; } - case TK_CONFIG_RELIEF: - result = Tk_NameOfRelief(*((int *) ptr)); + case TK_OPTION_RELIEF: { + objPtr = Tcl_NewStringObj(Tk_NameOfRelief( + *((int *) internalPtr)), -1); break; - case TK_CONFIG_CURSOR: - case TK_CONFIG_ACTIVE_CURSOR: { - Tk_Cursor cursor = *((Tk_Cursor *) ptr); + } + case TK_OPTION_CURSOR: { + Tk_Cursor cursor = *((Tk_Cursor *) internalPtr); if (cursor != None) { - result = Tk_NameOfCursor(Tk_Display(tkwin), cursor); + objPtr = Tcl_NewStringObj( + Tk_NameOfCursor(Tk_Display(tkwin), cursor), -1); } break; } - case TK_CONFIG_JUSTIFY: - result = Tk_NameOfJustify(*((Tk_Justify *) ptr)); - break; - case TK_CONFIG_ANCHOR: - result = Tk_NameOfAnchor(*((Tk_Anchor *) ptr)); + case TK_OPTION_JUSTIFY: { + objPtr = Tcl_NewStringObj(Tk_NameOfJustify( + *((Tk_Justify *) internalPtr)), -1); break; - case TK_CONFIG_CAP_STYLE: - result = Tk_NameOfCapStyle(*((int *) ptr)); - break; - case TK_CONFIG_JOIN_STYLE: - result = Tk_NameOfJoinStyle(*((int *) ptr)); - break; - case TK_CONFIG_PIXELS: - sprintf(buffer, "%d", *((int *) ptr)); - result = buffer; + } + case TK_OPTION_ANCHOR: { + objPtr = Tcl_NewStringObj(Tk_NameOfAnchor( + *((Tk_Anchor *) internalPtr)), -1); break; - case TK_CONFIG_MM: - Tcl_PrintDouble(interp, *((double *) ptr), buffer); - result = buffer; + } + case TK_OPTION_PIXELS: { + objPtr = Tcl_NewIntObj(*((int *) internalPtr)); break; - case TK_CONFIG_WINDOW: { - Tk_Window tkwin; - - tkwin = *((Tk_Window *) ptr); + } + case TK_OPTION_WINDOW: { + Tk_Window tkwin = *((Tk_Window *) internalPtr); if (tkwin != NULL) { - result = Tk_PathName(tkwin); + objPtr = Tcl_NewStringObj(Tk_PathName(tkwin), -1); } break; } - case TK_CONFIG_CUSTOM: - result = (*specPtr->customPtr->printProc)( - specPtr->customPtr->clientData, tkwin, widgRec, - specPtr->offset, freeProcPtr); - break; - default: - result = "?? unknown type ??"; + default: { + panic("bad option type in GetObjectForOption"); + } } - return result; + if (objPtr == NULL) { + objPtr = Tcl_NewObj(); + } + return objPtr; } /* *---------------------------------------------------------------------- * - * Tk_ConfigureValue -- + * Tk_GetOptionValue -- * * This procedure returns the current value of a configuration - * option for a widget. + * option. * * Results: - * The return value is a standard Tcl completion code (TCL_OK or - * TCL_ERROR). Interp->result will be set to hold either the value - * of the option given by argvName (if TCL_OK is returned) or - * an error message (if TCL_ERROR is returned). + * The return value is the object holding the current value of + * the option given by namePtr. If no such option exists, then + * the return value is NULL and an error message is left in + * interp's result (if interp isn't NULL). * * Side effects: * None. @@ -881,110 +1918,115 @@ FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, freeProcPtr) *---------------------------------------------------------------------- */ -int -Tk_ConfigureValue(interp, tkwin, specs, widgRec, argvName, flags) - Tcl_Interp *interp; /* Interpreter for error reporting. */ - Tk_Window tkwin; /* Window corresponding to widgRec. */ - Tk_ConfigSpec *specs; /* Describes legal options. */ - char *widgRec; /* Record whose fields contain current +Tcl_Obj * +Tk_GetOptionValue(interp, recordPtr, optionTable, namePtr, tkwin) + Tcl_Interp *interp; /* Interpreter for error reporting. If + * NULL then no messages are provided for + * errors. */ + char *recordPtr; /* Record whose fields contain current * values for options. */ - char *argvName; /* Gives the command-line name for the + Tk_OptionTable optionTable; /* Describes legal options. */ + Tcl_Obj *namePtr; /* Gives the command-line name for the * option whose value is to be returned. */ - int flags; /* Used to specify additional flags - * that must be present in config specs - * for them to be considered. */ + Tk_Window tkwin; /* Window corresponding to recordPtr. */ { - Tk_ConfigSpec *specPtr; - int needFlags, hateFlags; + OptionTable *tablePtr = (OptionTable *) optionTable; + Option *optionPtr; + Tcl_Obj *resultPtr; - needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); - if (Tk_Depth(tkwin) <= 1) { - hateFlags = TK_CONFIG_COLOR_ONLY; - } else { - hateFlags = TK_CONFIG_MONO_ONLY; + optionPtr = GetOptionFromObj(interp, namePtr, tablePtr); + if (optionPtr == NULL) { + return NULL; } - specPtr = FindConfigSpec(interp, specs, argvName, needFlags, hateFlags); - if (specPtr == NULL) { - return TCL_ERROR; + if (optionPtr->specPtr->type == TK_OPTION_SYNONYM) { + optionPtr = optionPtr->extra.synonymPtr; } - interp->result = FormatConfigValue(interp, tkwin, specPtr, widgRec, - interp->result, &interp->freeProc); - return TCL_OK; + if (optionPtr->specPtr->objOffset >= 0) { + resultPtr = *((Tcl_Obj **) (recordPtr + optionPtr->specPtr->objOffset)); + if (resultPtr == NULL) { + /* + * This option has a null value and is represented by a null + * object pointer. We can't return the null pointer, since that + * would indicate an error. Instead, return a new empty object. + */ + + resultPtr = Tcl_NewObj(); + } + } else { + resultPtr = GetObjectForOption(recordPtr, optionPtr, tkwin); + } + return resultPtr; } /* *---------------------------------------------------------------------- * - * Tk_FreeOptions -- + * TkDebugConfig -- * - * Free up all resources associated with configuration options. + * This is a debugging procedure that returns information about + * one of the configuration tables that currently exists for an + * interpreter. * * Results: - * None. + * If the specified table exists in the given interpreter, then a + * list is returned describing the table and any other tables that + * it chains to: for each table there will be three list elements + * giving the reference count for the table, the number of elements + * in the table, and the command-line name for the first option + * in the table. If the table doesn't exist in the interpreter + * then an empty object is returned. The reference count for the + * returned object is 0. * * Side effects: - * Any resource in widgRec that is controlled by a configuration - * option (e.g. a Tk_3DBorder or XColor) is freed in the appropriate - * fashion. + * None. * *---------------------------------------------------------------------- */ - /* ARGSUSED */ -void -Tk_FreeOptions(specs, widgRec, display, needFlags) - Tk_ConfigSpec *specs; /* Describes legal options. */ - char *widgRec; /* Record whose fields contain current - * values for options. */ - Display *display; /* X display; needed for freeing some - * resources. */ - int needFlags; /* Used to specify additional flags - * that must be present in config specs - * for them to be considered. */ +Tcl_Obj * +TkDebugConfig(interp, table) + Tcl_Interp *interp; /* Interpreter in which the table is + * defined. */ + Tk_OptionTable table; /* Table about which information is to + * be returned. May not necessarily + * exist in the interpreter anymore. */ { - register Tk_ConfigSpec *specPtr; - char *ptr; + OptionTable *tablePtr = (OptionTable *) table; + Tcl_HashTable *hashTablePtr; + Tcl_HashEntry *hashEntryPtr; + Tcl_HashSearch search; + Tcl_Obj *objPtr; - for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { - if ((specPtr->specFlags & needFlags) != needFlags) { - continue; - } - ptr = widgRec + specPtr->offset; - switch (specPtr->type) { - case TK_CONFIG_STRING: - if (*((char **) ptr) != NULL) { - ckfree(*((char **) ptr)); - *((char **) ptr) = NULL; - } - break; - case TK_CONFIG_COLOR: - if (*((XColor **) ptr) != NULL) { - Tk_FreeColor(*((XColor **) ptr)); - *((XColor **) ptr) = NULL; - } - break; - case TK_CONFIG_FONT: - Tk_FreeFont(*((Tk_Font *) ptr)); - *((Tk_Font *) ptr) = NULL; - break; - case TK_CONFIG_BITMAP: - if (*((Pixmap *) ptr) != None) { - Tk_FreeBitmap(display, *((Pixmap *) ptr)); - *((Pixmap *) ptr) = None; - } - break; - case TK_CONFIG_BORDER: - if (*((Tk_3DBorder *) ptr) != NULL) { - Tk_Free3DBorder(*((Tk_3DBorder *) ptr)); - *((Tk_3DBorder *) ptr) = NULL; - } - break; - case TK_CONFIG_CURSOR: - case TK_CONFIG_ACTIVE_CURSOR: - if (*((Tk_Cursor *) ptr) != None) { - Tk_FreeCursor(display, *((Tk_Cursor *) ptr)); - *((Tk_Cursor *) ptr) = None; - } + objPtr = Tcl_NewObj(); + hashTablePtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, OPTION_HASH_KEY, + NULL); + if (hashTablePtr == NULL) { + return objPtr; + } + + /* + * Scan all the tables for this interpreter to make sure that the + * one we want still is valid. + */ + + for (hashEntryPtr = Tcl_FirstHashEntry(hashTablePtr, &search); + hashEntryPtr != NULL; + hashEntryPtr = Tcl_NextHashEntry(&search)) { + if (tablePtr == (OptionTable *) Tcl_GetHashValue(hashEntryPtr)) { + for ( ; tablePtr != NULL; tablePtr = tablePtr->nextPtr) { + Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr, + Tcl_NewIntObj(tablePtr->refCount)); + Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr, + Tcl_NewIntObj(tablePtr->numOptions)); + Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr, + Tcl_NewStringObj( + tablePtr->options[0].specPtr->optionName, + -1)); + } + break; } } + return objPtr; } + + diff --git a/tk/generic/tkConsole.c b/tk/generic/tkConsole.c index 2294368e1ca..69b113b13ba 100644 --- a/tk/generic/tkConsole.c +++ b/tk/generic/tkConsole.c @@ -16,6 +16,8 @@ #include "tk.h" #include <string.h> +#include "tkInt.h" + /* * A data structure of the following type holds information for each console * which a handler (i.e. a Tcl command) has been defined for a particular @@ -27,7 +29,17 @@ typedef struct ConsoleInfo { Tcl_Interp *interp; /* Interpreter to send console commands. */ } ConsoleInfo; -static Tcl_Interp *gStdoutInterp = NULL; +typedef struct ThreadSpecificData { + Tcl_Interp *gStdoutInterp; +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; +static int consoleInitialized = 0; + +/* + * The Mutex below is used to lock access to the consoleIntialized flag + */ + +TCL_DECLARE_MUTEX(consoleMutex) /* * Forward declarations for procedures defined later in this file: @@ -35,8 +47,6 @@ static Tcl_Interp *gStdoutInterp = NULL; * The first three will be used in the tk app shells... */ -void TkConsoleCreate _ANSI_ARGS_((void)); -int TkConsoleInit _ANSI_ARGS_((Tcl_Interp *interp)); void TkConsolePrint _ANSI_ARGS_((Tcl_Interp *interp, int devId, char *buffer, long size)); @@ -75,11 +85,111 @@ static Tcl_ChannelType consoleChannelType = { ConsoleWatch, /* Watch for events on console. */ ConsoleHandle, /* Get a handle from the device. */ }; + + +#ifdef __WIN32__ + +#include <windows.h> + +/* + *---------------------------------------------------------------------- + * + * ShouldUseConsoleChannel + * + * Check to see if console window should be used for a given + * standard channel + * + * Results: + * None. + * + * Side effects: + * Creates the console channel and installs it as the standard + * channels. + * + *---------------------------------------------------------------------- + */ +static int ShouldUseConsoleChannel(type) + int type; +{ + DWORD handleId; /* Standard handle to retrieve. */ + DCB dcb; + DWORD consoleParams; + DWORD fileType; + int mode; + char *bufMode; + HANDLE handle; + + switch (type) { + case TCL_STDIN: + handleId = STD_INPUT_HANDLE; + mode = TCL_READABLE; + bufMode = "line"; + break; + case TCL_STDOUT: + handleId = STD_OUTPUT_HANDLE; + mode = TCL_WRITABLE; + bufMode = "line"; + break; + case TCL_STDERR: + handleId = STD_ERROR_HANDLE; + mode = TCL_WRITABLE; + bufMode = "none"; + break; + default: + return 0; + break; + } + + handle = GetStdHandle(handleId); + + /* + * Note that we need to check for 0 because Windows will return 0 if this + * is not a console mode application, even though this is not a valid + * handle. + */ + + if ((handle == INVALID_HANDLE_VALUE) || (handle == 0)) { + return 1; + } + fileType = GetFileType(handle); + + /* + * If the file is a character device, we need to try to figure out + * whether it is a serial port, a console, or something else. We + * test for the console case first because this is more common. + */ + + if (fileType == FILE_TYPE_CHAR) { + dcb.DCBlength = sizeof( DCB ) ; + if (!GetConsoleMode(handle, &consoleParams) && + !GetCommState(handle, &dcb)) { + /* + * Don't use a CHAR type channel for stdio, otherwise Tk + * runs into trouble with the MS DevStudio debugger. + */ + + return 1; + } + } else if (fileType == FILE_TYPE_UNKNOWN) { + return 1; + } else if (Tcl_GetStdChannel(type) == NULL) { + return 1; + } + + return 0; +} +#else +/* + * Mac should always use a console channel, Unix should if it's trying to + */ + +#define ShouldUseConsoleChannel(chan) (1) +#endif /* *---------------------------------------------------------------------- * - * TkConsoleCreate -- + * Tk_InitConsoleChannels -- * * Create the console channels and install them as the standard * channels. All I/O will be discarded until TkConsoleInit is @@ -96,37 +206,95 @@ static Tcl_ChannelType consoleChannelType = { */ void -TkConsoleCreate() +Tk_InitConsoleChannels(interp) + Tcl_Interp *interp; { Tcl_Channel consoleChannel; - consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console0", - (ClientData) TCL_STDIN, TCL_READABLE); - if (consoleChannel != NULL) { - Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf"); - Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none"); - } - Tcl_SetStdChannel(consoleChannel, TCL_STDIN); - consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console1", - (ClientData) TCL_STDOUT, TCL_WRITABLE); - if (consoleChannel != NULL) { - Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf"); - Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none"); + /* + * Ensure that we are getting the matching version of Tcl. This is + * really only an issue when Tk is loaded dynamically. + */ + + if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { + return; } - Tcl_SetStdChannel(consoleChannel, TCL_STDOUT); - consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console2", - (ClientData) TCL_STDERR, TCL_WRITABLE); - if (consoleChannel != NULL) { - Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf"); - Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none"); + + Tcl_MutexLock(&consoleMutex); + if (!consoleInitialized) { + + consoleInitialized = 1; + + /* + * check for STDIN, otherwise create it + * + * Don't do this check on the Mac, because it is hard to prevent + * callbacks from the SIOUX layer from opening stdout & stdin, but + * we don't want to use the SIOUX console. Since the console is not + * actually created till something is written to the channel, it is + * okay to just ignore it here. + * + * This is still a bit of a hack, however, and should be cleaned up + * when we have a better abstraction for the console. + */ + + if (ShouldUseConsoleChannel(TCL_STDIN)) { + consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console0", + (ClientData) TCL_STDIN, TCL_READABLE); + if (consoleChannel != NULL) { + Tcl_SetChannelOption(NULL, consoleChannel, + "-translation", "lf"); + Tcl_SetChannelOption(NULL, consoleChannel, + "-buffering", "none"); + Tcl_SetChannelOption(NULL, consoleChannel, + "-encoding", "utf-8"); + } + Tcl_SetStdChannel(consoleChannel, TCL_STDIN); + } + + /* + * check for STDOUT, otherwise create it + */ + + if (ShouldUseConsoleChannel(TCL_STDOUT)) { + consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console1", + (ClientData) TCL_STDOUT, TCL_WRITABLE); + if (consoleChannel != NULL) { + Tcl_SetChannelOption(NULL, consoleChannel, + "-translation", "lf"); + Tcl_SetChannelOption(NULL, consoleChannel, + "-buffering", "none"); + Tcl_SetChannelOption(NULL, consoleChannel, + "-encoding", "utf-8"); + } + Tcl_SetStdChannel(consoleChannel, TCL_STDOUT); + } + + /* + * check for STDERR, otherwise create it + */ + + if (ShouldUseConsoleChannel(TCL_STDERR)) { + consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console2", + (ClientData) TCL_STDERR, TCL_WRITABLE); + if (consoleChannel != NULL) { + Tcl_SetChannelOption(NULL, consoleChannel, + "-translation", "lf"); + Tcl_SetChannelOption(NULL, consoleChannel, + "-buffering", "none"); + Tcl_SetChannelOption(NULL, consoleChannel, + "-encoding", "utf-8"); + } + Tcl_SetStdChannel(consoleChannel, TCL_STDERR); + } } - Tcl_SetStdChannel(consoleChannel, TCL_STDERR); + Tcl_MutexUnlock(&consoleMutex); } /* *---------------------------------------------------------------------- * - * TkConsoleInit -- + * Tk_CreateConsoleWindow -- * * Initialize the console. This code actually creates a new * application and associated interpreter. This effectivly hides @@ -142,12 +310,14 @@ TkConsoleCreate() */ int -TkConsoleInit(interp) +Tk_CreateConsoleWindow(interp) Tcl_Interp *interp; /* Interpreter to use for prompting. */ { Tcl_Interp *consoleInterp; ConsoleInfo *info; Tk_Window mainWindow = Tk_MainWindow(interp); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); #ifdef MAC_TCL static char initCmd[] = "source -rsrc {Console}"; #else @@ -169,7 +339,7 @@ TkConsoleInit(interp) if (Tk_Init(consoleInterp) != TCL_OK) { goto error; } - gStdoutInterp = interp; + tsdPtr->gStdoutInterp = interp; /* * Add console commands to the interp @@ -225,11 +395,15 @@ ConsoleOutput(instanceData, buf, toWrite, errorCode) int toWrite; /* How many bytes to write? */ int *errorCode; /* Where to store error code. */ { + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + *errorCode = 0; Tcl_SetErrno(0); - if (gStdoutInterp != NULL) { - TkConsolePrint(gStdoutInterp, (int) instanceData, buf, toWrite); + if (tsdPtr->gStdoutInterp != NULL) { + TkConsolePrint(tsdPtr->gStdoutInterp, (int) instanceData, buf, + toWrite); } return toWrite; @@ -373,9 +547,10 @@ ConsoleCmd(clientData, interp, argc, argv) { ConsoleInfo *info = (ConsoleInfo *) clientData; char c; - int length; + size_t length; int result; Tcl_Interp *consoleInterp; + Tcl_DString dString; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], @@ -388,23 +563,25 @@ ConsoleCmd(clientData, interp, argc, argv) result = TCL_OK; consoleInterp = info->consoleInterp; Tcl_Preserve((ClientData) consoleInterp); + Tcl_DStringInit(&dString); + if ((c == 't') && (strncmp(argv[1], "title", length)) == 0) { - Tcl_DString dString; - - Tcl_DStringInit(&dString); Tcl_DStringAppend(&dString, "wm title . ", -1); if (argc == 3) { Tcl_DStringAppendElement(&dString, argv[2]); } Tcl_Eval(consoleInterp, Tcl_DStringValue(&dString)); - Tcl_DStringFree(&dString); } else if ((c == 'h') && (strncmp(argv[1], "hide", length)) == 0) { - Tcl_Eval(info->consoleInterp, "wm withdraw ."); + Tcl_DStringAppend(&dString, "wm withdraw . ", -1); + Tcl_Eval(consoleInterp, Tcl_DStringValue(&dString)); } else if ((c == 's') && (strncmp(argv[1], "show", length)) == 0) { - Tcl_Eval(info->consoleInterp, "wm deiconify ."); + Tcl_DStringAppend(&dString, "wm deiconify . ", -1); + Tcl_Eval(consoleInterp, Tcl_DStringValue(&dString)); } else if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) { if (argc == 3) { - Tcl_Eval(info->consoleInterp, argv[2]); + result = Tcl_Eval(consoleInterp, argv[2]); + Tcl_AppendResult(interp, Tcl_GetStringResult(consoleInterp), + (char *) NULL); } else { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " eval command\"", (char *) NULL); @@ -416,6 +593,7 @@ ConsoleCmd(clientData, interp, argc, argv) (char *) NULL); result = TCL_ERROR; } + Tcl_DStringFree(&dString); Tcl_Release((ClientData) consoleInterp); return result; } @@ -446,7 +624,7 @@ InterpreterCmd(clientData, interp, argc, argv) { ConsoleInfo *info = (ConsoleInfo *) clientData; char c; - int length; + size_t length; int result; Tcl_Interp *otherInterp; @@ -466,6 +644,7 @@ InterpreterCmd(clientData, interp, argc, argv) } else if ((c == 'r') && (strncmp(argv[1], "record", length)) == 0) { Tcl_RecordAndEval(otherInterp, argv[2], TCL_EVAL_GLOBAL); result = TCL_OK; + Tcl_ResetResult(interp); Tcl_AppendResult(interp, otherInterp->result, (char *) NULL); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], @@ -494,7 +673,7 @@ InterpreterCmd(clientData, interp, argc, argv) *---------------------------------------------------------------------- */ -void +static void ConsoleDeleteProc(clientData) ClientData clientData; { @@ -530,9 +709,13 @@ ConsoleEventProc(clientData, eventPtr) { ConsoleInfo *info = (ConsoleInfo *) clientData; Tcl_Interp *consoleInterp; + Tcl_DString dString; if (eventPtr->type == DestroyNotify) { - consoleInterp = info->consoleInterp; + + Tcl_DStringInit(&dString); + + consoleInterp = info->consoleInterp; /* * It is possible that the console interpreter itself has @@ -545,7 +728,9 @@ ConsoleEventProc(clientData, eventPtr) return; } Tcl_Preserve((ClientData) consoleInterp); - Tcl_Eval(consoleInterp, "tkConsoleExit"); + Tcl_DStringAppend(&dString, "tkConsoleExit", -1); + Tcl_Eval(consoleInterp, Tcl_DStringValue(&dString)); + Tcl_DStringFree(&dString); Tcl_Release((ClientData) consoleInterp); } } @@ -603,7 +788,7 @@ TkConsolePrint(interp, devId, buffer, size) Tcl_DStringAppend(&output, buffer, size); Tcl_DStringInit(&command); - Tcl_DStringAppend(&command, cmd, strlen(cmd)); + Tcl_DStringAppend(&command, cmd, (int) strlen(cmd)); Tcl_DStringAppendElement(&command, output.string); consoleInterp = info->consoleInterp; @@ -614,3 +799,4 @@ TkConsolePrint(interp, devId, buffer, size) Tcl_DStringFree(&command); Tcl_DStringFree(&output); } + diff --git a/tk/generic/tkCursor.c b/tk/generic/tkCursor.c index 31d2d1ca736..6782550b3ba 100644 --- a/tk/generic/tkCursor.c +++ b/tk/generic/tkCursor.c @@ -6,7 +6,7 @@ * 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. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -20,28 +20,11 @@ /* * 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. + * below. One of the tables is cursorIdTable, and the other is either + * cursorNameTable or cursorDataTable, each of which are stored in the + * TkDisplay structure for the current thread. */ -/* - * 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. */ @@ -53,24 +36,129 @@ typedef struct { } DataKey; /* - * Hash table that maps from <display + cursor id> to the TkCursor structure - * for the cursor. This table is used by Tk_FreeCursor. + * Forward declarations for procedures defined in this file: */ -static Tcl_HashTable idTable; -typedef struct { - Display *display; /* Display for which cursor was allocated. */ - Tk_Cursor cursor; /* Cursor identifier. */ -} IdKey; +static void CursorInit _ANSI_ARGS_((TkDisplay *dispPtr)); +static void DupCursorObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr, + Tcl_Obj *dupObjPtr)); +static void FreeCursor _ANSI_ARGS_((TkCursor *cursorPtr)); +static void FreeCursorObjProc _ANSI_ARGS_((Tcl_Obj *objPtr)); +static TkCursor * GetCursor _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, char *name)); +static TkCursor * GetCursorFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj *objPtr)); +static void InitCursorObj _ANSI_ARGS_((Tcl_Obj *objPtr)); -static int initialized = 0; /* 0 means static structures haven't been - * initialized yet. */ +/* + * The following structure defines the implementation of the "cursor" Tcl + * object, used for drawing. The color object remembers the hash table + * entry associated with a color. The actual allocation and deallocation + * of the color should be done by the configuration package when the cursor + * option is set. + */ +static Tcl_ObjType cursorObjType = { + "cursor", /* name */ + FreeCursorObjProc, /* freeIntRepProc */ + DupCursorObjProc, /* dupIntRepProc */ + NULL, /* updateStringProc */ + NULL /* setFromAnyProc */ +}; + /* - * Forward declarations for procedures defined in this file: + *---------------------------------------------------------------------- + * + * Tk_AllocCursorFromObj -- + * + * Given a Tcl_Obj *, map the value to a corresponding + * Tk_Cursor structure based on the tkwin given. + * + * Results: + * The return value is the X identifer for the desired cursor, + * unless objPtr couldn't be parsed correctly. In this case, + * None is returned and an error message is left in the interp's result. + * The caller should never modify the cursor that is returned, and + * should eventually call Tk_FreeCursorFromObj 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_FreeCursorFromObj, so that the database can be cleaned up + * when cursors aren't needed anymore. + * + *---------------------------------------------------------------------- */ -static void CursorInit _ANSI_ARGS_((void)); +Tk_Cursor +Tk_AllocCursorFromObj(interp, tkwin, objPtr) + Tcl_Interp *interp; /* Interp for error results. */ + Tk_Window tkwin; /* Window in which the cursor will be used.*/ + Tcl_Obj *objPtr; /* Object describing cursor; see manual + * entry for description of legal + * syntax of this obj's string rep. */ +{ + TkCursor *cursorPtr; + + if (objPtr->typePtr != &cursorObjType) { + InitCursorObj(objPtr); + } + cursorPtr = (TkCursor *) objPtr->internalRep.twoPtrValue.ptr1; + + /* + * If the object currently points to a TkCursor, see if it's the + * one we want. If so, increment its reference count and return. + */ + + if (cursorPtr != NULL) { + if (cursorPtr->resourceRefCount == 0) { + /* + * This is a stale reference: it refers to a TkCursor that's + * no longer in use. Clear the reference. + */ + FreeCursorObjProc(objPtr); + cursorPtr = NULL; + } else if (Tk_Display(tkwin) == cursorPtr->display) { + cursorPtr->resourceRefCount++; + return cursorPtr->cursor; + } + } + + /* + * The object didn't point to the TkCursor that we wanted. Search + * the list of TkCursors with the same name to see if one of the + * other TkCursors is the right one. + */ + + if (cursorPtr != NULL) { + TkCursor *firstCursorPtr = + (TkCursor *) Tcl_GetHashValue(cursorPtr->hashPtr); + FreeCursorObjProc(objPtr); + for (cursorPtr = firstCursorPtr; cursorPtr != NULL; + cursorPtr = cursorPtr->nextPtr) { + if (Tk_Display(tkwin) == cursorPtr->display) { + cursorPtr->resourceRefCount++; + cursorPtr->objRefCount++; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) cursorPtr; + return cursorPtr->cursor; + } + } + } + + /* + * Still no luck. Call GetCursor to allocate a new TkCursor object. + */ + + cursorPtr = GetCursor(interp, tkwin, Tcl_GetString(objPtr)); + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) cursorPtr; + if (cursorPtr == NULL) { + return None; + } else { + cursorPtr->objRefCount++; + return cursorPtr->cursor; + } +} /* *---------------------------------------------------------------------- @@ -83,7 +171,7 @@ static void CursorInit _ANSI_ARGS_((void)); * 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. + * None is returned and an error message is left in the interp's result. * The caller should never modify the cursor that is returned, and * should eventually call Tk_FreeCursor when the cursor is no longer * needed. @@ -101,52 +189,104 @@ 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 + char *string; /* Description of cursor. See manual entry * for details on legal syntax. */ { - NameKey nameKey; - IdKey idKey; - Tcl_HashEntry *nameHashPtr, *idHashPtr; + TkCursor *cursorPtr = GetCursor(interp, tkwin, string); + if (cursorPtr == NULL) { + return None; + } + return cursorPtr->cursor; +} + +/* + *---------------------------------------------------------------------- + * + * GetCursor -- + * + * Given a string describing a cursor, locate (or create if necessary) + * a cursor that fits the description. This routine returns the + * internal data structure for the cursor, which avoids extra + * hash table lookups in Tk_AllocCursorFromObj. + * + * Results: + * The return value is a pointer to the TkCursor for the desired + * cursor, unless string couldn't be parsed correctly. In this + * case, NULL is returned and an error message is left in the + * interp's 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. + * + *---------------------------------------------------------------------- + */ + +static TkCursor * +GetCursor(interp, tkwin, string) + Tcl_Interp *interp; /* Interpreter to use for error reporting. */ + Tk_Window tkwin; /* Window in which cursor will be used. */ + char *string; /* Description of cursor. See manual entry + * for details on legal syntax. */ +{ + Tcl_HashEntry *nameHashPtr; register TkCursor *cursorPtr; + TkCursor *existingCursorPtr = NULL; int new; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - if (!initialized) { - CursorInit(); + if (!dispPtr->cursorInit) { + CursorInit(dispPtr); } - nameKey.name = string; - nameKey.display = Tk_Display(tkwin); - nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new); + nameHashPtr = Tcl_CreateHashEntry(&dispPtr->cursorNameTable, + string, &new); if (!new) { - cursorPtr = (TkCursor *) Tcl_GetHashValue(nameHashPtr); - cursorPtr->refCount++; - return cursorPtr->cursor; + existingCursorPtr = (TkCursor *) Tcl_GetHashValue(nameHashPtr); + for (cursorPtr = existingCursorPtr; cursorPtr != NULL; + cursorPtr = cursorPtr->nextPtr) { + if (Tk_Display(tkwin) == cursorPtr->display) { + cursorPtr->resourceRefCount++; + return cursorPtr; + } + } + } else { + existingCursorPtr = NULL; } cursorPtr = TkGetCursorByName(interp, tkwin, string); if (cursorPtr == NULL) { - Tcl_DeleteHashEntry(nameHashPtr); - return None; + if (new) { + Tcl_DeleteHashEntry(nameHashPtr); + } + return NULL; } /* * Add information about this cursor to our database. */ - cursorPtr->refCount = 1; - cursorPtr->otherTable = &nameTable; + cursorPtr->display = Tk_Display(tkwin); + cursorPtr->resourceRefCount = 1; + cursorPtr->objRefCount = 0; + cursorPtr->otherTable = &dispPtr->cursorNameTable; cursorPtr->hashPtr = nameHashPtr; - idKey.display = nameKey.display; - idKey.cursor = cursorPtr->cursor; - idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new); + cursorPtr->nextPtr = NULL; + cursorPtr->idHashPtr = Tcl_CreateHashEntry(&dispPtr->cursorIdTable, + (char *) cursorPtr->cursor, &new); if (!new) { panic("cursor already registered in Tk_GetCursor"); } + cursorPtr->nextPtr = existingCursorPtr; Tcl_SetHashValue(nameHashPtr, cursorPtr); - Tcl_SetHashValue(idHashPtr, cursorPtr); + Tcl_SetHashValue(cursorPtr->idHashPtr, cursorPtr); - return cursorPtr->cursor; + return cursorPtr; } /* @@ -160,7 +300,7 @@ Tk_GetCursor(interp, tkwin, string) * 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 + * returned and an error message is left in the interp's result. The * caller should never modify the cursor that is returned, and * should eventually call Tk_FreeCursor when the cursor is no * longer needed. @@ -187,14 +327,15 @@ Tk_GetCursorFromData(interp, tkwin, source, mask, width, height, Tk_Uid bg; /* Background color for cursor. */ { DataKey dataKey; - IdKey idKey; - Tcl_HashEntry *dataHashPtr, *idHashPtr; + Tcl_HashEntry *dataHashPtr; register TkCursor *cursorPtr; int new; XColor fgColor, bgColor; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - if (!initialized) { - CursorInit(); + + if (!dispPtr->cursorInit) { + CursorInit(dispPtr); } dataKey.source = source; @@ -206,10 +347,11 @@ Tk_GetCursorFromData(interp, tkwin, source, mask, width, height, dataKey.fg = fg; dataKey.bg = bg; dataKey.display = Tk_Display(tkwin); - dataHashPtr = Tcl_CreateHashEntry(&dataTable, (char *) &dataKey, &new); + dataHashPtr = Tcl_CreateHashEntry(&dispPtr->cursorDataTable, + (char *) &dataKey, &new); if (!new) { cursorPtr = (TkCursor *) Tcl_GetHashValue(dataHashPtr); - cursorPtr->refCount++; + cursorPtr->resourceRefCount++; return cursorPtr->cursor; } @@ -236,17 +378,18 @@ Tk_GetCursorFromData(interp, tkwin, source, mask, width, height, goto error; } - cursorPtr->refCount = 1; - cursorPtr->otherTable = &dataTable; + cursorPtr->resourceRefCount = 1; + cursorPtr->otherTable = &dispPtr->cursorDataTable; cursorPtr->hashPtr = dataHashPtr; - idKey.display = dataKey.display; - idKey.cursor = cursorPtr->cursor; - idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new); + cursorPtr->objRefCount = 0; + cursorPtr->idHashPtr = Tcl_CreateHashEntry(&dispPtr->cursorIdTable, + (char *) cursorPtr->cursor, &new); + if (!new) { panic("cursor already registered in Tk_GetCursorFromData"); } Tcl_SetHashValue(dataHashPtr, cursorPtr); - Tcl_SetHashValue(idHashPtr, cursorPtr); + Tcl_SetHashValue(cursorPtr->idHashPtr, cursorPtr); return cursorPtr->cursor; error: @@ -281,27 +424,77 @@ Tk_NameOfCursor(display, cursor) Tk_Cursor cursor; /* Identifier for cursor whose name is * wanted. */ { - IdKey idKey; Tcl_HashEntry *idHashPtr; TkCursor *cursorPtr; - static char string[20]; + TkDisplay *dispPtr; - if (!initialized) { + dispPtr = TkGetDisplay(display); + + if (!dispPtr->cursorInit) { printid: - sprintf(string, "cursor id 0x%x", (unsigned int) cursor); - return string; + sprintf(dispPtr->cursorString, "cursor id 0x%x", + (unsigned int) cursor); + return dispPtr->cursorString; } - idKey.display = display; - idKey.cursor = cursor; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); + idHashPtr = Tcl_FindHashEntry(&dispPtr->cursorIdTable, (char *) cursor); if (idHashPtr == NULL) { goto printid; } cursorPtr = (TkCursor *) Tcl_GetHashValue(idHashPtr); - if (cursorPtr->otherTable != &nameTable) { + if (cursorPtr->otherTable != &dispPtr->cursorNameTable) { goto printid; } - return ((NameKey *) cursorPtr->hashPtr->key.words)->name; + return cursorPtr->hashPtr->key.string; +} + +/* + *---------------------------------------------------------------------- + * + * FreeCursor -- + * + * This procedure is invoked by both Tk_FreeCursor and + * Tk_FreeCursorFromObj; it does all the real work of deallocating + * a cursor. + * + * Results: + * None. + * + * Side effects: + * The reference count associated with cursor is decremented, and + * it is officially deallocated if no-one is using it anymore. + * + *---------------------------------------------------------------------- + */ + +static void +FreeCursor(cursorPtr) + TkCursor *cursorPtr; /* Cursor to be released. */ +{ + TkCursor *prevPtr; + + cursorPtr->resourceRefCount--; + if (cursorPtr->resourceRefCount > 0) { + return; + } + + Tcl_DeleteHashEntry(cursorPtr->idHashPtr); + prevPtr = (TkCursor *) Tcl_GetHashValue(cursorPtr->hashPtr); + if (prevPtr == cursorPtr) { + if (cursorPtr->nextPtr == NULL) { + Tcl_DeleteHashEntry(cursorPtr->hashPtr); + } else { + Tcl_SetHashValue(cursorPtr->hashPtr, cursorPtr->nextPtr); + } + } else { + while (prevPtr->nextPtr != cursorPtr) { + prevPtr = prevPtr->nextPtr; + } + prevPtr->nextPtr = cursorPtr->nextPtr; + } + TkpFreeCursor(cursorPtr); + if (cursorPtr->objRefCount == 0) { + ckfree((char *) cursorPtr); + } } /* @@ -327,27 +520,258 @@ 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; + TkDisplay *dispPtr = TkGetDisplay(display); - if (!initialized) { + if (!dispPtr->cursorInit) { panic("Tk_FreeCursor called before Tk_GetCursor"); } - idKey.display = display; - idKey.cursor = cursor; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); + idHashPtr = Tcl_FindHashEntry(&dispPtr->cursorIdTable, (char *) cursor); 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); + FreeCursor((TkCursor *) Tcl_GetHashValue(idHashPtr)); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_FreeCursorFromObj -- + * + * This procedure is called to release a cursor allocated by + * Tk_AllocCursorFromObj. It does not throw away the Tcl_Obj *; + * it only gets rid of the hash table entry for this cursor + * and clears the cached value that is normally stored in the object. + * + * Results: + * None. + * + * Side effects: + * The reference count associated with the cursor represented by + * objPtr is decremented, and the cursor is released to X if there are + * no remaining uses for it. + * + *---------------------------------------------------------------------- + */ + +void +Tk_FreeCursorFromObj(tkwin, objPtr) + Tk_Window tkwin; /* The window this cursor lives in. Needed + * for the display value. */ + Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */ +{ + FreeCursor(GetCursorFromObj(tkwin, objPtr)); + FreeCursorObjProc(objPtr); +} + +/* + *--------------------------------------------------------------------------- + * + * FreeCursorFromObjProc -- + * + * This proc is called to release an object reference to a cursor. + * Called when the object's internal rep is released or when + * the cached tkColPtr needs to be changed. + * + * Results: + * None. + * + * Side effects: + * The object reference count is decremented. When both it + * and the hash ref count go to zero, the color's resources + * are released. + * + *--------------------------------------------------------------------------- + */ + +static void +FreeCursorObjProc(objPtr) + Tcl_Obj *objPtr; /* The object we are releasing. */ +{ + TkCursor *cursorPtr = (TkCursor *) objPtr->internalRep.twoPtrValue.ptr1; + + if (cursorPtr != NULL) { + cursorPtr->objRefCount--; + if ((cursorPtr->objRefCount == 0) + && (cursorPtr->resourceRefCount == 0)) { + ckfree((char *) cursorPtr); + } + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL; + } +} + +/* + *--------------------------------------------------------------------------- + * + * DupCursorObjProc -- + * + * When a cached cursor object is duplicated, this is called to + * update the internal reps. + * + * Results: + * None. + * + * Side effects: + * The color's objRefCount is incremented and the internal rep + * of the copy is set to point to it. + * + *--------------------------------------------------------------------------- + */ + +static void +DupCursorObjProc(srcObjPtr, dupObjPtr) + Tcl_Obj *srcObjPtr; /* The object we are copying from. */ + Tcl_Obj *dupObjPtr; /* The object we are copying to. */ +{ + TkCursor *cursorPtr = (TkCursor *) srcObjPtr->internalRep.twoPtrValue.ptr1; + + dupObjPtr->typePtr = srcObjPtr->typePtr; + dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) cursorPtr; + + if (cursorPtr != NULL) { + cursorPtr->objRefCount++; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetCursorFromObj -- + * + * Returns the cursor referred to buy a Tcl object. The cursor must + * already have been allocated via a call to Tk_AllocCursorFromObj or + * Tk_GetCursor. + * + * Results: + * Returns the Tk_Cursor that matches the tkwin and the string rep + * of the name of the cursor given in objPtr. + * + * Side effects: + * If the object is not already a cursor, the conversion will free + * any old internal representation. + * + *---------------------------------------------------------------------- + */ + +Tk_Cursor +Tk_GetCursorFromObj(tkwin, objPtr) + Tk_Window tkwin; + Tcl_Obj *objPtr; /* The object from which to get pixels. */ +{ + TkCursor *cursorPtr = GetCursorFromObj(tkwin, objPtr); + /* GetCursorFromObj should never return NULL */ + return cursorPtr->cursor; +} + +/* + *---------------------------------------------------------------------- + * + * GetCursorFromObj -- + * + * Returns the cursor referred to by a Tcl object. The cursor must + * already have been allocated via a call to Tk_AllocCursorFromObj + * or Tk_GetCursor. + * + * Results: + * Returns the TkCursor * that matches the tkwin and the string rep + * of the name of the cursor given in objPtr. + * + * Side effects: + * If the object is not already a cursor, the conversion will free + * any old internal representation. + * + *---------------------------------------------------------------------- + */ + +static TkCursor * +GetCursorFromObj(tkwin, objPtr) + Tk_Window tkwin; /* Window in which the cursor will be used. */ + Tcl_Obj *objPtr; /* The object that describes the desired + * cursor. */ +{ + TkCursor *cursorPtr; + Tcl_HashEntry *hashPtr; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + + if (objPtr->typePtr != &cursorObjType) { + InitCursorObj(objPtr); + } + + /* + * The internal representation is a cache of the last cursor used + * with the given name. But there can be lots different cursors + * for each cursor name; one cursor for each display. Check to + * see if the cursor we have cached is the one that is needed. + */ + cursorPtr = (TkCursor *) objPtr->internalRep.twoPtrValue.ptr1; + if ((cursorPtr != NULL) && (Tk_Display(tkwin) == cursorPtr->display)) { + return cursorPtr; + } + + /* + * If we get to here, it means the cursor we need is not in the cache. + * Try to look up the cursor in the TkDisplay structure of the window. + */ + + hashPtr = Tcl_FindHashEntry(&dispPtr->cursorNameTable, + Tcl_GetString(objPtr)); + if (hashPtr == NULL) { + goto error; + } + for (cursorPtr = (TkCursor *) Tcl_GetHashValue(hashPtr); + cursorPtr != NULL; cursorPtr = cursorPtr->nextPtr) { + if (Tk_Display(tkwin) == cursorPtr->display) { + FreeCursorObjProc(objPtr); + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) cursorPtr; + cursorPtr->objRefCount++; + return cursorPtr; + } + } + + error: + panic("GetCursorFromObj called with non-existent cursor!"); + /* + * The following code isn't reached; it's just there to please compilers. + */ + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * InitCursorObj -- + * + * Bookeeping procedure to change an objPtr to a cursor type. + * + * Results: + * None. + * + * Side effects: + * The old internal rep of the object is freed. The internal + * rep is cleared. The final form of the object is set + * by either Tk_AllocCursorFromObj or GetCursorFromObj. + * + *---------------------------------------------------------------------- + */ + +static void +InitCursorObj(objPtr) + Tcl_Obj *objPtr; /* The object to convert. */ +{ + Tcl_ObjType *typePtr; + + /* + * Free the old internalRep before setting the new one. + */ + + Tcl_GetString(objPtr); + typePtr = objPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(objPtr); } + objPtr->typePtr = &cursorObjType; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL; } /* @@ -367,11 +791,11 @@ Tk_FreeCursor(display, cursor) */ static void -CursorInit() +CursorInit(dispPtr) + TkDisplay *dispPtr; /* Display used to store thread-specific data. */ { - initialized = 1; - Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int)); - Tcl_InitHashTable(&dataTable, sizeof(DataKey)/sizeof(int)); + Tcl_InitHashTable(&dispPtr->cursorNameTable, TCL_STRING_KEYS); + Tcl_InitHashTable(&dispPtr->cursorDataTable, sizeof(DataKey)/sizeof(int)); /* * The call below is tricky: can't use sizeof(IdKey) because it @@ -379,6 +803,68 @@ CursorInit() * machines. */ - Tcl_InitHashTable(&idTable, (sizeof(Display *) + sizeof(Tk_Cursor)) - /sizeof(int)); + /* + * Old code.... + * Tcl_InitHashTable(&dispPtr->cursorIdTable, sizeof(Display *) + * /sizeof(int)); + * + * The comment above doesn't make sense. + * However, XIDs should only be 32 bits, by the definition of X, + * so the code above causes Tk to crash. Here is the real code: + */ + + Tcl_InitHashTable(&dispPtr->cursorIdTable, TCL_ONE_WORD_KEYS); + + dispPtr->cursorInit = 1; +} + +/* + *---------------------------------------------------------------------- + * + * TkDebugCursor -- + * + * This procedure returns debugging information about a cursor. + * + * Results: + * The return value is a list with one sublist for each TkCursor + * corresponding to "name". Each sublist has two elements that + * contain the resourceRefCount and objRefCount fields from the + * TkCursor structure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_Obj * +TkDebugCursor(tkwin, name) + Tk_Window tkwin; /* The window in which the cursor will be + * used (not currently used). */ + char *name; /* Name of the desired color. */ +{ + TkCursor *cursorPtr; + Tcl_HashEntry *hashPtr; + Tcl_Obj *resultPtr, *objPtr; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + + resultPtr = Tcl_NewObj(); + hashPtr = Tcl_FindHashEntry(&dispPtr->cursorNameTable, name); + if (hashPtr != NULL) { + cursorPtr = (TkCursor *) Tcl_GetHashValue(hashPtr); + if (cursorPtr == NULL) { + panic("TkDebugCursor found empty hash table entry"); + } + for ( ; (cursorPtr != NULL); cursorPtr = cursorPtr->nextPtr) { + objPtr = Tcl_NewObj(); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewIntObj(cursorPtr->resourceRefCount)); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewIntObj(cursorPtr->objRefCount)); + Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); + } + } + return resultPtr; } + + diff --git a/tk/generic/tkDecls.h b/tk/generic/tkDecls.h new file mode 100644 index 00000000000..c60345ad2f7 --- /dev/null +++ b/tk/generic/tkDecls.h @@ -0,0 +1,2050 @@ +/* + * tkDecls.h -- + * + * Declarations of functions in the platform independent public Tcl API. + * + * Copyright (c) 1998-1999 by Scriptics Corporation. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +#ifndef _TKDECLS +#define _TKDECLS + +#ifdef BUILD_tk +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLEXPORT +#endif + +/* + * WARNING: This file is automatically generated by the tools/genStubs.tcl + * script. Any modifications to the function declarations below should be made + * in the generic/tk.decls script. + */ + +/* !BEGIN!: Do not edit below this line. */ + +/* + * Exported function declarations: + */ + +/* 0 */ +EXTERN void Tk_MainLoop _ANSI_ARGS_((void)); +/* 1 */ +EXTERN XColor * Tk_3DBorderColor _ANSI_ARGS_((Tk_3DBorder border)); +/* 2 */ +EXTERN GC Tk_3DBorderGC _ANSI_ARGS_((Tk_Window tkwin, + Tk_3DBorder border, int which)); +/* 3 */ +EXTERN void Tk_3DHorizontalBevel _ANSI_ARGS_((Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, int x, + int y, int width, int height, int leftIn, + int rightIn, int topBevel, int relief)); +/* 4 */ +EXTERN void Tk_3DVerticalBevel _ANSI_ARGS_((Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, int x, + int y, int width, int height, int leftBevel, + int relief)); +/* 5 */ +EXTERN void Tk_AddOption _ANSI_ARGS_((Tk_Window tkwin, + char * name, char * value, int priority)); +/* 6 */ +EXTERN void Tk_BindEvent _ANSI_ARGS_(( + Tk_BindingTable bindingTable, + XEvent * eventPtr, Tk_Window tkwin, + int numObjects, ClientData * objectPtr)); +/* 7 */ +EXTERN void Tk_CanvasDrawableCoords _ANSI_ARGS_(( + Tk_Canvas canvas, double x, double y, + short * drawableXPtr, short * drawableYPtr)); +/* 8 */ +EXTERN void Tk_CanvasEventuallyRedraw _ANSI_ARGS_(( + Tk_Canvas canvas, int x1, int y1, int x2, + int y2)); +/* 9 */ +EXTERN int Tk_CanvasGetCoord _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Canvas canvas, char * str, + double * doublePtr)); +/* 10 */ +EXTERN Tk_CanvasTextInfo * Tk_CanvasGetTextInfo _ANSI_ARGS_(( + Tk_Canvas canvas)); +/* 11 */ +EXTERN int Tk_CanvasPsBitmap _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Canvas canvas, Pixmap bitmap, int x, + int y, int width, int height)); +/* 12 */ +EXTERN int Tk_CanvasPsColor _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Canvas canvas, XColor * colorPtr)); +/* 13 */ +EXTERN int Tk_CanvasPsFont _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Canvas canvas, Tk_Font font)); +/* 14 */ +EXTERN void Tk_CanvasPsPath _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Canvas canvas, double * coordPtr, + int numPoints)); +/* 15 */ +EXTERN int Tk_CanvasPsStipple _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Canvas canvas, Pixmap bitmap)); +/* 16 */ +EXTERN double Tk_CanvasPsY _ANSI_ARGS_((Tk_Canvas canvas, double y)); +/* 17 */ +EXTERN void Tk_CanvasSetStippleOrigin _ANSI_ARGS_(( + Tk_Canvas canvas, GC gc)); +/* 18 */ +EXTERN int Tk_CanvasTagsParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp * interp, + Tk_Window tkwin, char * value, + char * widgRec, int offset)); +/* 19 */ +EXTERN char * Tk_CanvasTagsPrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char * widgRec, int offset, + Tcl_FreeProc ** freeProcPtr)); +/* 20 */ +EXTERN Tk_Window Tk_CanvasTkwin _ANSI_ARGS_((Tk_Canvas canvas)); +/* 21 */ +EXTERN void Tk_CanvasWindowCoords _ANSI_ARGS_((Tk_Canvas canvas, + double x, double y, short * screenXPtr, + short * screenYPtr)); +/* 22 */ +EXTERN void Tk_ChangeWindowAttributes _ANSI_ARGS_(( + Tk_Window tkwin, unsigned long valueMask, + XSetWindowAttributes * attsPtr)); +/* 23 */ +EXTERN int Tk_CharBbox _ANSI_ARGS_((Tk_TextLayout layout, + int index, int * xPtr, int * yPtr, + int * widthPtr, int * heightPtr)); +/* 24 */ +EXTERN void Tk_ClearSelection _ANSI_ARGS_((Tk_Window tkwin, + Atom selection)); +/* 25 */ +EXTERN int Tk_ClipboardAppend _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Atom target, Atom format, + char* buffer)); +/* 26 */ +EXTERN int Tk_ClipboardClear _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin)); +/* 27 */ +EXTERN int Tk_ConfigureInfo _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tk_ConfigSpec * specs, + char * widgRec, char * argvName, int flags)); +/* 28 */ +EXTERN int Tk_ConfigureValue _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tk_ConfigSpec * specs, + char * widgRec, char * argvName, int flags)); +/* 29 */ +EXTERN int Tk_ConfigureWidget _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tk_ConfigSpec * specs, + int argc, char ** argv, char * widgRec, + int flags)); +/* 30 */ +EXTERN void Tk_ConfigureWindow _ANSI_ARGS_((Tk_Window tkwin, + unsigned int valueMask, + XWindowChanges * valuePtr)); +/* 31 */ +EXTERN Tk_TextLayout Tk_ComputeTextLayout _ANSI_ARGS_((Tk_Font font, + CONST char * str, int numChars, + int wrapLength, Tk_Justify justify, + int flags, int * widthPtr, int * heightPtr)); +/* 32 */ +EXTERN Tk_Window Tk_CoordsToWindow _ANSI_ARGS_((int rootX, int rootY, + Tk_Window tkwin)); +/* 33 */ +EXTERN unsigned long Tk_CreateBinding _ANSI_ARGS_((Tcl_Interp * interp, + Tk_BindingTable bindingTable, + ClientData object, char * eventStr, + char * command, int append)); +/* 34 */ +EXTERN Tk_BindingTable Tk_CreateBindingTable _ANSI_ARGS_(( + Tcl_Interp * interp)); +/* 35 */ +EXTERN Tk_ErrorHandler Tk_CreateErrorHandler _ANSI_ARGS_((Display * display, + int errNum, int request, int minorCode, + Tk_ErrorProc * errorProc, + ClientData clientData)); +/* 36 */ +EXTERN void Tk_CreateEventHandler _ANSI_ARGS_((Tk_Window token, + unsigned long mask, Tk_EventProc * proc, + ClientData clientData)); +/* 37 */ +EXTERN void Tk_CreateGenericHandler _ANSI_ARGS_(( + Tk_GenericProc * proc, ClientData clientData)); +/* 38 */ +EXTERN void Tk_CreateImageType _ANSI_ARGS_(( + Tk_ImageType * typePtr)); +/* 39 */ +EXTERN void Tk_CreateItemType _ANSI_ARGS_((Tk_ItemType * typePtr)); +/* 40 */ +EXTERN void Tk_CreatePhotoImageFormat _ANSI_ARGS_(( + Tk_PhotoImageFormat * formatPtr)); +/* 41 */ +EXTERN void Tk_CreateSelHandler _ANSI_ARGS_((Tk_Window tkwin, + Atom selection, Atom target, + Tk_SelectionProc * proc, + ClientData clientData, Atom format)); +/* 42 */ +EXTERN Tk_Window Tk_CreateWindow _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window parent, char * name, + char * screenName)); +/* 43 */ +EXTERN Tk_Window Tk_CreateWindowFromPath _ANSI_ARGS_(( + Tcl_Interp * interp, Tk_Window tkwin, + char * pathName, char * screenName)); +/* 44 */ +EXTERN int Tk_DefineBitmap _ANSI_ARGS_((Tcl_Interp * interp, + CONST char * name, char * source, int width, + int height)); +/* 45 */ +EXTERN void Tk_DefineCursor _ANSI_ARGS_((Tk_Window window, + Tk_Cursor cursor)); +/* 46 */ +EXTERN void Tk_DeleteAllBindings _ANSI_ARGS_(( + Tk_BindingTable bindingTable, + ClientData object)); +/* 47 */ +EXTERN int Tk_DeleteBinding _ANSI_ARGS_((Tcl_Interp * interp, + Tk_BindingTable bindingTable, + ClientData object, char * eventStr)); +/* 48 */ +EXTERN void Tk_DeleteBindingTable _ANSI_ARGS_(( + Tk_BindingTable bindingTable)); +/* 49 */ +EXTERN void Tk_DeleteErrorHandler _ANSI_ARGS_(( + Tk_ErrorHandler handler)); +/* 50 */ +EXTERN void Tk_DeleteEventHandler _ANSI_ARGS_((Tk_Window token, + unsigned long mask, Tk_EventProc * proc, + ClientData clientData)); +/* 51 */ +EXTERN void Tk_DeleteGenericHandler _ANSI_ARGS_(( + Tk_GenericProc * proc, ClientData clientData)); +/* 52 */ +EXTERN void Tk_DeleteImage _ANSI_ARGS_((Tcl_Interp * interp, + char * name)); +/* 53 */ +EXTERN void Tk_DeleteSelHandler _ANSI_ARGS_((Tk_Window tkwin, + Atom selection, Atom target)); +/* 54 */ +EXTERN void Tk_DestroyWindow _ANSI_ARGS_((Tk_Window tkwin)); +/* 55 */ +EXTERN char * Tk_DisplayName _ANSI_ARGS_((Tk_Window tkwin)); +/* 56 */ +EXTERN int Tk_DistanceToTextLayout _ANSI_ARGS_(( + Tk_TextLayout layout, int x, int y)); +/* 57 */ +EXTERN void Tk_Draw3DPolygon _ANSI_ARGS_((Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, + XPoint * pointPtr, int numPoints, + int borderWidth, int leftRelief)); +/* 58 */ +EXTERN void Tk_Draw3DRectangle _ANSI_ARGS_((Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, int x, + int y, int width, int height, + int borderWidth, int relief)); +/* 59 */ +EXTERN void Tk_DrawChars _ANSI_ARGS_((Display * display, + Drawable drawable, GC gc, Tk_Font tkfont, + CONST char * source, int numBytes, int x, + int y)); +/* 60 */ +EXTERN void Tk_DrawFocusHighlight _ANSI_ARGS_((Tk_Window tkwin, + GC gc, int width, Drawable drawable)); +/* 61 */ +EXTERN void Tk_DrawTextLayout _ANSI_ARGS_((Display * display, + Drawable drawable, GC gc, + Tk_TextLayout layout, int x, int y, + int firstChar, int lastChar)); +/* 62 */ +EXTERN void Tk_Fill3DPolygon _ANSI_ARGS_((Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, + XPoint * pointPtr, int numPoints, + int borderWidth, int leftRelief)); +/* 63 */ +EXTERN void Tk_Fill3DRectangle _ANSI_ARGS_((Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, int x, + int y, int width, int height, + int borderWidth, int relief)); +/* 64 */ +EXTERN Tk_PhotoHandle Tk_FindPhoto _ANSI_ARGS_((Tcl_Interp * interp, + char * imageName)); +/* 65 */ +EXTERN Font Tk_FontId _ANSI_ARGS_((Tk_Font font)); +/* 66 */ +EXTERN void Tk_Free3DBorder _ANSI_ARGS_((Tk_3DBorder border)); +/* 67 */ +EXTERN void Tk_FreeBitmap _ANSI_ARGS_((Display * display, + Pixmap bitmap)); +/* 68 */ +EXTERN void Tk_FreeColor _ANSI_ARGS_((XColor * colorPtr)); +/* 69 */ +EXTERN void Tk_FreeColormap _ANSI_ARGS_((Display * display, + Colormap colormap)); +/* 70 */ +EXTERN void Tk_FreeCursor _ANSI_ARGS_((Display * display, + Tk_Cursor cursor)); +/* 71 */ +EXTERN void Tk_FreeFont _ANSI_ARGS_((Tk_Font f)); +/* 72 */ +EXTERN void Tk_FreeGC _ANSI_ARGS_((Display * display, GC gc)); +/* 73 */ +EXTERN void Tk_FreeImage _ANSI_ARGS_((Tk_Image image)); +/* 74 */ +EXTERN void Tk_FreeOptions _ANSI_ARGS_((Tk_ConfigSpec * specs, + char * widgRec, Display * display, + int needFlags)); +/* 75 */ +EXTERN void Tk_FreePixmap _ANSI_ARGS_((Display * display, + Pixmap pixmap)); +/* 76 */ +EXTERN void Tk_FreeTextLayout _ANSI_ARGS_(( + Tk_TextLayout textLayout)); +/* 77 */ +EXTERN void Tk_FreeXId _ANSI_ARGS_((Display * display, XID xid)); +/* 78 */ +EXTERN GC Tk_GCForColor _ANSI_ARGS_((XColor * colorPtr, + Drawable drawable)); +/* 79 */ +EXTERN void Tk_GeometryRequest _ANSI_ARGS_((Tk_Window tkwin, + int reqWidth, int reqHeight)); +/* 80 */ +EXTERN Tk_3DBorder Tk_Get3DBorder _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tk_Uid colorName)); +/* 81 */ +EXTERN void Tk_GetAllBindings _ANSI_ARGS_((Tcl_Interp * interp, + Tk_BindingTable bindingTable, + ClientData object)); +/* 82 */ +EXTERN int Tk_GetAnchor _ANSI_ARGS_((Tcl_Interp * interp, + char * str, Tk_Anchor * anchorPtr)); +/* 83 */ +EXTERN char * Tk_GetAtomName _ANSI_ARGS_((Tk_Window tkwin, + Atom atom)); +/* 84 */ +EXTERN char * Tk_GetBinding _ANSI_ARGS_((Tcl_Interp * interp, + Tk_BindingTable bindingTable, + ClientData object, char * eventStr)); +/* 85 */ +EXTERN Pixmap Tk_GetBitmap _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, CONST char * str)); +/* 86 */ +EXTERN Pixmap Tk_GetBitmapFromData _ANSI_ARGS_(( + Tcl_Interp * interp, Tk_Window tkwin, + char * source, int width, int height)); +/* 87 */ +EXTERN int Tk_GetCapStyle _ANSI_ARGS_((Tcl_Interp * interp, + char * str, int * capPtr)); +/* 88 */ +EXTERN XColor * Tk_GetColor _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tk_Uid name)); +/* 89 */ +EXTERN XColor * Tk_GetColorByValue _ANSI_ARGS_((Tk_Window tkwin, + XColor * colorPtr)); +/* 90 */ +EXTERN Colormap Tk_GetColormap _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, char * str)); +/* 91 */ +EXTERN Tk_Cursor Tk_GetCursor _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tk_Uid str)); +/* 92 */ +EXTERN Tk_Cursor Tk_GetCursorFromData _ANSI_ARGS_(( + Tcl_Interp * interp, Tk_Window tkwin, + char * source, char * mask, int width, + int height, int xHot, int yHot, Tk_Uid fg, + Tk_Uid bg)); +/* 93 */ +EXTERN Tk_Font Tk_GetFont _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, CONST char * str)); +/* 94 */ +EXTERN Tk_Font Tk_GetFontFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 95 */ +EXTERN void Tk_GetFontMetrics _ANSI_ARGS_((Tk_Font font, + Tk_FontMetrics * fmPtr)); +/* 96 */ +EXTERN GC Tk_GetGC _ANSI_ARGS_((Tk_Window tkwin, + unsigned long valueMask, + XGCValues * valuePtr)); +/* 97 */ +EXTERN Tk_Image Tk_GetImage _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, char * name, + Tk_ImageChangedProc * changeProc, + ClientData clientData)); +/* 98 */ +EXTERN ClientData Tk_GetImageMasterData _ANSI_ARGS_(( + Tcl_Interp * interp, char * name, + Tk_ImageType ** typePtrPtr)); +/* 99 */ +EXTERN Tk_ItemType * Tk_GetItemTypes _ANSI_ARGS_((void)); +/* 100 */ +EXTERN int Tk_GetJoinStyle _ANSI_ARGS_((Tcl_Interp * interp, + char * str, int * joinPtr)); +/* 101 */ +EXTERN int Tk_GetJustify _ANSI_ARGS_((Tcl_Interp * interp, + char * str, Tk_Justify * justifyPtr)); +/* 102 */ +EXTERN int Tk_GetNumMainWindows _ANSI_ARGS_((void)); +/* 103 */ +EXTERN Tk_Uid Tk_GetOption _ANSI_ARGS_((Tk_Window tkwin, + char * name, char * className)); +/* 104 */ +EXTERN int Tk_GetPixels _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, char * str, int * intPtr)); +/* 105 */ +EXTERN Pixmap Tk_GetPixmap _ANSI_ARGS_((Display * display, + Drawable d, int width, int height, int depth)); +/* 106 */ +EXTERN int Tk_GetRelief _ANSI_ARGS_((Tcl_Interp * interp, + char * name, int * reliefPtr)); +/* 107 */ +EXTERN void Tk_GetRootCoords _ANSI_ARGS_((Tk_Window tkwin, + int * xPtr, int * yPtr)); +/* 108 */ +EXTERN int Tk_GetScrollInfo _ANSI_ARGS_((Tcl_Interp * interp, + int argc, char ** argv, double * dblPtr, + int * intPtr)); +/* 109 */ +EXTERN int Tk_GetScreenMM _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, char * str, + double * doublePtr)); +/* 110 */ +EXTERN int Tk_GetSelection _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Atom selection, Atom target, + Tk_GetSelProc * proc, ClientData clientData)); +/* 111 */ +EXTERN Tk_Uid Tk_GetUid _ANSI_ARGS_((CONST char * str)); +/* 112 */ +EXTERN Visual * Tk_GetVisual _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, char * str, int * depthPtr, + Colormap * colormapPtr)); +/* 113 */ +EXTERN void Tk_GetVRootGeometry _ANSI_ARGS_((Tk_Window tkwin, + int * xPtr, int * yPtr, int * widthPtr, + int * heightPtr)); +/* 114 */ +EXTERN int Tk_Grab _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, int grabGlobal)); +/* 115 */ +EXTERN void Tk_HandleEvent _ANSI_ARGS_((XEvent * eventPtr)); +/* 116 */ +EXTERN Tk_Window Tk_IdToWindow _ANSI_ARGS_((Display * display, + Window window)); +/* 117 */ +EXTERN void Tk_ImageChanged _ANSI_ARGS_((Tk_ImageMaster master, + int x, int y, int width, int height, + int imageWidth, int imageHeight)); +/* 118 */ +EXTERN int Tk_Init _ANSI_ARGS_((Tcl_Interp * interp)); +/* 119 */ +EXTERN Atom Tk_InternAtom _ANSI_ARGS_((Tk_Window tkwin, + char * name)); +/* 120 */ +EXTERN int Tk_IntersectTextLayout _ANSI_ARGS_(( + Tk_TextLayout layout, int x, int y, + int width, int height)); +/* 121 */ +EXTERN void Tk_MaintainGeometry _ANSI_ARGS_((Tk_Window slave, + Tk_Window master, int x, int y, int width, + int height)); +/* 122 */ +EXTERN Tk_Window Tk_MainWindow _ANSI_ARGS_((Tcl_Interp * interp)); +/* 123 */ +EXTERN void Tk_MakeWindowExist _ANSI_ARGS_((Tk_Window tkwin)); +/* 124 */ +EXTERN void Tk_ManageGeometry _ANSI_ARGS_((Tk_Window tkwin, + Tk_GeomMgr * mgrPtr, ClientData clientData)); +/* 125 */ +EXTERN void Tk_MapWindow _ANSI_ARGS_((Tk_Window tkwin)); +/* 126 */ +EXTERN int Tk_MeasureChars _ANSI_ARGS_((Tk_Font tkfont, + CONST char * source, int numBytes, + int maxPixels, int flags, int * lengthPtr)); +/* 127 */ +EXTERN void Tk_MoveResizeWindow _ANSI_ARGS_((Tk_Window tkwin, + int x, int y, int width, int height)); +/* 128 */ +EXTERN void Tk_MoveWindow _ANSI_ARGS_((Tk_Window tkwin, int x, + int y)); +/* 129 */ +EXTERN void Tk_MoveToplevelWindow _ANSI_ARGS_((Tk_Window tkwin, + int x, int y)); +/* 130 */ +EXTERN char * Tk_NameOf3DBorder _ANSI_ARGS_((Tk_3DBorder border)); +/* 131 */ +EXTERN char * Tk_NameOfAnchor _ANSI_ARGS_((Tk_Anchor anchor)); +/* 132 */ +EXTERN char * Tk_NameOfBitmap _ANSI_ARGS_((Display * display, + Pixmap bitmap)); +/* 133 */ +EXTERN char * Tk_NameOfCapStyle _ANSI_ARGS_((int cap)); +/* 134 */ +EXTERN char * Tk_NameOfColor _ANSI_ARGS_((XColor * colorPtr)); +/* 135 */ +EXTERN char * Tk_NameOfCursor _ANSI_ARGS_((Display * display, + Tk_Cursor cursor)); +/* 136 */ +EXTERN char * Tk_NameOfFont _ANSI_ARGS_((Tk_Font font)); +/* 137 */ +EXTERN char * Tk_NameOfImage _ANSI_ARGS_(( + Tk_ImageMaster imageMaster)); +/* 138 */ +EXTERN char * Tk_NameOfJoinStyle _ANSI_ARGS_((int join)); +/* 139 */ +EXTERN char * Tk_NameOfJustify _ANSI_ARGS_((Tk_Justify justify)); +/* 140 */ +EXTERN char * Tk_NameOfRelief _ANSI_ARGS_((int relief)); +/* 141 */ +EXTERN Tk_Window Tk_NameToWindow _ANSI_ARGS_((Tcl_Interp * interp, + char * pathName, Tk_Window tkwin)); +/* 142 */ +EXTERN void Tk_OwnSelection _ANSI_ARGS_((Tk_Window tkwin, + Atom selection, Tk_LostSelProc * proc, + ClientData clientData)); +/* 143 */ +EXTERN int Tk_ParseArgv _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, int * argcPtr, char ** argv, + Tk_ArgvInfo * argTable, int flags)); +/* 144 */ +EXTERN void Tk_PhotoPutBlock _ANSI_ARGS_((Tk_PhotoHandle handle, + Tk_PhotoImageBlock * blockPtr, int x, int y, + int width, int height)); +/* 145 */ +EXTERN void Tk_PhotoPutZoomedBlock _ANSI_ARGS_(( + Tk_PhotoHandle handle, + Tk_PhotoImageBlock * blockPtr, int x, int y, + int width, int height, int zoomX, int zoomY, + int subsampleX, int subsampleY)); +/* 146 */ +EXTERN int Tk_PhotoGetImage _ANSI_ARGS_((Tk_PhotoHandle handle, + Tk_PhotoImageBlock * blockPtr)); +/* 147 */ +EXTERN void Tk_PhotoBlank _ANSI_ARGS_((Tk_PhotoHandle handle)); +/* 148 */ +EXTERN void Tk_PhotoExpand _ANSI_ARGS_((Tk_PhotoHandle handle, + int width, int height)); +/* 149 */ +EXTERN void Tk_PhotoGetSize _ANSI_ARGS_((Tk_PhotoHandle handle, + int * widthPtr, int * heightPtr)); +/* 150 */ +EXTERN void Tk_PhotoSetSize _ANSI_ARGS_((Tk_PhotoHandle handle, + int width, int height)); +/* 151 */ +EXTERN int Tk_PointToChar _ANSI_ARGS_((Tk_TextLayout layout, + int x, int y)); +/* 152 */ +EXTERN int Tk_PostscriptFontName _ANSI_ARGS_((Tk_Font tkfont, + Tcl_DString * dsPtr)); +/* 153 */ +EXTERN void Tk_PreserveColormap _ANSI_ARGS_((Display * display, + Colormap colormap)); +/* 154 */ +EXTERN void Tk_QueueWindowEvent _ANSI_ARGS_((XEvent * eventPtr, + Tcl_QueuePosition position)); +/* 155 */ +EXTERN void Tk_RedrawImage _ANSI_ARGS_((Tk_Image image, + int imageX, int imageY, int width, + int height, Drawable drawable, int drawableX, + int drawableY)); +/* 156 */ +EXTERN void Tk_ResizeWindow _ANSI_ARGS_((Tk_Window tkwin, + int width, int height)); +/* 157 */ +EXTERN int Tk_RestackWindow _ANSI_ARGS_((Tk_Window tkwin, + int aboveBelow, Tk_Window other)); +/* 158 */ +EXTERN Tk_RestrictProc * Tk_RestrictEvents _ANSI_ARGS_(( + Tk_RestrictProc * proc, ClientData arg, + ClientData * prevArgPtr)); +/* 159 */ +EXTERN int Tk_SafeInit _ANSI_ARGS_((Tcl_Interp * interp)); +/* 160 */ +EXTERN char * Tk_SetAppName _ANSI_ARGS_((Tk_Window tkwin, + char * name)); +/* 161 */ +EXTERN void Tk_SetBackgroundFromBorder _ANSI_ARGS_(( + Tk_Window tkwin, Tk_3DBorder border)); +/* 162 */ +EXTERN void Tk_SetClass _ANSI_ARGS_((Tk_Window tkwin, + char * className)); +/* 163 */ +EXTERN void Tk_SetGrid _ANSI_ARGS_((Tk_Window tkwin, + int reqWidth, int reqHeight, int gridWidth, + int gridHeight)); +/* 164 */ +EXTERN void Tk_SetInternalBorder _ANSI_ARGS_((Tk_Window tkwin, + int width)); +/* 165 */ +EXTERN void Tk_SetWindowBackground _ANSI_ARGS_((Tk_Window tkwin, + unsigned long pixel)); +/* 166 */ +EXTERN void Tk_SetWindowBackgroundPixmap _ANSI_ARGS_(( + Tk_Window tkwin, Pixmap pixmap)); +/* 167 */ +EXTERN void Tk_SetWindowBorder _ANSI_ARGS_((Tk_Window tkwin, + unsigned long pixel)); +/* 168 */ +EXTERN void Tk_SetWindowBorderWidth _ANSI_ARGS_((Tk_Window tkwin, + int width)); +/* 169 */ +EXTERN void Tk_SetWindowBorderPixmap _ANSI_ARGS_(( + Tk_Window tkwin, Pixmap pixmap)); +/* 170 */ +EXTERN void Tk_SetWindowColormap _ANSI_ARGS_((Tk_Window tkwin, + Colormap colormap)); +/* 171 */ +EXTERN int Tk_SetWindowVisual _ANSI_ARGS_((Tk_Window tkwin, + Visual * visual, int depth, + Colormap colormap)); +/* 172 */ +EXTERN void Tk_SizeOfBitmap _ANSI_ARGS_((Display * display, + Pixmap bitmap, int * widthPtr, + int * heightPtr)); +/* 173 */ +EXTERN void Tk_SizeOfImage _ANSI_ARGS_((Tk_Image image, + int * widthPtr, int * heightPtr)); +/* 174 */ +EXTERN int Tk_StrictMotif _ANSI_ARGS_((Tk_Window tkwin)); +/* 175 */ +EXTERN void Tk_TextLayoutToPostscript _ANSI_ARGS_(( + Tcl_Interp * interp, Tk_TextLayout layout)); +/* 176 */ +EXTERN int Tk_TextWidth _ANSI_ARGS_((Tk_Font font, + CONST char * str, int numBytes)); +/* 177 */ +EXTERN void Tk_UndefineCursor _ANSI_ARGS_((Tk_Window window)); +/* 178 */ +EXTERN void Tk_UnderlineChars _ANSI_ARGS_((Display * display, + Drawable drawable, GC gc, Tk_Font tkfont, + CONST char * source, int x, int y, + int firstByte, int lastByte)); +/* 179 */ +EXTERN void Tk_UnderlineTextLayout _ANSI_ARGS_(( + Display * display, Drawable drawable, GC gc, + Tk_TextLayout layout, int x, int y, + int underline)); +/* 180 */ +EXTERN void Tk_Ungrab _ANSI_ARGS_((Tk_Window tkwin)); +/* 181 */ +EXTERN void Tk_UnmaintainGeometry _ANSI_ARGS_((Tk_Window slave, + Tk_Window master)); +/* 182 */ +EXTERN void Tk_UnmapWindow _ANSI_ARGS_((Tk_Window tkwin)); +/* 183 */ +EXTERN void Tk_UnsetGrid _ANSI_ARGS_((Tk_Window tkwin)); +/* 184 */ +EXTERN void Tk_UpdatePointer _ANSI_ARGS_((Tk_Window tkwin, int x, + int y, int state)); +/* 185 */ +EXTERN Pixmap Tk_AllocBitmapFromObj _ANSI_ARGS_(( + Tcl_Interp * interp, Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 186 */ +EXTERN Tk_3DBorder Tk_Alloc3DBorderFromObj _ANSI_ARGS_(( + Tcl_Interp * interp, Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 187 */ +EXTERN XColor * Tk_AllocColorFromObj _ANSI_ARGS_(( + Tcl_Interp * interp, Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 188 */ +EXTERN Tk_Cursor Tk_AllocCursorFromObj _ANSI_ARGS_(( + Tcl_Interp * interp, Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 189 */ +EXTERN Tk_Font Tk_AllocFontFromObj _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tcl_Obj * objPtr)); +/* 190 */ +EXTERN Tk_OptionTable Tk_CreateOptionTable _ANSI_ARGS_(( + Tcl_Interp * interp, + CONST Tk_OptionSpec * templatePtr)); +/* 191 */ +EXTERN void Tk_DeleteOptionTable _ANSI_ARGS_(( + Tk_OptionTable optionTable)); +/* 192 */ +EXTERN void Tk_Free3DBorderFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 193 */ +EXTERN void Tk_FreeBitmapFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 194 */ +EXTERN void Tk_FreeColorFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 195 */ +EXTERN void Tk_FreeConfigOptions _ANSI_ARGS_((char * recordPtr, + Tk_OptionTable optionToken, Tk_Window tkwin)); +/* 196 */ +EXTERN void Tk_FreeSavedOptions _ANSI_ARGS_(( + Tk_SavedOptions * savePtr)); +/* 197 */ +EXTERN void Tk_FreeCursorFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 198 */ +EXTERN void Tk_FreeFontFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 199 */ +EXTERN Tk_3DBorder Tk_Get3DBorderFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 200 */ +EXTERN int Tk_GetAnchorFromObj _ANSI_ARGS_((Tcl_Interp * interp, + Tcl_Obj * objPtr, Tk_Anchor * anchorPtr)); +/* 201 */ +EXTERN Pixmap Tk_GetBitmapFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 202 */ +EXTERN XColor * Tk_GetColorFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 203 */ +EXTERN Tk_Cursor Tk_GetCursorFromObj _ANSI_ARGS_((Tk_Window tkwin, + Tcl_Obj * objPtr)); +/* 204 */ +EXTERN Tcl_Obj * Tk_GetOptionInfo _ANSI_ARGS_((Tcl_Interp * interp, + char * recordPtr, Tk_OptionTable optionTable, + Tcl_Obj * namePtr, Tk_Window tkwin)); +/* 205 */ +EXTERN Tcl_Obj * Tk_GetOptionValue _ANSI_ARGS_((Tcl_Interp * interp, + char * recordPtr, Tk_OptionTable optionTable, + Tcl_Obj * namePtr, Tk_Window tkwin)); +/* 206 */ +EXTERN int Tk_GetJustifyFromObj _ANSI_ARGS_(( + Tcl_Interp * interp, Tcl_Obj * objPtr, + Tk_Justify * justifyPtr)); +/* 207 */ +EXTERN int Tk_GetMMFromObj _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tcl_Obj * objPtr, + double * doublePtr)); +/* 208 */ +EXTERN int Tk_GetPixelsFromObj _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tcl_Obj * objPtr, + int * intPtr)); +/* 209 */ +EXTERN int Tk_GetReliefFromObj _ANSI_ARGS_((Tcl_Interp * interp, + Tcl_Obj * objPtr, int * resultPtr)); +/* 210 */ +EXTERN int Tk_GetScrollInfoObj _ANSI_ARGS_((Tcl_Interp * interp, + int objc, Tcl_Obj *CONST objv[], + double * dblPtr, int * intPtr)); +/* 211 */ +EXTERN int Tk_InitOptions _ANSI_ARGS_((Tcl_Interp * interp, + char * recordPtr, Tk_OptionTable optionToken, + Tk_Window tkwin)); +/* 212 */ +EXTERN void Tk_MainEx _ANSI_ARGS_((int argc, char ** argv, + Tcl_AppInitProc * appInitProc, + Tcl_Interp * interp)); +/* 213 */ +EXTERN void Tk_RestoreSavedOptions _ANSI_ARGS_(( + Tk_SavedOptions * savePtr)); +/* 214 */ +EXTERN int Tk_SetOptions _ANSI_ARGS_((Tcl_Interp * interp, + char * recordPtr, Tk_OptionTable optionTable, + int objc, Tcl_Obj *CONST objv[], + Tk_Window tkwin, Tk_SavedOptions * savePtr, + int * maskPtr)); +/* 215 */ +EXTERN void Tk_InitConsoleChannels _ANSI_ARGS_(( + Tcl_Interp * interp)); +/* 216 */ +EXTERN int Tk_CreateConsoleWindow _ANSI_ARGS_(( + Tcl_Interp * interp)); +/* 217 */ +EXTERN void Tk_CreateSmoothMethod _ANSI_ARGS_(( + Tcl_Interp * interp, + Tk_SmoothMethod * method)); +/* Slot 218 is reserved */ +/* Slot 219 is reserved */ +/* 220 */ +EXTERN int Tk_GetDash _ANSI_ARGS_((Tcl_Interp * interp, + CONST char * value, Tk_Dash * dash)); +/* 221 */ +EXTERN void Tk_CreateOutline _ANSI_ARGS_((Tk_Outline * outline)); +/* 222 */ +EXTERN void Tk_DeleteOutline _ANSI_ARGS_((Display * display, + Tk_Outline * outline)); +/* 223 */ +EXTERN int Tk_ConfigOutlineGC _ANSI_ARGS_((XGCValues * gcValues, + Tk_Canvas canvas, Tk_Item * item, + Tk_Outline * outline)); +/* 224 */ +EXTERN int Tk_ChangeOutlineGC _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item * item, Tk_Outline * outline)); +/* 225 */ +EXTERN int Tk_ResetOutlineGC _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item * item, Tk_Outline * outline)); +/* 226 */ +EXTERN int Tk_CanvasPsOutline _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item * item, Tk_Outline * outline)); +/* 227 */ +EXTERN void Tk_SetTSOrigin _ANSI_ARGS_((Tk_Window tkwin, GC gc, + int x, int y)); +/* 228 */ +EXTERN int Tk_CanvasGetCoordFromObj _ANSI_ARGS_(( + Tcl_Interp * interp, Tk_Canvas canvas, + Tcl_Obj * obj, double * doublePtr)); +/* 229 */ +EXTERN void Tk_CanvasSetOffset _ANSI_ARGS_((Tk_Canvas canvas, + GC gc, Tk_TSOffset * offset)); +/* 230 */ +EXTERN void Tk_DitherPhoto _ANSI_ARGS_((Tk_PhotoHandle handle, + int x, int y, int width, int height)); +/* 231 */ +EXTERN int Tk_PostscriptBitmap _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tk_PostscriptInfo psInfo, + Pixmap bitmap, int startX, int startY, + int width, int height)); +/* 232 */ +EXTERN int Tk_PostscriptColor _ANSI_ARGS_((Tcl_Interp * interp, + Tk_PostscriptInfo psInfo, XColor * colorPtr)); +/* 233 */ +EXTERN int Tk_PostscriptFont _ANSI_ARGS_((Tcl_Interp * interp, + Tk_PostscriptInfo psInfo, Tk_Font font)); +/* 234 */ +EXTERN int Tk_PostscriptImage _ANSI_ARGS_((Tk_Image image, + Tcl_Interp * interp, Tk_Window tkwin, + Tk_PostscriptInfo psinfo, int x, int y, + int width, int height, int prepass)); +/* 235 */ +EXTERN void Tk_PostscriptPath _ANSI_ARGS_((Tcl_Interp * interp, + Tk_PostscriptInfo psInfo, double * coordPtr, + int numPoints)); +/* 236 */ +EXTERN int Tk_PostscriptStipple _ANSI_ARGS_(( + Tcl_Interp * interp, Tk_Window tkwin, + Tk_PostscriptInfo psInfo, Pixmap bitmap)); +/* 237 */ +EXTERN double Tk_PostscriptY _ANSI_ARGS_((double y, + Tk_PostscriptInfo psInfo)); +/* 238 */ +EXTERN int Tk_PostscriptPhoto _ANSI_ARGS_((Tcl_Interp * interp, + Tk_PhotoImageBlock * blockPtr, + Tk_PostscriptInfo psInfo, int width, + int height)); + +typedef struct TkStubHooks { + struct TkPlatStubs *tkPlatStubs; + struct TkIntStubs *tkIntStubs; + struct TkIntPlatStubs *tkIntPlatStubs; + struct TkIntXlibStubs *tkIntXlibStubs; +} TkStubHooks; + +typedef struct TkStubs { + int magic; + struct TkStubHooks *hooks; + + void (*tk_MainLoop) _ANSI_ARGS_((void)); /* 0 */ + XColor * (*tk_3DBorderColor) _ANSI_ARGS_((Tk_3DBorder border)); /* 1 */ + GC (*tk_3DBorderGC) _ANSI_ARGS_((Tk_Window tkwin, Tk_3DBorder border, int which)); /* 2 */ + void (*tk_3DHorizontalBevel) _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height, int leftIn, int rightIn, int topBevel, int relief)); /* 3 */ + void (*tk_3DVerticalBevel) _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height, int leftBevel, int relief)); /* 4 */ + void (*tk_AddOption) _ANSI_ARGS_((Tk_Window tkwin, char * name, char * value, int priority)); /* 5 */ + void (*tk_BindEvent) _ANSI_ARGS_((Tk_BindingTable bindingTable, XEvent * eventPtr, Tk_Window tkwin, int numObjects, ClientData * objectPtr)); /* 6 */ + void (*tk_CanvasDrawableCoords) _ANSI_ARGS_((Tk_Canvas canvas, double x, double y, short * drawableXPtr, short * drawableYPtr)); /* 7 */ + void (*tk_CanvasEventuallyRedraw) _ANSI_ARGS_((Tk_Canvas canvas, int x1, int y1, int x2, int y2)); /* 8 */ + int (*tk_CanvasGetCoord) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Canvas canvas, char * str, double * doublePtr)); /* 9 */ + Tk_CanvasTextInfo * (*tk_CanvasGetTextInfo) _ANSI_ARGS_((Tk_Canvas canvas)); /* 10 */ + int (*tk_CanvasPsBitmap) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Canvas canvas, Pixmap bitmap, int x, int y, int width, int height)); /* 11 */ + int (*tk_CanvasPsColor) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Canvas canvas, XColor * colorPtr)); /* 12 */ + int (*tk_CanvasPsFont) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Canvas canvas, Tk_Font font)); /* 13 */ + void (*tk_CanvasPsPath) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Canvas canvas, double * coordPtr, int numPoints)); /* 14 */ + int (*tk_CanvasPsStipple) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Canvas canvas, Pixmap bitmap)); /* 15 */ + double (*tk_CanvasPsY) _ANSI_ARGS_((Tk_Canvas canvas, double y)); /* 16 */ + void (*tk_CanvasSetStippleOrigin) _ANSI_ARGS_((Tk_Canvas canvas, GC gc)); /* 17 */ + int (*tk_CanvasTagsParseProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, Tk_Window tkwin, char * value, char * widgRec, int offset)); /* 18 */ + char * (*tk_CanvasTagsPrintProc) _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char * widgRec, int offset, Tcl_FreeProc ** freeProcPtr)); /* 19 */ + Tk_Window (*tk_CanvasTkwin) _ANSI_ARGS_((Tk_Canvas canvas)); /* 20 */ + void (*tk_CanvasWindowCoords) _ANSI_ARGS_((Tk_Canvas canvas, double x, double y, short * screenXPtr, short * screenYPtr)); /* 21 */ + void (*tk_ChangeWindowAttributes) _ANSI_ARGS_((Tk_Window tkwin, unsigned long valueMask, XSetWindowAttributes * attsPtr)); /* 22 */ + int (*tk_CharBbox) _ANSI_ARGS_((Tk_TextLayout layout, int index, int * xPtr, int * yPtr, int * widthPtr, int * heightPtr)); /* 23 */ + void (*tk_ClearSelection) _ANSI_ARGS_((Tk_Window tkwin, Atom selection)); /* 24 */ + int (*tk_ClipboardAppend) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Atom target, Atom format, char* buffer)); /* 25 */ + int (*tk_ClipboardClear) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin)); /* 26 */ + int (*tk_ConfigureInfo) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tk_ConfigSpec * specs, char * widgRec, char * argvName, int flags)); /* 27 */ + int (*tk_ConfigureValue) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tk_ConfigSpec * specs, char * widgRec, char * argvName, int flags)); /* 28 */ + int (*tk_ConfigureWidget) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tk_ConfigSpec * specs, int argc, char ** argv, char * widgRec, int flags)); /* 29 */ + void (*tk_ConfigureWindow) _ANSI_ARGS_((Tk_Window tkwin, unsigned int valueMask, XWindowChanges * valuePtr)); /* 30 */ + Tk_TextLayout (*tk_ComputeTextLayout) _ANSI_ARGS_((Tk_Font font, CONST char * str, int numChars, int wrapLength, Tk_Justify justify, int flags, int * widthPtr, int * heightPtr)); /* 31 */ + Tk_Window (*tk_CoordsToWindow) _ANSI_ARGS_((int rootX, int rootY, Tk_Window tkwin)); /* 32 */ + unsigned long (*tk_CreateBinding) _ANSI_ARGS_((Tcl_Interp * interp, Tk_BindingTable bindingTable, ClientData object, char * eventStr, char * command, int append)); /* 33 */ + Tk_BindingTable (*tk_CreateBindingTable) _ANSI_ARGS_((Tcl_Interp * interp)); /* 34 */ + Tk_ErrorHandler (*tk_CreateErrorHandler) _ANSI_ARGS_((Display * display, int errNum, int request, int minorCode, Tk_ErrorProc * errorProc, ClientData clientData)); /* 35 */ + void (*tk_CreateEventHandler) _ANSI_ARGS_((Tk_Window token, unsigned long mask, Tk_EventProc * proc, ClientData clientData)); /* 36 */ + void (*tk_CreateGenericHandler) _ANSI_ARGS_((Tk_GenericProc * proc, ClientData clientData)); /* 37 */ + void (*tk_CreateImageType) _ANSI_ARGS_((Tk_ImageType * typePtr)); /* 38 */ + void (*tk_CreateItemType) _ANSI_ARGS_((Tk_ItemType * typePtr)); /* 39 */ + void (*tk_CreatePhotoImageFormat) _ANSI_ARGS_((Tk_PhotoImageFormat * formatPtr)); /* 40 */ + void (*tk_CreateSelHandler) _ANSI_ARGS_((Tk_Window tkwin, Atom selection, Atom target, Tk_SelectionProc * proc, ClientData clientData, Atom format)); /* 41 */ + Tk_Window (*tk_CreateWindow) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window parent, char * name, char * screenName)); /* 42 */ + Tk_Window (*tk_CreateWindowFromPath) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * pathName, char * screenName)); /* 43 */ + int (*tk_DefineBitmap) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * name, char * source, int width, int height)); /* 44 */ + void (*tk_DefineCursor) _ANSI_ARGS_((Tk_Window window, Tk_Cursor cursor)); /* 45 */ + void (*tk_DeleteAllBindings) _ANSI_ARGS_((Tk_BindingTable bindingTable, ClientData object)); /* 46 */ + int (*tk_DeleteBinding) _ANSI_ARGS_((Tcl_Interp * interp, Tk_BindingTable bindingTable, ClientData object, char * eventStr)); /* 47 */ + void (*tk_DeleteBindingTable) _ANSI_ARGS_((Tk_BindingTable bindingTable)); /* 48 */ + void (*tk_DeleteErrorHandler) _ANSI_ARGS_((Tk_ErrorHandler handler)); /* 49 */ + void (*tk_DeleteEventHandler) _ANSI_ARGS_((Tk_Window token, unsigned long mask, Tk_EventProc * proc, ClientData clientData)); /* 50 */ + void (*tk_DeleteGenericHandler) _ANSI_ARGS_((Tk_GenericProc * proc, ClientData clientData)); /* 51 */ + void (*tk_DeleteImage) _ANSI_ARGS_((Tcl_Interp * interp, char * name)); /* 52 */ + void (*tk_DeleteSelHandler) _ANSI_ARGS_((Tk_Window tkwin, Atom selection, Atom target)); /* 53 */ + void (*tk_DestroyWindow) _ANSI_ARGS_((Tk_Window tkwin)); /* 54 */ + char * (*tk_DisplayName) _ANSI_ARGS_((Tk_Window tkwin)); /* 55 */ + int (*tk_DistanceToTextLayout) _ANSI_ARGS_((Tk_TextLayout layout, int x, int y)); /* 56 */ + void (*tk_Draw3DPolygon) _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, XPoint * pointPtr, int numPoints, int borderWidth, int leftRelief)); /* 57 */ + void (*tk_Draw3DRectangle) _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height, int borderWidth, int relief)); /* 58 */ + void (*tk_DrawChars) _ANSI_ARGS_((Display * display, Drawable drawable, GC gc, Tk_Font tkfont, CONST char * source, int numBytes, int x, int y)); /* 59 */ + void (*tk_DrawFocusHighlight) _ANSI_ARGS_((Tk_Window tkwin, GC gc, int width, Drawable drawable)); /* 60 */ + void (*tk_DrawTextLayout) _ANSI_ARGS_((Display * display, Drawable drawable, GC gc, Tk_TextLayout layout, int x, int y, int firstChar, int lastChar)); /* 61 */ + void (*tk_Fill3DPolygon) _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, XPoint * pointPtr, int numPoints, int borderWidth, int leftRelief)); /* 62 */ + void (*tk_Fill3DRectangle) _ANSI_ARGS_((Tk_Window tkwin, Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height, int borderWidth, int relief)); /* 63 */ + Tk_PhotoHandle (*tk_FindPhoto) _ANSI_ARGS_((Tcl_Interp * interp, char * imageName)); /* 64 */ + Font (*tk_FontId) _ANSI_ARGS_((Tk_Font font)); /* 65 */ + void (*tk_Free3DBorder) _ANSI_ARGS_((Tk_3DBorder border)); /* 66 */ + void (*tk_FreeBitmap) _ANSI_ARGS_((Display * display, Pixmap bitmap)); /* 67 */ + void (*tk_FreeColor) _ANSI_ARGS_((XColor * colorPtr)); /* 68 */ + void (*tk_FreeColormap) _ANSI_ARGS_((Display * display, Colormap colormap)); /* 69 */ + void (*tk_FreeCursor) _ANSI_ARGS_((Display * display, Tk_Cursor cursor)); /* 70 */ + void (*tk_FreeFont) _ANSI_ARGS_((Tk_Font f)); /* 71 */ + void (*tk_FreeGC) _ANSI_ARGS_((Display * display, GC gc)); /* 72 */ + void (*tk_FreeImage) _ANSI_ARGS_((Tk_Image image)); /* 73 */ + void (*tk_FreeOptions) _ANSI_ARGS_((Tk_ConfigSpec * specs, char * widgRec, Display * display, int needFlags)); /* 74 */ + void (*tk_FreePixmap) _ANSI_ARGS_((Display * display, Pixmap pixmap)); /* 75 */ + void (*tk_FreeTextLayout) _ANSI_ARGS_((Tk_TextLayout textLayout)); /* 76 */ + void (*tk_FreeXId) _ANSI_ARGS_((Display * display, XID xid)); /* 77 */ + GC (*tk_GCForColor) _ANSI_ARGS_((XColor * colorPtr, Drawable drawable)); /* 78 */ + void (*tk_GeometryRequest) _ANSI_ARGS_((Tk_Window tkwin, int reqWidth, int reqHeight)); /* 79 */ + Tk_3DBorder (*tk_Get3DBorder) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tk_Uid colorName)); /* 80 */ + void (*tk_GetAllBindings) _ANSI_ARGS_((Tcl_Interp * interp, Tk_BindingTable bindingTable, ClientData object)); /* 81 */ + int (*tk_GetAnchor) _ANSI_ARGS_((Tcl_Interp * interp, char * str, Tk_Anchor * anchorPtr)); /* 82 */ + char * (*tk_GetAtomName) _ANSI_ARGS_((Tk_Window tkwin, Atom atom)); /* 83 */ + char * (*tk_GetBinding) _ANSI_ARGS_((Tcl_Interp * interp, Tk_BindingTable bindingTable, ClientData object, char * eventStr)); /* 84 */ + Pixmap (*tk_GetBitmap) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, CONST char * str)); /* 85 */ + Pixmap (*tk_GetBitmapFromData) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * source, int width, int height)); /* 86 */ + int (*tk_GetCapStyle) _ANSI_ARGS_((Tcl_Interp * interp, char * str, int * capPtr)); /* 87 */ + XColor * (*tk_GetColor) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tk_Uid name)); /* 88 */ + XColor * (*tk_GetColorByValue) _ANSI_ARGS_((Tk_Window tkwin, XColor * colorPtr)); /* 89 */ + Colormap (*tk_GetColormap) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * str)); /* 90 */ + Tk_Cursor (*tk_GetCursor) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tk_Uid str)); /* 91 */ + Tk_Cursor (*tk_GetCursorFromData) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * source, char * mask, int width, int height, int xHot, int yHot, Tk_Uid fg, Tk_Uid bg)); /* 92 */ + Tk_Font (*tk_GetFont) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, CONST char * str)); /* 93 */ + Tk_Font (*tk_GetFontFromObj) _ANSI_ARGS_((Tk_Window tkwin, Tcl_Obj * objPtr)); /* 94 */ + void (*tk_GetFontMetrics) _ANSI_ARGS_((Tk_Font font, Tk_FontMetrics * fmPtr)); /* 95 */ + GC (*tk_GetGC) _ANSI_ARGS_((Tk_Window tkwin, unsigned long valueMask, XGCValues * valuePtr)); /* 96 */ + Tk_Image (*tk_GetImage) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * name, Tk_ImageChangedProc * changeProc, ClientData clientData)); /* 97 */ + ClientData (*tk_GetImageMasterData) _ANSI_ARGS_((Tcl_Interp * interp, char * name, Tk_ImageType ** typePtrPtr)); /* 98 */ + Tk_ItemType * (*tk_GetItemTypes) _ANSI_ARGS_((void)); /* 99 */ + int (*tk_GetJoinStyle) _ANSI_ARGS_((Tcl_Interp * interp, char * str, int * joinPtr)); /* 100 */ + int (*tk_GetJustify) _ANSI_ARGS_((Tcl_Interp * interp, char * str, Tk_Justify * justifyPtr)); /* 101 */ + int (*tk_GetNumMainWindows) _ANSI_ARGS_((void)); /* 102 */ + Tk_Uid (*tk_GetOption) _ANSI_ARGS_((Tk_Window tkwin, char * name, char * className)); /* 103 */ + int (*tk_GetPixels) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * str, int * intPtr)); /* 104 */ + Pixmap (*tk_GetPixmap) _ANSI_ARGS_((Display * display, Drawable d, int width, int height, int depth)); /* 105 */ + int (*tk_GetRelief) _ANSI_ARGS_((Tcl_Interp * interp, char * name, int * reliefPtr)); /* 106 */ + void (*tk_GetRootCoords) _ANSI_ARGS_((Tk_Window tkwin, int * xPtr, int * yPtr)); /* 107 */ + int (*tk_GetScrollInfo) _ANSI_ARGS_((Tcl_Interp * interp, int argc, char ** argv, double * dblPtr, int * intPtr)); /* 108 */ + int (*tk_GetScreenMM) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * str, double * doublePtr)); /* 109 */ + int (*tk_GetSelection) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Atom selection, Atom target, Tk_GetSelProc * proc, ClientData clientData)); /* 110 */ + Tk_Uid (*tk_GetUid) _ANSI_ARGS_((CONST char * str)); /* 111 */ + Visual * (*tk_GetVisual) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * str, int * depthPtr, Colormap * colormapPtr)); /* 112 */ + void (*tk_GetVRootGeometry) _ANSI_ARGS_((Tk_Window tkwin, int * xPtr, int * yPtr, int * widthPtr, int * heightPtr)); /* 113 */ + int (*tk_Grab) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, int grabGlobal)); /* 114 */ + void (*tk_HandleEvent) _ANSI_ARGS_((XEvent * eventPtr)); /* 115 */ + Tk_Window (*tk_IdToWindow) _ANSI_ARGS_((Display * display, Window window)); /* 116 */ + void (*tk_ImageChanged) _ANSI_ARGS_((Tk_ImageMaster master, int x, int y, int width, int height, int imageWidth, int imageHeight)); /* 117 */ + int (*tk_Init) _ANSI_ARGS_((Tcl_Interp * interp)); /* 118 */ + Atom (*tk_InternAtom) _ANSI_ARGS_((Tk_Window tkwin, char * name)); /* 119 */ + int (*tk_IntersectTextLayout) _ANSI_ARGS_((Tk_TextLayout layout, int x, int y, int width, int height)); /* 120 */ + void (*tk_MaintainGeometry) _ANSI_ARGS_((Tk_Window slave, Tk_Window master, int x, int y, int width, int height)); /* 121 */ + Tk_Window (*tk_MainWindow) _ANSI_ARGS_((Tcl_Interp * interp)); /* 122 */ + void (*tk_MakeWindowExist) _ANSI_ARGS_((Tk_Window tkwin)); /* 123 */ + void (*tk_ManageGeometry) _ANSI_ARGS_((Tk_Window tkwin, Tk_GeomMgr * mgrPtr, ClientData clientData)); /* 124 */ + void (*tk_MapWindow) _ANSI_ARGS_((Tk_Window tkwin)); /* 125 */ + int (*tk_MeasureChars) _ANSI_ARGS_((Tk_Font tkfont, CONST char * source, int numBytes, int maxPixels, int flags, int * lengthPtr)); /* 126 */ + void (*tk_MoveResizeWindow) _ANSI_ARGS_((Tk_Window tkwin, int x, int y, int width, int height)); /* 127 */ + void (*tk_MoveWindow) _ANSI_ARGS_((Tk_Window tkwin, int x, int y)); /* 128 */ + void (*tk_MoveToplevelWindow) _ANSI_ARGS_((Tk_Window tkwin, int x, int y)); /* 129 */ + char * (*tk_NameOf3DBorder) _ANSI_ARGS_((Tk_3DBorder border)); /* 130 */ + char * (*tk_NameOfAnchor) _ANSI_ARGS_((Tk_Anchor anchor)); /* 131 */ + char * (*tk_NameOfBitmap) _ANSI_ARGS_((Display * display, Pixmap bitmap)); /* 132 */ + char * (*tk_NameOfCapStyle) _ANSI_ARGS_((int cap)); /* 133 */ + char * (*tk_NameOfColor) _ANSI_ARGS_((XColor * colorPtr)); /* 134 */ + char * (*tk_NameOfCursor) _ANSI_ARGS_((Display * display, Tk_Cursor cursor)); /* 135 */ + char * (*tk_NameOfFont) _ANSI_ARGS_((Tk_Font font)); /* 136 */ + char * (*tk_NameOfImage) _ANSI_ARGS_((Tk_ImageMaster imageMaster)); /* 137 */ + char * (*tk_NameOfJoinStyle) _ANSI_ARGS_((int join)); /* 138 */ + char * (*tk_NameOfJustify) _ANSI_ARGS_((Tk_Justify justify)); /* 139 */ + char * (*tk_NameOfRelief) _ANSI_ARGS_((int relief)); /* 140 */ + Tk_Window (*tk_NameToWindow) _ANSI_ARGS_((Tcl_Interp * interp, char * pathName, Tk_Window tkwin)); /* 141 */ + void (*tk_OwnSelection) _ANSI_ARGS_((Tk_Window tkwin, Atom selection, Tk_LostSelProc * proc, ClientData clientData)); /* 142 */ + int (*tk_ParseArgv) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, int * argcPtr, char ** argv, Tk_ArgvInfo * argTable, int flags)); /* 143 */ + void (*tk_PhotoPutBlock) _ANSI_ARGS_((Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr, int x, int y, int width, int height)); /* 144 */ + void (*tk_PhotoPutZoomedBlock) _ANSI_ARGS_((Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr, int x, int y, int width, int height, int zoomX, int zoomY, int subsampleX, int subsampleY)); /* 145 */ + int (*tk_PhotoGetImage) _ANSI_ARGS_((Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr)); /* 146 */ + void (*tk_PhotoBlank) _ANSI_ARGS_((Tk_PhotoHandle handle)); /* 147 */ + void (*tk_PhotoExpand) _ANSI_ARGS_((Tk_PhotoHandle handle, int width, int height)); /* 148 */ + void (*tk_PhotoGetSize) _ANSI_ARGS_((Tk_PhotoHandle handle, int * widthPtr, int * heightPtr)); /* 149 */ + void (*tk_PhotoSetSize) _ANSI_ARGS_((Tk_PhotoHandle handle, int width, int height)); /* 150 */ + int (*tk_PointToChar) _ANSI_ARGS_((Tk_TextLayout layout, int x, int y)); /* 151 */ + int (*tk_PostscriptFontName) _ANSI_ARGS_((Tk_Font tkfont, Tcl_DString * dsPtr)); /* 152 */ + void (*tk_PreserveColormap) _ANSI_ARGS_((Display * display, Colormap colormap)); /* 153 */ + void (*tk_QueueWindowEvent) _ANSI_ARGS_((XEvent * eventPtr, Tcl_QueuePosition position)); /* 154 */ + void (*tk_RedrawImage) _ANSI_ARGS_((Tk_Image image, int imageX, int imageY, int width, int height, Drawable drawable, int drawableX, int drawableY)); /* 155 */ + void (*tk_ResizeWindow) _ANSI_ARGS_((Tk_Window tkwin, int width, int height)); /* 156 */ + int (*tk_RestackWindow) _ANSI_ARGS_((Tk_Window tkwin, int aboveBelow, Tk_Window other)); /* 157 */ + Tk_RestrictProc * (*tk_RestrictEvents) _ANSI_ARGS_((Tk_RestrictProc * proc, ClientData arg, ClientData * prevArgPtr)); /* 158 */ + int (*tk_SafeInit) _ANSI_ARGS_((Tcl_Interp * interp)); /* 159 */ + char * (*tk_SetAppName) _ANSI_ARGS_((Tk_Window tkwin, char * name)); /* 160 */ + void (*tk_SetBackgroundFromBorder) _ANSI_ARGS_((Tk_Window tkwin, Tk_3DBorder border)); /* 161 */ + void (*tk_SetClass) _ANSI_ARGS_((Tk_Window tkwin, char * className)); /* 162 */ + void (*tk_SetGrid) _ANSI_ARGS_((Tk_Window tkwin, int reqWidth, int reqHeight, int gridWidth, int gridHeight)); /* 163 */ + void (*tk_SetInternalBorder) _ANSI_ARGS_((Tk_Window tkwin, int width)); /* 164 */ + void (*tk_SetWindowBackground) _ANSI_ARGS_((Tk_Window tkwin, unsigned long pixel)); /* 165 */ + void (*tk_SetWindowBackgroundPixmap) _ANSI_ARGS_((Tk_Window tkwin, Pixmap pixmap)); /* 166 */ + void (*tk_SetWindowBorder) _ANSI_ARGS_((Tk_Window tkwin, unsigned long pixel)); /* 167 */ + void (*tk_SetWindowBorderWidth) _ANSI_ARGS_((Tk_Window tkwin, int width)); /* 168 */ + void (*tk_SetWindowBorderPixmap) _ANSI_ARGS_((Tk_Window tkwin, Pixmap pixmap)); /* 169 */ + void (*tk_SetWindowColormap) _ANSI_ARGS_((Tk_Window tkwin, Colormap colormap)); /* 170 */ + int (*tk_SetWindowVisual) _ANSI_ARGS_((Tk_Window tkwin, Visual * visual, int depth, Colormap colormap)); /* 171 */ + void (*tk_SizeOfBitmap) _ANSI_ARGS_((Display * display, Pixmap bitmap, int * widthPtr, int * heightPtr)); /* 172 */ + void (*tk_SizeOfImage) _ANSI_ARGS_((Tk_Image image, int * widthPtr, int * heightPtr)); /* 173 */ + int (*tk_StrictMotif) _ANSI_ARGS_((Tk_Window tkwin)); /* 174 */ + void (*tk_TextLayoutToPostscript) _ANSI_ARGS_((Tcl_Interp * interp, Tk_TextLayout layout)); /* 175 */ + int (*tk_TextWidth) _ANSI_ARGS_((Tk_Font font, CONST char * str, int numBytes)); /* 176 */ + void (*tk_UndefineCursor) _ANSI_ARGS_((Tk_Window window)); /* 177 */ + void (*tk_UnderlineChars) _ANSI_ARGS_((Display * display, Drawable drawable, GC gc, Tk_Font tkfont, CONST char * source, int x, int y, int firstByte, int lastByte)); /* 178 */ + void (*tk_UnderlineTextLayout) _ANSI_ARGS_((Display * display, Drawable drawable, GC gc, Tk_TextLayout layout, int x, int y, int underline)); /* 179 */ + void (*tk_Ungrab) _ANSI_ARGS_((Tk_Window tkwin)); /* 180 */ + void (*tk_UnmaintainGeometry) _ANSI_ARGS_((Tk_Window slave, Tk_Window master)); /* 181 */ + void (*tk_UnmapWindow) _ANSI_ARGS_((Tk_Window tkwin)); /* 182 */ + void (*tk_UnsetGrid) _ANSI_ARGS_((Tk_Window tkwin)); /* 183 */ + void (*tk_UpdatePointer) _ANSI_ARGS_((Tk_Window tkwin, int x, int y, int state)); /* 184 */ + Pixmap (*tk_AllocBitmapFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tcl_Obj * objPtr)); /* 185 */ + Tk_3DBorder (*tk_Alloc3DBorderFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tcl_Obj * objPtr)); /* 186 */ + XColor * (*tk_AllocColorFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tcl_Obj * objPtr)); /* 187 */ + Tk_Cursor (*tk_AllocCursorFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tcl_Obj * objPtr)); /* 188 */ + Tk_Font (*tk_AllocFontFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tcl_Obj * objPtr)); /* 189 */ + Tk_OptionTable (*tk_CreateOptionTable) _ANSI_ARGS_((Tcl_Interp * interp, CONST Tk_OptionSpec * templatePtr)); /* 190 */ + void (*tk_DeleteOptionTable) _ANSI_ARGS_((Tk_OptionTable optionTable)); /* 191 */ + void (*tk_Free3DBorderFromObj) _ANSI_ARGS_((Tk_Window tkwin, Tcl_Obj * objPtr)); /* 192 */ + void (*tk_FreeBitmapFromObj) _ANSI_ARGS_((Tk_Window tkwin, Tcl_Obj * objPtr)); /* 193 */ + void (*tk_FreeColorFromObj) _ANSI_ARGS_((Tk_Window tkwin, Tcl_Obj * objPtr)); /* 194 */ + void (*tk_FreeConfigOptions) _ANSI_ARGS_((char * recordPtr, Tk_OptionTable optionToken, Tk_Window tkwin)); /* 195 */ + void (*tk_FreeSavedOptions) _ANSI_ARGS_((Tk_SavedOptions * savePtr)); /* 196 */ + void (*tk_FreeCursorFromObj) _ANSI_ARGS_((Tk_Window tkwin, Tcl_Obj * objPtr)); /* 197 */ + void (*tk_FreeFontFromObj) _ANSI_ARGS_((Tk_Window tkwin, Tcl_Obj * objPtr)); /* 198 */ + Tk_3DBorder (*tk_Get3DBorderFromObj) _ANSI_ARGS_((Tk_Window tkwin, Tcl_Obj * objPtr)); /* 199 */ + int (*tk_GetAnchorFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * objPtr, Tk_Anchor * anchorPtr)); /* 200 */ + Pixmap (*tk_GetBitmapFromObj) _ANSI_ARGS_((Tk_Window tkwin, Tcl_Obj * objPtr)); /* 201 */ + XColor * (*tk_GetColorFromObj) _ANSI_ARGS_((Tk_Window tkwin, Tcl_Obj * objPtr)); /* 202 */ + Tk_Cursor (*tk_GetCursorFromObj) _ANSI_ARGS_((Tk_Window tkwin, Tcl_Obj * objPtr)); /* 203 */ + Tcl_Obj * (*tk_GetOptionInfo) _ANSI_ARGS_((Tcl_Interp * interp, char * recordPtr, Tk_OptionTable optionTable, Tcl_Obj * namePtr, Tk_Window tkwin)); /* 204 */ + Tcl_Obj * (*tk_GetOptionValue) _ANSI_ARGS_((Tcl_Interp * interp, char * recordPtr, Tk_OptionTable optionTable, Tcl_Obj * namePtr, Tk_Window tkwin)); /* 205 */ + int (*tk_GetJustifyFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * objPtr, Tk_Justify * justifyPtr)); /* 206 */ + int (*tk_GetMMFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tcl_Obj * objPtr, double * doublePtr)); /* 207 */ + int (*tk_GetPixelsFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tcl_Obj * objPtr, int * intPtr)); /* 208 */ + int (*tk_GetReliefFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * objPtr, int * resultPtr)); /* 209 */ + int (*tk_GetScrollInfoObj) _ANSI_ARGS_((Tcl_Interp * interp, int objc, Tcl_Obj *CONST objv[], double * dblPtr, int * intPtr)); /* 210 */ + int (*tk_InitOptions) _ANSI_ARGS_((Tcl_Interp * interp, char * recordPtr, Tk_OptionTable optionToken, Tk_Window tkwin)); /* 211 */ + void (*tk_MainEx) _ANSI_ARGS_((int argc, char ** argv, Tcl_AppInitProc * appInitProc, Tcl_Interp * interp)); /* 212 */ + void (*tk_RestoreSavedOptions) _ANSI_ARGS_((Tk_SavedOptions * savePtr)); /* 213 */ + int (*tk_SetOptions) _ANSI_ARGS_((Tcl_Interp * interp, char * recordPtr, Tk_OptionTable optionTable, int objc, Tcl_Obj *CONST objv[], Tk_Window tkwin, Tk_SavedOptions * savePtr, int * maskPtr)); /* 214 */ + void (*tk_InitConsoleChannels) _ANSI_ARGS_((Tcl_Interp * interp)); /* 215 */ + int (*tk_CreateConsoleWindow) _ANSI_ARGS_((Tcl_Interp * interp)); /* 216 */ + void (*tk_CreateSmoothMethod) _ANSI_ARGS_((Tcl_Interp * interp, Tk_SmoothMethod * method)); /* 217 */ + void *reserved218; + void *reserved219; + int (*tk_GetDash) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * value, Tk_Dash * dash)); /* 220 */ + void (*tk_CreateOutline) _ANSI_ARGS_((Tk_Outline * outline)); /* 221 */ + void (*tk_DeleteOutline) _ANSI_ARGS_((Display * display, Tk_Outline * outline)); /* 222 */ + int (*tk_ConfigOutlineGC) _ANSI_ARGS_((XGCValues * gcValues, Tk_Canvas canvas, Tk_Item * item, Tk_Outline * outline)); /* 223 */ + int (*tk_ChangeOutlineGC) _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * item, Tk_Outline * outline)); /* 224 */ + int (*tk_ResetOutlineGC) _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * item, Tk_Outline * outline)); /* 225 */ + int (*tk_CanvasPsOutline) _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item * item, Tk_Outline * outline)); /* 226 */ + void (*tk_SetTSOrigin) _ANSI_ARGS_((Tk_Window tkwin, GC gc, int x, int y)); /* 227 */ + int (*tk_CanvasGetCoordFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Canvas canvas, Tcl_Obj * obj, double * doublePtr)); /* 228 */ + void (*tk_CanvasSetOffset) _ANSI_ARGS_((Tk_Canvas canvas, GC gc, Tk_TSOffset * offset)); /* 229 */ + void (*tk_DitherPhoto) _ANSI_ARGS_((Tk_PhotoHandle handle, int x, int y, int width, int height)); /* 230 */ + int (*tk_PostscriptBitmap) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tk_PostscriptInfo psInfo, Pixmap bitmap, int startX, int startY, int width, int height)); /* 231 */ + int (*tk_PostscriptColor) _ANSI_ARGS_((Tcl_Interp * interp, Tk_PostscriptInfo psInfo, XColor * colorPtr)); /* 232 */ + int (*tk_PostscriptFont) _ANSI_ARGS_((Tcl_Interp * interp, Tk_PostscriptInfo psInfo, Tk_Font font)); /* 233 */ + int (*tk_PostscriptImage) _ANSI_ARGS_((Tk_Image image, Tcl_Interp * interp, Tk_Window tkwin, Tk_PostscriptInfo psinfo, int x, int y, int width, int height, int prepass)); /* 234 */ + void (*tk_PostscriptPath) _ANSI_ARGS_((Tcl_Interp * interp, Tk_PostscriptInfo psInfo, double * coordPtr, int numPoints)); /* 235 */ + int (*tk_PostscriptStipple) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tk_PostscriptInfo psInfo, Pixmap bitmap)); /* 236 */ + double (*tk_PostscriptY) _ANSI_ARGS_((double y, Tk_PostscriptInfo psInfo)); /* 237 */ + int (*tk_PostscriptPhoto) _ANSI_ARGS_((Tcl_Interp * interp, Tk_PhotoImageBlock * blockPtr, Tk_PostscriptInfo psInfo, int width, int height)); /* 238 */ +} TkStubs; + +#ifdef __cplusplus +extern "C" { +#endif +extern TkStubs *tkStubsPtr; +#ifdef __cplusplus +} +#endif + +#if defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) + +/* + * Inline function declarations: + */ + +#ifndef Tk_MainLoop +#define Tk_MainLoop \ + (tkStubsPtr->tk_MainLoop) /* 0 */ +#endif +#ifndef Tk_3DBorderColor +#define Tk_3DBorderColor \ + (tkStubsPtr->tk_3DBorderColor) /* 1 */ +#endif +#ifndef Tk_3DBorderGC +#define Tk_3DBorderGC \ + (tkStubsPtr->tk_3DBorderGC) /* 2 */ +#endif +#ifndef Tk_3DHorizontalBevel +#define Tk_3DHorizontalBevel \ + (tkStubsPtr->tk_3DHorizontalBevel) /* 3 */ +#endif +#ifndef Tk_3DVerticalBevel +#define Tk_3DVerticalBevel \ + (tkStubsPtr->tk_3DVerticalBevel) /* 4 */ +#endif +#ifndef Tk_AddOption +#define Tk_AddOption \ + (tkStubsPtr->tk_AddOption) /* 5 */ +#endif +#ifndef Tk_BindEvent +#define Tk_BindEvent \ + (tkStubsPtr->tk_BindEvent) /* 6 */ +#endif +#ifndef Tk_CanvasDrawableCoords +#define Tk_CanvasDrawableCoords \ + (tkStubsPtr->tk_CanvasDrawableCoords) /* 7 */ +#endif +#ifndef Tk_CanvasEventuallyRedraw +#define Tk_CanvasEventuallyRedraw \ + (tkStubsPtr->tk_CanvasEventuallyRedraw) /* 8 */ +#endif +#ifndef Tk_CanvasGetCoord +#define Tk_CanvasGetCoord \ + (tkStubsPtr->tk_CanvasGetCoord) /* 9 */ +#endif +#ifndef Tk_CanvasGetTextInfo +#define Tk_CanvasGetTextInfo \ + (tkStubsPtr->tk_CanvasGetTextInfo) /* 10 */ +#endif +#ifndef Tk_CanvasPsBitmap +#define Tk_CanvasPsBitmap \ + (tkStubsPtr->tk_CanvasPsBitmap) /* 11 */ +#endif +#ifndef Tk_CanvasPsColor +#define Tk_CanvasPsColor \ + (tkStubsPtr->tk_CanvasPsColor) /* 12 */ +#endif +#ifndef Tk_CanvasPsFont +#define Tk_CanvasPsFont \ + (tkStubsPtr->tk_CanvasPsFont) /* 13 */ +#endif +#ifndef Tk_CanvasPsPath +#define Tk_CanvasPsPath \ + (tkStubsPtr->tk_CanvasPsPath) /* 14 */ +#endif +#ifndef Tk_CanvasPsStipple +#define Tk_CanvasPsStipple \ + (tkStubsPtr->tk_CanvasPsStipple) /* 15 */ +#endif +#ifndef Tk_CanvasPsY +#define Tk_CanvasPsY \ + (tkStubsPtr->tk_CanvasPsY) /* 16 */ +#endif +#ifndef Tk_CanvasSetStippleOrigin +#define Tk_CanvasSetStippleOrigin \ + (tkStubsPtr->tk_CanvasSetStippleOrigin) /* 17 */ +#endif +#ifndef Tk_CanvasTagsParseProc +#define Tk_CanvasTagsParseProc \ + (tkStubsPtr->tk_CanvasTagsParseProc) /* 18 */ +#endif +#ifndef Tk_CanvasTagsPrintProc +#define Tk_CanvasTagsPrintProc \ + (tkStubsPtr->tk_CanvasTagsPrintProc) /* 19 */ +#endif +#ifndef Tk_CanvasTkwin +#define Tk_CanvasTkwin \ + (tkStubsPtr->tk_CanvasTkwin) /* 20 */ +#endif +#ifndef Tk_CanvasWindowCoords +#define Tk_CanvasWindowCoords \ + (tkStubsPtr->tk_CanvasWindowCoords) /* 21 */ +#endif +#ifndef Tk_ChangeWindowAttributes +#define Tk_ChangeWindowAttributes \ + (tkStubsPtr->tk_ChangeWindowAttributes) /* 22 */ +#endif +#ifndef Tk_CharBbox +#define Tk_CharBbox \ + (tkStubsPtr->tk_CharBbox) /* 23 */ +#endif +#ifndef Tk_ClearSelection +#define Tk_ClearSelection \ + (tkStubsPtr->tk_ClearSelection) /* 24 */ +#endif +#ifndef Tk_ClipboardAppend +#define Tk_ClipboardAppend \ + (tkStubsPtr->tk_ClipboardAppend) /* 25 */ +#endif +#ifndef Tk_ClipboardClear +#define Tk_ClipboardClear \ + (tkStubsPtr->tk_ClipboardClear) /* 26 */ +#endif +#ifndef Tk_ConfigureInfo +#define Tk_ConfigureInfo \ + (tkStubsPtr->tk_ConfigureInfo) /* 27 */ +#endif +#ifndef Tk_ConfigureValue +#define Tk_ConfigureValue \ + (tkStubsPtr->tk_ConfigureValue) /* 28 */ +#endif +#ifndef Tk_ConfigureWidget +#define Tk_ConfigureWidget \ + (tkStubsPtr->tk_ConfigureWidget) /* 29 */ +#endif +#ifndef Tk_ConfigureWindow +#define Tk_ConfigureWindow \ + (tkStubsPtr->tk_ConfigureWindow) /* 30 */ +#endif +#ifndef Tk_ComputeTextLayout +#define Tk_ComputeTextLayout \ + (tkStubsPtr->tk_ComputeTextLayout) /* 31 */ +#endif +#ifndef Tk_CoordsToWindow +#define Tk_CoordsToWindow \ + (tkStubsPtr->tk_CoordsToWindow) /* 32 */ +#endif +#ifndef Tk_CreateBinding +#define Tk_CreateBinding \ + (tkStubsPtr->tk_CreateBinding) /* 33 */ +#endif +#ifndef Tk_CreateBindingTable +#define Tk_CreateBindingTable \ + (tkStubsPtr->tk_CreateBindingTable) /* 34 */ +#endif +#ifndef Tk_CreateErrorHandler +#define Tk_CreateErrorHandler \ + (tkStubsPtr->tk_CreateErrorHandler) /* 35 */ +#endif +#ifndef Tk_CreateEventHandler +#define Tk_CreateEventHandler \ + (tkStubsPtr->tk_CreateEventHandler) /* 36 */ +#endif +#ifndef Tk_CreateGenericHandler +#define Tk_CreateGenericHandler \ + (tkStubsPtr->tk_CreateGenericHandler) /* 37 */ +#endif +#ifndef Tk_CreateImageType +#define Tk_CreateImageType \ + (tkStubsPtr->tk_CreateImageType) /* 38 */ +#endif +#ifndef Tk_CreateItemType +#define Tk_CreateItemType \ + (tkStubsPtr->tk_CreateItemType) /* 39 */ +#endif +#ifndef Tk_CreatePhotoImageFormat +#define Tk_CreatePhotoImageFormat \ + (tkStubsPtr->tk_CreatePhotoImageFormat) /* 40 */ +#endif +#ifndef Tk_CreateSelHandler +#define Tk_CreateSelHandler \ + (tkStubsPtr->tk_CreateSelHandler) /* 41 */ +#endif +#ifndef Tk_CreateWindow +#define Tk_CreateWindow \ + (tkStubsPtr->tk_CreateWindow) /* 42 */ +#endif +#ifndef Tk_CreateWindowFromPath +#define Tk_CreateWindowFromPath \ + (tkStubsPtr->tk_CreateWindowFromPath) /* 43 */ +#endif +#ifndef Tk_DefineBitmap +#define Tk_DefineBitmap \ + (tkStubsPtr->tk_DefineBitmap) /* 44 */ +#endif +#ifndef Tk_DefineCursor +#define Tk_DefineCursor \ + (tkStubsPtr->tk_DefineCursor) /* 45 */ +#endif +#ifndef Tk_DeleteAllBindings +#define Tk_DeleteAllBindings \ + (tkStubsPtr->tk_DeleteAllBindings) /* 46 */ +#endif +#ifndef Tk_DeleteBinding +#define Tk_DeleteBinding \ + (tkStubsPtr->tk_DeleteBinding) /* 47 */ +#endif +#ifndef Tk_DeleteBindingTable +#define Tk_DeleteBindingTable \ + (tkStubsPtr->tk_DeleteBindingTable) /* 48 */ +#endif +#ifndef Tk_DeleteErrorHandler +#define Tk_DeleteErrorHandler \ + (tkStubsPtr->tk_DeleteErrorHandler) /* 49 */ +#endif +#ifndef Tk_DeleteEventHandler +#define Tk_DeleteEventHandler \ + (tkStubsPtr->tk_DeleteEventHandler) /* 50 */ +#endif +#ifndef Tk_DeleteGenericHandler +#define Tk_DeleteGenericHandler \ + (tkStubsPtr->tk_DeleteGenericHandler) /* 51 */ +#endif +#ifndef Tk_DeleteImage +#define Tk_DeleteImage \ + (tkStubsPtr->tk_DeleteImage) /* 52 */ +#endif +#ifndef Tk_DeleteSelHandler +#define Tk_DeleteSelHandler \ + (tkStubsPtr->tk_DeleteSelHandler) /* 53 */ +#endif +#ifndef Tk_DestroyWindow +#define Tk_DestroyWindow \ + (tkStubsPtr->tk_DestroyWindow) /* 54 */ +#endif +#ifndef Tk_DisplayName +#define Tk_DisplayName \ + (tkStubsPtr->tk_DisplayName) /* 55 */ +#endif +#ifndef Tk_DistanceToTextLayout +#define Tk_DistanceToTextLayout \ + (tkStubsPtr->tk_DistanceToTextLayout) /* 56 */ +#endif +#ifndef Tk_Draw3DPolygon +#define Tk_Draw3DPolygon \ + (tkStubsPtr->tk_Draw3DPolygon) /* 57 */ +#endif +#ifndef Tk_Draw3DRectangle +#define Tk_Draw3DRectangle \ + (tkStubsPtr->tk_Draw3DRectangle) /* 58 */ +#endif +#ifndef Tk_DrawChars +#define Tk_DrawChars \ + (tkStubsPtr->tk_DrawChars) /* 59 */ +#endif +#ifndef Tk_DrawFocusHighlight +#define Tk_DrawFocusHighlight \ + (tkStubsPtr->tk_DrawFocusHighlight) /* 60 */ +#endif +#ifndef Tk_DrawTextLayout +#define Tk_DrawTextLayout \ + (tkStubsPtr->tk_DrawTextLayout) /* 61 */ +#endif +#ifndef Tk_Fill3DPolygon +#define Tk_Fill3DPolygon \ + (tkStubsPtr->tk_Fill3DPolygon) /* 62 */ +#endif +#ifndef Tk_Fill3DRectangle +#define Tk_Fill3DRectangle \ + (tkStubsPtr->tk_Fill3DRectangle) /* 63 */ +#endif +#ifndef Tk_FindPhoto +#define Tk_FindPhoto \ + (tkStubsPtr->tk_FindPhoto) /* 64 */ +#endif +#ifndef Tk_FontId +#define Tk_FontId \ + (tkStubsPtr->tk_FontId) /* 65 */ +#endif +#ifndef Tk_Free3DBorder +#define Tk_Free3DBorder \ + (tkStubsPtr->tk_Free3DBorder) /* 66 */ +#endif +#ifndef Tk_FreeBitmap +#define Tk_FreeBitmap \ + (tkStubsPtr->tk_FreeBitmap) /* 67 */ +#endif +#ifndef Tk_FreeColor +#define Tk_FreeColor \ + (tkStubsPtr->tk_FreeColor) /* 68 */ +#endif +#ifndef Tk_FreeColormap +#define Tk_FreeColormap \ + (tkStubsPtr->tk_FreeColormap) /* 69 */ +#endif +#ifndef Tk_FreeCursor +#define Tk_FreeCursor \ + (tkStubsPtr->tk_FreeCursor) /* 70 */ +#endif +#ifndef Tk_FreeFont +#define Tk_FreeFont \ + (tkStubsPtr->tk_FreeFont) /* 71 */ +#endif +#ifndef Tk_FreeGC +#define Tk_FreeGC \ + (tkStubsPtr->tk_FreeGC) /* 72 */ +#endif +#ifndef Tk_FreeImage +#define Tk_FreeImage \ + (tkStubsPtr->tk_FreeImage) /* 73 */ +#endif +#ifndef Tk_FreeOptions +#define Tk_FreeOptions \ + (tkStubsPtr->tk_FreeOptions) /* 74 */ +#endif +#ifndef Tk_FreePixmap +#define Tk_FreePixmap \ + (tkStubsPtr->tk_FreePixmap) /* 75 */ +#endif +#ifndef Tk_FreeTextLayout +#define Tk_FreeTextLayout \ + (tkStubsPtr->tk_FreeTextLayout) /* 76 */ +#endif +#ifndef Tk_FreeXId +#define Tk_FreeXId \ + (tkStubsPtr->tk_FreeXId) /* 77 */ +#endif +#ifndef Tk_GCForColor +#define Tk_GCForColor \ + (tkStubsPtr->tk_GCForColor) /* 78 */ +#endif +#ifndef Tk_GeometryRequest +#define Tk_GeometryRequest \ + (tkStubsPtr->tk_GeometryRequest) /* 79 */ +#endif +#ifndef Tk_Get3DBorder +#define Tk_Get3DBorder \ + (tkStubsPtr->tk_Get3DBorder) /* 80 */ +#endif +#ifndef Tk_GetAllBindings +#define Tk_GetAllBindings \ + (tkStubsPtr->tk_GetAllBindings) /* 81 */ +#endif +#ifndef Tk_GetAnchor +#define Tk_GetAnchor \ + (tkStubsPtr->tk_GetAnchor) /* 82 */ +#endif +#ifndef Tk_GetAtomName +#define Tk_GetAtomName \ + (tkStubsPtr->tk_GetAtomName) /* 83 */ +#endif +#ifndef Tk_GetBinding +#define Tk_GetBinding \ + (tkStubsPtr->tk_GetBinding) /* 84 */ +#endif +#ifndef Tk_GetBitmap +#define Tk_GetBitmap \ + (tkStubsPtr->tk_GetBitmap) /* 85 */ +#endif +#ifndef Tk_GetBitmapFromData +#define Tk_GetBitmapFromData \ + (tkStubsPtr->tk_GetBitmapFromData) /* 86 */ +#endif +#ifndef Tk_GetCapStyle +#define Tk_GetCapStyle \ + (tkStubsPtr->tk_GetCapStyle) /* 87 */ +#endif +#ifndef Tk_GetColor +#define Tk_GetColor \ + (tkStubsPtr->tk_GetColor) /* 88 */ +#endif +#ifndef Tk_GetColorByValue +#define Tk_GetColorByValue \ + (tkStubsPtr->tk_GetColorByValue) /* 89 */ +#endif +#ifndef Tk_GetColormap +#define Tk_GetColormap \ + (tkStubsPtr->tk_GetColormap) /* 90 */ +#endif +#ifndef Tk_GetCursor +#define Tk_GetCursor \ + (tkStubsPtr->tk_GetCursor) /* 91 */ +#endif +#ifndef Tk_GetCursorFromData +#define Tk_GetCursorFromData \ + (tkStubsPtr->tk_GetCursorFromData) /* 92 */ +#endif +#ifndef Tk_GetFont +#define Tk_GetFont \ + (tkStubsPtr->tk_GetFont) /* 93 */ +#endif +#ifndef Tk_GetFontFromObj +#define Tk_GetFontFromObj \ + (tkStubsPtr->tk_GetFontFromObj) /* 94 */ +#endif +#ifndef Tk_GetFontMetrics +#define Tk_GetFontMetrics \ + (tkStubsPtr->tk_GetFontMetrics) /* 95 */ +#endif +#ifndef Tk_GetGC +#define Tk_GetGC \ + (tkStubsPtr->tk_GetGC) /* 96 */ +#endif +#ifndef Tk_GetImage +#define Tk_GetImage \ + (tkStubsPtr->tk_GetImage) /* 97 */ +#endif +#ifndef Tk_GetImageMasterData +#define Tk_GetImageMasterData \ + (tkStubsPtr->tk_GetImageMasterData) /* 98 */ +#endif +#ifndef Tk_GetItemTypes +#define Tk_GetItemTypes \ + (tkStubsPtr->tk_GetItemTypes) /* 99 */ +#endif +#ifndef Tk_GetJoinStyle +#define Tk_GetJoinStyle \ + (tkStubsPtr->tk_GetJoinStyle) /* 100 */ +#endif +#ifndef Tk_GetJustify +#define Tk_GetJustify \ + (tkStubsPtr->tk_GetJustify) /* 101 */ +#endif +#ifndef Tk_GetNumMainWindows +#define Tk_GetNumMainWindows \ + (tkStubsPtr->tk_GetNumMainWindows) /* 102 */ +#endif +#ifndef Tk_GetOption +#define Tk_GetOption \ + (tkStubsPtr->tk_GetOption) /* 103 */ +#endif +#ifndef Tk_GetPixels +#define Tk_GetPixels \ + (tkStubsPtr->tk_GetPixels) /* 104 */ +#endif +#ifndef Tk_GetPixmap +#define Tk_GetPixmap \ + (tkStubsPtr->tk_GetPixmap) /* 105 */ +#endif +#ifndef Tk_GetRelief +#define Tk_GetRelief \ + (tkStubsPtr->tk_GetRelief) /* 106 */ +#endif +#ifndef Tk_GetRootCoords +#define Tk_GetRootCoords \ + (tkStubsPtr->tk_GetRootCoords) /* 107 */ +#endif +#ifndef Tk_GetScrollInfo +#define Tk_GetScrollInfo \ + (tkStubsPtr->tk_GetScrollInfo) /* 108 */ +#endif +#ifndef Tk_GetScreenMM +#define Tk_GetScreenMM \ + (tkStubsPtr->tk_GetScreenMM) /* 109 */ +#endif +#ifndef Tk_GetSelection +#define Tk_GetSelection \ + (tkStubsPtr->tk_GetSelection) /* 110 */ +#endif +#ifndef Tk_GetUid +#define Tk_GetUid \ + (tkStubsPtr->tk_GetUid) /* 111 */ +#endif +#ifndef Tk_GetVisual +#define Tk_GetVisual \ + (tkStubsPtr->tk_GetVisual) /* 112 */ +#endif +#ifndef Tk_GetVRootGeometry +#define Tk_GetVRootGeometry \ + (tkStubsPtr->tk_GetVRootGeometry) /* 113 */ +#endif +#ifndef Tk_Grab +#define Tk_Grab \ + (tkStubsPtr->tk_Grab) /* 114 */ +#endif +#ifndef Tk_HandleEvent +#define Tk_HandleEvent \ + (tkStubsPtr->tk_HandleEvent) /* 115 */ +#endif +#ifndef Tk_IdToWindow +#define Tk_IdToWindow \ + (tkStubsPtr->tk_IdToWindow) /* 116 */ +#endif +#ifndef Tk_ImageChanged +#define Tk_ImageChanged \ + (tkStubsPtr->tk_ImageChanged) /* 117 */ +#endif +#ifndef Tk_Init +#define Tk_Init \ + (tkStubsPtr->tk_Init) /* 118 */ +#endif +#ifndef Tk_InternAtom +#define Tk_InternAtom \ + (tkStubsPtr->tk_InternAtom) /* 119 */ +#endif +#ifndef Tk_IntersectTextLayout +#define Tk_IntersectTextLayout \ + (tkStubsPtr->tk_IntersectTextLayout) /* 120 */ +#endif +#ifndef Tk_MaintainGeometry +#define Tk_MaintainGeometry \ + (tkStubsPtr->tk_MaintainGeometry) /* 121 */ +#endif +#ifndef Tk_MainWindow +#define Tk_MainWindow \ + (tkStubsPtr->tk_MainWindow) /* 122 */ +#endif +#ifndef Tk_MakeWindowExist +#define Tk_MakeWindowExist \ + (tkStubsPtr->tk_MakeWindowExist) /* 123 */ +#endif +#ifndef Tk_ManageGeometry +#define Tk_ManageGeometry \ + (tkStubsPtr->tk_ManageGeometry) /* 124 */ +#endif +#ifndef Tk_MapWindow +#define Tk_MapWindow \ + (tkStubsPtr->tk_MapWindow) /* 125 */ +#endif +#ifndef Tk_MeasureChars +#define Tk_MeasureChars \ + (tkStubsPtr->tk_MeasureChars) /* 126 */ +#endif +#ifndef Tk_MoveResizeWindow +#define Tk_MoveResizeWindow \ + (tkStubsPtr->tk_MoveResizeWindow) /* 127 */ +#endif +#ifndef Tk_MoveWindow +#define Tk_MoveWindow \ + (tkStubsPtr->tk_MoveWindow) /* 128 */ +#endif +#ifndef Tk_MoveToplevelWindow +#define Tk_MoveToplevelWindow \ + (tkStubsPtr->tk_MoveToplevelWindow) /* 129 */ +#endif +#ifndef Tk_NameOf3DBorder +#define Tk_NameOf3DBorder \ + (tkStubsPtr->tk_NameOf3DBorder) /* 130 */ +#endif +#ifndef Tk_NameOfAnchor +#define Tk_NameOfAnchor \ + (tkStubsPtr->tk_NameOfAnchor) /* 131 */ +#endif +#ifndef Tk_NameOfBitmap +#define Tk_NameOfBitmap \ + (tkStubsPtr->tk_NameOfBitmap) /* 132 */ +#endif +#ifndef Tk_NameOfCapStyle +#define Tk_NameOfCapStyle \ + (tkStubsPtr->tk_NameOfCapStyle) /* 133 */ +#endif +#ifndef Tk_NameOfColor +#define Tk_NameOfColor \ + (tkStubsPtr->tk_NameOfColor) /* 134 */ +#endif +#ifndef Tk_NameOfCursor +#define Tk_NameOfCursor \ + (tkStubsPtr->tk_NameOfCursor) /* 135 */ +#endif +#ifndef Tk_NameOfFont +#define Tk_NameOfFont \ + (tkStubsPtr->tk_NameOfFont) /* 136 */ +#endif +#ifndef Tk_NameOfImage +#define Tk_NameOfImage \ + (tkStubsPtr->tk_NameOfImage) /* 137 */ +#endif +#ifndef Tk_NameOfJoinStyle +#define Tk_NameOfJoinStyle \ + (tkStubsPtr->tk_NameOfJoinStyle) /* 138 */ +#endif +#ifndef Tk_NameOfJustify +#define Tk_NameOfJustify \ + (tkStubsPtr->tk_NameOfJustify) /* 139 */ +#endif +#ifndef Tk_NameOfRelief +#define Tk_NameOfRelief \ + (tkStubsPtr->tk_NameOfRelief) /* 140 */ +#endif +#ifndef Tk_NameToWindow +#define Tk_NameToWindow \ + (tkStubsPtr->tk_NameToWindow) /* 141 */ +#endif +#ifndef Tk_OwnSelection +#define Tk_OwnSelection \ + (tkStubsPtr->tk_OwnSelection) /* 142 */ +#endif +#ifndef Tk_ParseArgv +#define Tk_ParseArgv \ + (tkStubsPtr->tk_ParseArgv) /* 143 */ +#endif +#ifndef Tk_PhotoPutBlock +#define Tk_PhotoPutBlock \ + (tkStubsPtr->tk_PhotoPutBlock) /* 144 */ +#endif +#ifndef Tk_PhotoPutZoomedBlock +#define Tk_PhotoPutZoomedBlock \ + (tkStubsPtr->tk_PhotoPutZoomedBlock) /* 145 */ +#endif +#ifndef Tk_PhotoGetImage +#define Tk_PhotoGetImage \ + (tkStubsPtr->tk_PhotoGetImage) /* 146 */ +#endif +#ifndef Tk_PhotoBlank +#define Tk_PhotoBlank \ + (tkStubsPtr->tk_PhotoBlank) /* 147 */ +#endif +#ifndef Tk_PhotoExpand +#define Tk_PhotoExpand \ + (tkStubsPtr->tk_PhotoExpand) /* 148 */ +#endif +#ifndef Tk_PhotoGetSize +#define Tk_PhotoGetSize \ + (tkStubsPtr->tk_PhotoGetSize) /* 149 */ +#endif +#ifndef Tk_PhotoSetSize +#define Tk_PhotoSetSize \ + (tkStubsPtr->tk_PhotoSetSize) /* 150 */ +#endif +#ifndef Tk_PointToChar +#define Tk_PointToChar \ + (tkStubsPtr->tk_PointToChar) /* 151 */ +#endif +#ifndef Tk_PostscriptFontName +#define Tk_PostscriptFontName \ + (tkStubsPtr->tk_PostscriptFontName) /* 152 */ +#endif +#ifndef Tk_PreserveColormap +#define Tk_PreserveColormap \ + (tkStubsPtr->tk_PreserveColormap) /* 153 */ +#endif +#ifndef Tk_QueueWindowEvent +#define Tk_QueueWindowEvent \ + (tkStubsPtr->tk_QueueWindowEvent) /* 154 */ +#endif +#ifndef Tk_RedrawImage +#define Tk_RedrawImage \ + (tkStubsPtr->tk_RedrawImage) /* 155 */ +#endif +#ifndef Tk_ResizeWindow +#define Tk_ResizeWindow \ + (tkStubsPtr->tk_ResizeWindow) /* 156 */ +#endif +#ifndef Tk_RestackWindow +#define Tk_RestackWindow \ + (tkStubsPtr->tk_RestackWindow) /* 157 */ +#endif +#ifndef Tk_RestrictEvents +#define Tk_RestrictEvents \ + (tkStubsPtr->tk_RestrictEvents) /* 158 */ +#endif +#ifndef Tk_SafeInit +#define Tk_SafeInit \ + (tkStubsPtr->tk_SafeInit) /* 159 */ +#endif +#ifndef Tk_SetAppName +#define Tk_SetAppName \ + (tkStubsPtr->tk_SetAppName) /* 160 */ +#endif +#ifndef Tk_SetBackgroundFromBorder +#define Tk_SetBackgroundFromBorder \ + (tkStubsPtr->tk_SetBackgroundFromBorder) /* 161 */ +#endif +#ifndef Tk_SetClass +#define Tk_SetClass \ + (tkStubsPtr->tk_SetClass) /* 162 */ +#endif +#ifndef Tk_SetGrid +#define Tk_SetGrid \ + (tkStubsPtr->tk_SetGrid) /* 163 */ +#endif +#ifndef Tk_SetInternalBorder +#define Tk_SetInternalBorder \ + (tkStubsPtr->tk_SetInternalBorder) /* 164 */ +#endif +#ifndef Tk_SetWindowBackground +#define Tk_SetWindowBackground \ + (tkStubsPtr->tk_SetWindowBackground) /* 165 */ +#endif +#ifndef Tk_SetWindowBackgroundPixmap +#define Tk_SetWindowBackgroundPixmap \ + (tkStubsPtr->tk_SetWindowBackgroundPixmap) /* 166 */ +#endif +#ifndef Tk_SetWindowBorder +#define Tk_SetWindowBorder \ + (tkStubsPtr->tk_SetWindowBorder) /* 167 */ +#endif +#ifndef Tk_SetWindowBorderWidth +#define Tk_SetWindowBorderWidth \ + (tkStubsPtr->tk_SetWindowBorderWidth) /* 168 */ +#endif +#ifndef Tk_SetWindowBorderPixmap +#define Tk_SetWindowBorderPixmap \ + (tkStubsPtr->tk_SetWindowBorderPixmap) /* 169 */ +#endif +#ifndef Tk_SetWindowColormap +#define Tk_SetWindowColormap \ + (tkStubsPtr->tk_SetWindowColormap) /* 170 */ +#endif +#ifndef Tk_SetWindowVisual +#define Tk_SetWindowVisual \ + (tkStubsPtr->tk_SetWindowVisual) /* 171 */ +#endif +#ifndef Tk_SizeOfBitmap +#define Tk_SizeOfBitmap \ + (tkStubsPtr->tk_SizeOfBitmap) /* 172 */ +#endif +#ifndef Tk_SizeOfImage +#define Tk_SizeOfImage \ + (tkStubsPtr->tk_SizeOfImage) /* 173 */ +#endif +#ifndef Tk_StrictMotif +#define Tk_StrictMotif \ + (tkStubsPtr->tk_StrictMotif) /* 174 */ +#endif +#ifndef Tk_TextLayoutToPostscript +#define Tk_TextLayoutToPostscript \ + (tkStubsPtr->tk_TextLayoutToPostscript) /* 175 */ +#endif +#ifndef Tk_TextWidth +#define Tk_TextWidth \ + (tkStubsPtr->tk_TextWidth) /* 176 */ +#endif +#ifndef Tk_UndefineCursor +#define Tk_UndefineCursor \ + (tkStubsPtr->tk_UndefineCursor) /* 177 */ +#endif +#ifndef Tk_UnderlineChars +#define Tk_UnderlineChars \ + (tkStubsPtr->tk_UnderlineChars) /* 178 */ +#endif +#ifndef Tk_UnderlineTextLayout +#define Tk_UnderlineTextLayout \ + (tkStubsPtr->tk_UnderlineTextLayout) /* 179 */ +#endif +#ifndef Tk_Ungrab +#define Tk_Ungrab \ + (tkStubsPtr->tk_Ungrab) /* 180 */ +#endif +#ifndef Tk_UnmaintainGeometry +#define Tk_UnmaintainGeometry \ + (tkStubsPtr->tk_UnmaintainGeometry) /* 181 */ +#endif +#ifndef Tk_UnmapWindow +#define Tk_UnmapWindow \ + (tkStubsPtr->tk_UnmapWindow) /* 182 */ +#endif +#ifndef Tk_UnsetGrid +#define Tk_UnsetGrid \ + (tkStubsPtr->tk_UnsetGrid) /* 183 */ +#endif +#ifndef Tk_UpdatePointer +#define Tk_UpdatePointer \ + (tkStubsPtr->tk_UpdatePointer) /* 184 */ +#endif +#ifndef Tk_AllocBitmapFromObj +#define Tk_AllocBitmapFromObj \ + (tkStubsPtr->tk_AllocBitmapFromObj) /* 185 */ +#endif +#ifndef Tk_Alloc3DBorderFromObj +#define Tk_Alloc3DBorderFromObj \ + (tkStubsPtr->tk_Alloc3DBorderFromObj) /* 186 */ +#endif +#ifndef Tk_AllocColorFromObj +#define Tk_AllocColorFromObj \ + (tkStubsPtr->tk_AllocColorFromObj) /* 187 */ +#endif +#ifndef Tk_AllocCursorFromObj +#define Tk_AllocCursorFromObj \ + (tkStubsPtr->tk_AllocCursorFromObj) /* 188 */ +#endif +#ifndef Tk_AllocFontFromObj +#define Tk_AllocFontFromObj \ + (tkStubsPtr->tk_AllocFontFromObj) /* 189 */ +#endif +#ifndef Tk_CreateOptionTable +#define Tk_CreateOptionTable \ + (tkStubsPtr->tk_CreateOptionTable) /* 190 */ +#endif +#ifndef Tk_DeleteOptionTable +#define Tk_DeleteOptionTable \ + (tkStubsPtr->tk_DeleteOptionTable) /* 191 */ +#endif +#ifndef Tk_Free3DBorderFromObj +#define Tk_Free3DBorderFromObj \ + (tkStubsPtr->tk_Free3DBorderFromObj) /* 192 */ +#endif +#ifndef Tk_FreeBitmapFromObj +#define Tk_FreeBitmapFromObj \ + (tkStubsPtr->tk_FreeBitmapFromObj) /* 193 */ +#endif +#ifndef Tk_FreeColorFromObj +#define Tk_FreeColorFromObj \ + (tkStubsPtr->tk_FreeColorFromObj) /* 194 */ +#endif +#ifndef Tk_FreeConfigOptions +#define Tk_FreeConfigOptions \ + (tkStubsPtr->tk_FreeConfigOptions) /* 195 */ +#endif +#ifndef Tk_FreeSavedOptions +#define Tk_FreeSavedOptions \ + (tkStubsPtr->tk_FreeSavedOptions) /* 196 */ +#endif +#ifndef Tk_FreeCursorFromObj +#define Tk_FreeCursorFromObj \ + (tkStubsPtr->tk_FreeCursorFromObj) /* 197 */ +#endif +#ifndef Tk_FreeFontFromObj +#define Tk_FreeFontFromObj \ + (tkStubsPtr->tk_FreeFontFromObj) /* 198 */ +#endif +#ifndef Tk_Get3DBorderFromObj +#define Tk_Get3DBorderFromObj \ + (tkStubsPtr->tk_Get3DBorderFromObj) /* 199 */ +#endif +#ifndef Tk_GetAnchorFromObj +#define Tk_GetAnchorFromObj \ + (tkStubsPtr->tk_GetAnchorFromObj) /* 200 */ +#endif +#ifndef Tk_GetBitmapFromObj +#define Tk_GetBitmapFromObj \ + (tkStubsPtr->tk_GetBitmapFromObj) /* 201 */ +#endif +#ifndef Tk_GetColorFromObj +#define Tk_GetColorFromObj \ + (tkStubsPtr->tk_GetColorFromObj) /* 202 */ +#endif +#ifndef Tk_GetCursorFromObj +#define Tk_GetCursorFromObj \ + (tkStubsPtr->tk_GetCursorFromObj) /* 203 */ +#endif +#ifndef Tk_GetOptionInfo +#define Tk_GetOptionInfo \ + (tkStubsPtr->tk_GetOptionInfo) /* 204 */ +#endif +#ifndef Tk_GetOptionValue +#define Tk_GetOptionValue \ + (tkStubsPtr->tk_GetOptionValue) /* 205 */ +#endif +#ifndef Tk_GetJustifyFromObj +#define Tk_GetJustifyFromObj \ + (tkStubsPtr->tk_GetJustifyFromObj) /* 206 */ +#endif +#ifndef Tk_GetMMFromObj +#define Tk_GetMMFromObj \ + (tkStubsPtr->tk_GetMMFromObj) /* 207 */ +#endif +#ifndef Tk_GetPixelsFromObj +#define Tk_GetPixelsFromObj \ + (tkStubsPtr->tk_GetPixelsFromObj) /* 208 */ +#endif +#ifndef Tk_GetReliefFromObj +#define Tk_GetReliefFromObj \ + (tkStubsPtr->tk_GetReliefFromObj) /* 209 */ +#endif +#ifndef Tk_GetScrollInfoObj +#define Tk_GetScrollInfoObj \ + (tkStubsPtr->tk_GetScrollInfoObj) /* 210 */ +#endif +#ifndef Tk_InitOptions +#define Tk_InitOptions \ + (tkStubsPtr->tk_InitOptions) /* 211 */ +#endif +#ifndef Tk_MainEx +#define Tk_MainEx \ + (tkStubsPtr->tk_MainEx) /* 212 */ +#endif +#ifndef Tk_RestoreSavedOptions +#define Tk_RestoreSavedOptions \ + (tkStubsPtr->tk_RestoreSavedOptions) /* 213 */ +#endif +#ifndef Tk_SetOptions +#define Tk_SetOptions \ + (tkStubsPtr->tk_SetOptions) /* 214 */ +#endif +#ifndef Tk_InitConsoleChannels +#define Tk_InitConsoleChannels \ + (tkStubsPtr->tk_InitConsoleChannels) /* 215 */ +#endif +#ifndef Tk_CreateConsoleWindow +#define Tk_CreateConsoleWindow \ + (tkStubsPtr->tk_CreateConsoleWindow) /* 216 */ +#endif +#ifndef Tk_CreateSmoothMethod +#define Tk_CreateSmoothMethod \ + (tkStubsPtr->tk_CreateSmoothMethod) /* 217 */ +#endif +/* Slot 218 is reserved */ +/* Slot 219 is reserved */ +#ifndef Tk_GetDash +#define Tk_GetDash \ + (tkStubsPtr->tk_GetDash) /* 220 */ +#endif +#ifndef Tk_CreateOutline +#define Tk_CreateOutline \ + (tkStubsPtr->tk_CreateOutline) /* 221 */ +#endif +#ifndef Tk_DeleteOutline +#define Tk_DeleteOutline \ + (tkStubsPtr->tk_DeleteOutline) /* 222 */ +#endif +#ifndef Tk_ConfigOutlineGC +#define Tk_ConfigOutlineGC \ + (tkStubsPtr->tk_ConfigOutlineGC) /* 223 */ +#endif +#ifndef Tk_ChangeOutlineGC +#define Tk_ChangeOutlineGC \ + (tkStubsPtr->tk_ChangeOutlineGC) /* 224 */ +#endif +#ifndef Tk_ResetOutlineGC +#define Tk_ResetOutlineGC \ + (tkStubsPtr->tk_ResetOutlineGC) /* 225 */ +#endif +#ifndef Tk_CanvasPsOutline +#define Tk_CanvasPsOutline \ + (tkStubsPtr->tk_CanvasPsOutline) /* 226 */ +#endif +#ifndef Tk_SetTSOrigin +#define Tk_SetTSOrigin \ + (tkStubsPtr->tk_SetTSOrigin) /* 227 */ +#endif +#ifndef Tk_CanvasGetCoordFromObj +#define Tk_CanvasGetCoordFromObj \ + (tkStubsPtr->tk_CanvasGetCoordFromObj) /* 228 */ +#endif +#ifndef Tk_CanvasSetOffset +#define Tk_CanvasSetOffset \ + (tkStubsPtr->tk_CanvasSetOffset) /* 229 */ +#endif +#ifndef Tk_DitherPhoto +#define Tk_DitherPhoto \ + (tkStubsPtr->tk_DitherPhoto) /* 230 */ +#endif +#ifndef Tk_PostscriptBitmap +#define Tk_PostscriptBitmap \ + (tkStubsPtr->tk_PostscriptBitmap) /* 231 */ +#endif +#ifndef Tk_PostscriptColor +#define Tk_PostscriptColor \ + (tkStubsPtr->tk_PostscriptColor) /* 232 */ +#endif +#ifndef Tk_PostscriptFont +#define Tk_PostscriptFont \ + (tkStubsPtr->tk_PostscriptFont) /* 233 */ +#endif +#ifndef Tk_PostscriptImage +#define Tk_PostscriptImage \ + (tkStubsPtr->tk_PostscriptImage) /* 234 */ +#endif +#ifndef Tk_PostscriptPath +#define Tk_PostscriptPath \ + (tkStubsPtr->tk_PostscriptPath) /* 235 */ +#endif +#ifndef Tk_PostscriptStipple +#define Tk_PostscriptStipple \ + (tkStubsPtr->tk_PostscriptStipple) /* 236 */ +#endif +#ifndef Tk_PostscriptY +#define Tk_PostscriptY \ + (tkStubsPtr->tk_PostscriptY) /* 237 */ +#endif +#ifndef Tk_PostscriptPhoto +#define Tk_PostscriptPhoto \ + (tkStubsPtr->tk_PostscriptPhoto) /* 238 */ +#endif + +#endif /* defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) */ + +/* !END!: Do not edit above this line. */ + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#endif /* _TKDECLS */ + + diff --git a/tk/generic/tkEntry.c b/tk/generic/tkEntry.c index 86da2fd92e2..6ed11d6f9b7 100644 --- a/tk/generic/tkEntry.c +++ b/tk/generic/tkEntry.c @@ -6,7 +6,7 @@ * the string to be edited. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -32,6 +32,9 @@ typedef struct { * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with entry. */ Tcl_Command widgetCmd; /* Token for entry's widget command. */ + Tk_OptionTable optionTable; /* Table that defines configuration options + * available for this widget. */ + /* * Fields that are set by widget commands other than "configure". @@ -39,17 +42,17 @@ typedef struct { char *string; /* Pointer to storage for string; * NULL-terminated; malloc-ed. */ - int insertPos; /* Index of character before which next - * typed character will be inserted. */ + int insertPos; /* Character index before which next typed + * character will be inserted. */ /* * Information about what's selected, if any. */ - int selectFirst; /* Index of first selected character (-1 means - * nothing selected. */ - int selectLast; /* Index of last selected character (-1 means - * nothing selected. */ + int selectFirst; /* Character index of first selected + * character (-1 means nothing selected. */ + int selectLast; /* Character index just after last selected + * character (-1 means nothing selected. */ int selectAnchor; /* Fixed end of selection (i.e. "select to" * operation will use this as one end of the * selection). */ @@ -60,8 +63,8 @@ typedef struct { int scanMarkX; /* X-position at which scan started (e.g. * button was pressed here). */ - int scanMarkIndex; /* Index of character that was at left of - * window when scan started. */ + int scanMarkIndex; /* Character index of character that was at + * left of window when scan started. */ /* * Configuration settings that are updated by Tk_ConfigureWidget. @@ -99,7 +102,7 @@ typedef struct { char *showChar; /* Value of -show option. If non-NULL, first * character is used for displaying all * characters in entry. Malloc'ed. */ - Tk_Uid state; /* Normal or disabled. Entry is read-only + int state; /* Normal or disabled. Entry is read-only * when disabled. */ char *textVarName; /* Name of variable (malloc'ed) or NULL. * If non-NULL, entry's string tracks the @@ -118,20 +121,27 @@ typedef struct { * configuration settings above. */ - int numChars; /* Number of non-NULL characters in - * string (may be 0). */ - char *displayString; /* If non-NULL, points to string with same + int numBytes; /* Length of string in bytes. */ + int numChars; /* Length of string in characters. Both + * string and displayString have the same + * character length, but may have different + * byte lengths due to being made from + * different UTF-8 characters. */ + char *displayString; /* String to use when displaying. This may + * be a pointer to string, or a pointer to + * malloced memory with the same character * length as string but whose characters - * are all equal to showChar. Malloc'ed. */ + * are all equal to showChar. */ + int numDisplayBytes; /* Length of displayString in bytes. */ int inset; /* Number of pixels on the left and right * sides that are taken up by XPAD, borderWidth * (if any), and highlightWidth (if any). */ Tk_TextLayout textLayout; /* Cached text layout information. */ int layoutX, layoutY; /* Origin for layout. */ - int leftIndex; /* Index of left-most character visible in - * window. */ int leftX; /* X position at which character at leftIndex * is drawn (varies depending on justify). */ + int leftIndex; /* Character index of left-most character + * visible in window. */ Tcl_TimerToken insertBlinkHandler; /* Timer handler used to blink cursor on and * off. */ @@ -141,6 +151,14 @@ typedef struct { int avgWidth; /* Width of average character. */ int flags; /* Miscellaneous flags; see below for * definitions. */ + Tk_TSOffset tsoffset; + + char *validateCmd; /* Command prefix to use when invoking + * validate command. NULL means don't + * invoke commands. Malloc'ed. */ + int validate; /* Non-zero means try to validate */ + char *invalidCmd; /* Command called when a validation returns 0 + * (successfully fails), defaults to {}. */ } Entry; /* @@ -159,6 +177,12 @@ typedef struct { * UPDATE_SCROLLBAR: Non-zero means scrollbar should be updated * during next redisplay operation. * GOT_SELECTION: Non-zero means we've claimed the selection. + * ENTRY_DELETED: This entry has been effectively destroyed. + * VALIDATING: Non-zero means we are in a validateCmd + * VALIDATE_VAR: Non-zero means we are attempting to validate + * the entry's textvariable with validateCmd + * VALIDATE_ABORT: Non-zero if validatecommand signals an abort + * for current procedure and make no changes */ #define REDRAW_PENDING 1 @@ -167,6 +191,10 @@ typedef struct { #define GOT_FOCUS 8 #define UPDATE_SCROLLBAR 0x10 #define GOT_SELECTION 0x20 +#define ENTRY_DELETED 0x40 +#define VALIDATING 0x80 +#define VALIDATE_VAR 0x100 +#define VALIDATE_ABORT 0x200 /* * The following macro defines how many extra pixels to leave on each @@ -177,93 +205,139 @@ typedef struct { #define YPAD 1 /* + * The following enum is used to define a type for the -state option + * of the Entry widget. These values are used as indices into the + * string table below. + */ + +enum state { + STATE_DISABLED, STATE_NORMAL +}; + +static char *stateStrings[] = { + "disabled", "normal", (char *) NULL +}; + +/* + * Definitions for -validate option values: + */ + +static char *validateStrings[] = { + "all", "key", "focus", "focusin", "focusout", "none", (char *) NULL +}; +enum validateType { + VALIDATE_ALL, VALIDATE_KEY, VALIDATE_FOCUS, + VALIDATE_FOCUSIN, VALIDATE_FOCUSOUT, VALIDATE_NONE, + /* + * These extra enums are for use with EntryValidateChange + */ + VALIDATE_FORCED, VALIDATE_DELETE, VALIDATE_INSERT +}; +#define DEF_ENTRY_VALIDATE "none" +#define DEF_ENTRY_INVALIDCMD "" + +/* * Information used for argv parsing. */ -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_ENTRY_BG_COLOR, Tk_Offset(Entry, normalBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_ENTRY_BG_MONO, Tk_Offset(Entry, normalBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_ENTRY_BORDER_WIDTH, Tk_Offset(Entry, borderWidth), 0}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_ENTRY_CURSOR, Tk_Offset(Entry, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection", - "ExportSelection", DEF_ENTRY_EXPORT_SELECTION, - Tk_Offset(Entry, exportSelection), 0}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_ENTRY_FONT, Tk_Offset(Entry, tkfont), 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_ENTRY_FG, Tk_Offset(Entry, fgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_BORDER, "-background", "background", "Background", + DEF_ENTRY_BG_COLOR, -1, Tk_Offset(Entry, normalBorder), + 0, (ClientData) DEF_ENTRY_BG_MONO, 0}, + {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + DEF_ENTRY_BORDER_WIDTH, -1, Tk_Offset(Entry, borderWidth), + 0, 0, 0}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + DEF_ENTRY_CURSOR, -1, Tk_Offset(Entry, cursor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BOOLEAN, "-exportselection", "exportSelection", + "ExportSelection", DEF_ENTRY_EXPORT_SELECTION, -1, + Tk_Offset(Entry, exportSelection), 0, 0, 0}, + {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + DEF_ENTRY_FONT, -1, Tk_Offset(Entry, tkfont), 0, 0, 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + DEF_ENTRY_FG, -1, Tk_Offset(Entry, fgColorPtr), 0, + 0, 0}, + {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_ENTRY_HIGHLIGHT_BG, - Tk_Offset(Entry, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_ENTRY_HIGHLIGHT, Tk_Offset(Entry, highlightColorPtr), 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_ENTRY_HIGHLIGHT_WIDTH, Tk_Offset(Entry, highlightWidth), 0}, - {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground", - DEF_ENTRY_INSERT_BG, Tk_Offset(Entry, insertBorder), 0}, - {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth", - DEF_ENTRY_INSERT_BD_COLOR, Tk_Offset(Entry, insertBorderWidth), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth", - DEF_ENTRY_INSERT_BD_MONO, Tk_Offset(Entry, insertBorderWidth), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime", - DEF_ENTRY_INSERT_OFF_TIME, Tk_Offset(Entry, insertOffTime), 0}, - {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime", - DEF_ENTRY_INSERT_ON_TIME, Tk_Offset(Entry, insertOnTime), 0}, - {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", - DEF_ENTRY_INSERT_WIDTH, Tk_Offset(Entry, insertWidth), 0}, - {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", - DEF_ENTRY_JUSTIFY, Tk_Offset(Entry, justify), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_ENTRY_RELIEF, Tk_Offset(Entry, relief), 0}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_ENTRY_SELECT_COLOR, Tk_Offset(Entry, selBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_ENTRY_SELECT_MONO, Tk_Offset(Entry, selBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth", - DEF_ENTRY_SELECT_BD_COLOR, Tk_Offset(Entry, selBorderWidth), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth", - DEF_ENTRY_SELECT_BD_MONO, Tk_Offset(Entry, selBorderWidth), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_ENTRY_SELECT_FG_COLOR, Tk_Offset(Entry, selFgColorPtr), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_ENTRY_SELECT_FG_MONO, Tk_Offset(Entry, selFgColorPtr), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_STRING, "-show", "show", "Show", - DEF_ENTRY_SHOW, Tk_Offset(Entry, showChar), TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-state", "state", "State", - DEF_ENTRY_STATE, Tk_Offset(Entry, state), 0}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_ENTRY_TAKE_FOCUS, Tk_Offset(Entry, takeFocus), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable", - DEF_ENTRY_TEXT_VARIABLE, Tk_Offset(Entry, textVarName), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-width", "width", "Width", - DEF_ENTRY_WIDTH, Tk_Offset(Entry, prefWidth), 0}, - {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", - DEF_ENTRY_SCROLL_COMMAND, Tk_Offset(Entry, scrollCmd), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} + -1, Tk_Offset(Entry, highlightBgColorPtr), + 0, 0, 0}, + {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", + DEF_ENTRY_HIGHLIGHT, -1, Tk_Offset(Entry, highlightColorPtr), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", + "HighlightThickness", DEF_ENTRY_HIGHLIGHT_WIDTH, -1, + Tk_Offset(Entry, highlightWidth), 0, 0, 0}, + {TK_OPTION_BORDER, "-insertbackground", "insertBackground", "Foreground", + DEF_ENTRY_INSERT_BG, + -1, Tk_Offset(Entry, insertBorder), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-insertborderwidth", "insertBorderWidth", + "BorderWidth", DEF_ENTRY_INSERT_BD_COLOR, -1, + Tk_Offset(Entry, insertBorderWidth), 0, + (ClientData) DEF_ENTRY_INSERT_BD_MONO, 0}, + {TK_OPTION_INT, "-insertofftime", "insertOffTime", "OffTime", + DEF_ENTRY_INSERT_OFF_TIME, -1, Tk_Offset(Entry, insertOffTime), + 0, 0, 0}, + {TK_OPTION_INT, "-insertontime", "insertOnTime", "OnTime", + DEF_ENTRY_INSERT_ON_TIME, -1, Tk_Offset(Entry, insertOnTime), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", + DEF_ENTRY_INSERT_WIDTH, -1, Tk_Offset(Entry, insertWidth), + 0, 0, 0}, + {TK_OPTION_STRING, "-invalidcommand", "invalidCommand", "InvalidCommand", + DEF_ENTRY_INVALIDCMD, -1, Tk_Offset(Entry, invalidCmd), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_SYNONYM, "-invcmd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-invalidcommand", 0}, + {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", + DEF_ENTRY_JUSTIFY, -1, Tk_Offset(Entry, justify), 0, 0, 0}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + DEF_ENTRY_RELIEF, -1, Tk_Offset(Entry, relief), + 0, 0, 0}, + {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground", + DEF_ENTRY_SELECT_COLOR, -1, Tk_Offset(Entry, selBorder), + 0, (ClientData) DEF_ENTRY_SELECT_MONO, 0}, + {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth", + "BorderWidth", DEF_ENTRY_SELECT_BD_COLOR, -1, + Tk_Offset(Entry, selBorderWidth), + 0, (ClientData) DEF_ENTRY_SELECT_BD_MONO, 0}, + {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background", + DEF_ENTRY_SELECT_FG_COLOR, -1, Tk_Offset(Entry, selFgColorPtr), + 0, (ClientData) DEF_ENTRY_SELECT_FG_MONO, 0}, + {TK_OPTION_STRING, "-show", "show", "Show", + DEF_ENTRY_SHOW, -1, Tk_Offset(Entry, showChar), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", "state", "State", + DEF_ENTRY_STATE, -1, Tk_Offset(Entry, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + DEF_ENTRY_TAKE_FOCUS, -1, Tk_Offset(Entry, takeFocus), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", + DEF_ENTRY_TEXT_VARIABLE, -1, Tk_Offset(Entry, textVarName), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-validate", "validate", "Validate", + DEF_ENTRY_VALIDATE, -1, Tk_Offset(Entry, validate), + 0, (ClientData) validateStrings, 0}, + {TK_OPTION_STRING, "-validatecommand", "validateCommand", "ValidateCommand", + (char *) NULL, -1, Tk_Offset(Entry, validateCmd), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_SYNONYM, "-vcmd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-validatecommand", 0}, + {TK_OPTION_INT, "-width", "width", "Width", + DEF_ENTRY_WIDTH, -1, Tk_Offset(Entry, prefWidth), 0, 0, 0}, + {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", + DEF_ENTRY_SCROLL_COMMAND, -1, Tk_Offset(Entry, scrollCmd), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, 0, 0} }; /* @@ -274,12 +348,38 @@ static Tk_ConfigSpec configSpecs[] = { #define LAST_PLUS_ONE_OK 2 /* + * The following tables define the entry widget commands (and sub- + * commands) and map the indexes into the string tables into + * enumerated types used to dispatch the entry widget command. + */ + +static char *commandNames[] = { + "bbox", "cget", "configure", "delete", "get", "icursor", "index", + "insert", "scan", "selection", "validate", "xview", (char *) NULL +}; + +enum command { + COMMAND_BBOX, COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DELETE, + COMMAND_GET, COMMAND_ICURSOR, COMMAND_INDEX, COMMAND_INSERT, + COMMAND_SCAN, COMMAND_SELECTION, COMMAND_VALIDATE, COMMAND_XVIEW +}; + +static char *selCommandNames[] = { + "adjust", "clear", "from", "present", "range", "to", (char *) NULL +}; + +enum selcommand { + SELECTION_ADJUST, SELECTION_CLEAR, SELECTION_FROM, + SELECTION_PRESENT, SELECTION_RANGE, SELECTION_TO +}; + +/* * Forward declarations for procedures defined later in this file: */ static int ConfigureEntry _ANSI_ARGS_((Tcl_Interp *interp, - Entry *entryPtr, int argc, char **argv, - int flags)); + Entry *entryPtr, int objc, + Tcl_Obj *CONST objv[], int flags)); static void DeleteChars _ANSI_ARGS_((Entry *entryPtr, int index, int count)); static void DestroyEntry _ANSI_ARGS_((char *memPtr)); @@ -306,11 +406,19 @@ static char * EntryTextVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)); static void EntryUpdateScrollbar _ANSI_ARGS_((Entry *entryPtr)); +static int EntryValidate _ANSI_ARGS_((Entry *entryPtr, + char *cmd)); +static int EntryValidateChange _ANSI_ARGS_((Entry *entryPtr, + char *change, char *new, int index, int type)); +static void ExpandPercents _ANSI_ARGS_((Entry *entryPtr, + char *before, char *change, char *new, + int index, int type, Tcl_DString *dsPtr)); static void EntryValueChanged _ANSI_ARGS_((Entry *entryPtr)); static void EntryVisibleRange _ANSI_ARGS_((Entry *entryPtr, double *firstPtr, double *lastPtr)); -static int EntryWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); +static int EntryWidgetObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); static void EntryWorldChanged _ANSI_ARGS_(( ClientData instanceData)); static int GetEntryIndex _ANSI_ARGS_((Tcl_Interp *interp, @@ -333,7 +441,7 @@ static TkClassProcs entryClass = { /* *-------------------------------------------------------------- * - * Tk_EntryCmd -- + * Tk_EntryObjCmd -- * * This procedure is invoked to process the "entry" Tcl * command. See the user documentation for details on what @@ -349,25 +457,43 @@ static TkClassProcs entryClass = { */ int -Tk_EntryCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ +Tk_EntryObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Either NULL or pointer to option table. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - Tk_Window tkwin = (Tk_Window) clientData; register Entry *entryPtr; - Tk_Window new; + Tk_OptionTable optionTable; + Tk_Window tkwin; + + optionTable = (Tk_OptionTable) clientData; + if (optionTable == NULL) { + Tcl_CmdInfo info; + char *name; + + /* + * We haven't created the option table for this widget class + * yet. Do it now and save the table as the clientData for + * the command, so we'll have access to it in future + * invocations of the command. + */ + + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + name = Tcl_GetString(objv[0]); + Tcl_GetCommandInfo(interp, name, &info); + info.objClientData = (ClientData) optionTable; + Tcl_SetCommandInfo(interp, name, &info); + } - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { + tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), + Tcl_GetString(objv[1]), (char *) NULL); + if (tkwin == NULL) { return TCL_ERROR; } @@ -377,62 +503,67 @@ Tk_EntryCmd(clientData, interp, argc, argv) * initialized already (e.g. resource pointers). */ - entryPtr = (Entry *) ckalloc(sizeof(Entry)); - entryPtr->tkwin = new; - entryPtr->display = Tk_Display(new); - entryPtr->interp = interp; - entryPtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(entryPtr->tkwin), EntryWidgetCmd, + entryPtr = (Entry *) ckalloc(sizeof(Entry)); + entryPtr->tkwin = tkwin; + entryPtr->display = Tk_Display(tkwin); + entryPtr->interp = interp; + entryPtr->widgetCmd = Tcl_CreateObjCommand(interp, + Tk_PathName(entryPtr->tkwin), EntryWidgetObjCmd, (ClientData) entryPtr, EntryCmdDeletedProc); - entryPtr->string = (char *) ckalloc(1); - entryPtr->string[0] = '\0'; - entryPtr->insertPos = 0; - entryPtr->selectFirst = -1; - entryPtr->selectLast = -1; - entryPtr->selectAnchor = 0; - entryPtr->scanMarkX = 0; - entryPtr->scanMarkIndex = 0; - - entryPtr->normalBorder = NULL; - entryPtr->borderWidth = 0; - entryPtr->cursor = None; - entryPtr->exportSelection = 1; - entryPtr->tkfont = NULL; - entryPtr->fgColorPtr = NULL; - entryPtr->highlightBgColorPtr = NULL; - entryPtr->highlightColorPtr = NULL; - entryPtr->highlightWidth = 0; - entryPtr->insertBorder = NULL; - entryPtr->insertBorderWidth = 0; - entryPtr->insertOffTime = 0; - entryPtr->insertOnTime = 0; - entryPtr->insertWidth = 0; - entryPtr->justify = TK_JUSTIFY_LEFT; - entryPtr->relief = TK_RELIEF_FLAT; - entryPtr->selBorder = NULL; - entryPtr->selBorderWidth = 0; - entryPtr->selFgColorPtr = NULL; - entryPtr->showChar = NULL; - entryPtr->state = tkNormalUid; - entryPtr->textVarName = NULL; - entryPtr->takeFocus = NULL; - entryPtr->prefWidth = 0; - entryPtr->scrollCmd = NULL; - - entryPtr->numChars = 0; - entryPtr->displayString = NULL; - entryPtr->inset = XPAD; - entryPtr->textLayout = NULL; - entryPtr->layoutX = 0; - entryPtr->layoutY = 0; - entryPtr->leftIndex = 0; - entryPtr->leftX = 0; - entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; - entryPtr->textGC = None; - entryPtr->selTextGC = None; - entryPtr->highlightGC = None; - entryPtr->avgWidth = 1; - entryPtr->flags = 0; + entryPtr->optionTable = optionTable; + entryPtr->string = (char *) ckalloc(1); + entryPtr->string[0] = '\0'; + entryPtr->insertPos = 0; + entryPtr->selectFirst = -1; + entryPtr->selectLast = -1; + entryPtr->selectAnchor = 0; + entryPtr->scanMarkX = 0; + entryPtr->scanMarkIndex = 0; + + entryPtr->normalBorder = NULL; + entryPtr->borderWidth = 0; + entryPtr->cursor = None; + entryPtr->exportSelection = 1; + entryPtr->tkfont = NULL; + entryPtr->fgColorPtr = NULL; + entryPtr->highlightBgColorPtr = NULL; + entryPtr->highlightColorPtr = NULL; + entryPtr->highlightWidth = 0; + entryPtr->insertBorder = NULL; + entryPtr->insertBorderWidth = 0; + entryPtr->insertOffTime = 0; + entryPtr->insertOnTime = 0; + entryPtr->insertWidth = 0; + entryPtr->justify = TK_JUSTIFY_LEFT; + entryPtr->relief = TK_RELIEF_FLAT; + entryPtr->selBorder = NULL; + entryPtr->selBorderWidth = 0; + entryPtr->selFgColorPtr = NULL; + entryPtr->showChar = NULL; + entryPtr->state = STATE_NORMAL; + entryPtr->textVarName = NULL; + entryPtr->takeFocus = NULL; + entryPtr->prefWidth = 0; + entryPtr->scrollCmd = NULL; + entryPtr->numBytes = 0; + entryPtr->numChars = 0; + entryPtr->displayString = entryPtr->string; + entryPtr->numDisplayBytes = 0; + entryPtr->inset = XPAD; + entryPtr->textLayout = NULL; + entryPtr->layoutX = 0; + entryPtr->layoutY = 0; + entryPtr->leftX = 0; + entryPtr->leftIndex = 0; + entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; + entryPtr->textGC = None; + entryPtr->selTextGC = None; + entryPtr->highlightGC = None; + entryPtr->avgWidth = 1; + entryPtr->flags = 0; + entryPtr->validateCmd = NULL; + entryPtr->validate = VALIDATE_NONE; + entryPtr->invalidCmd = NULL; Tk_SetClass(entryPtr->tkwin, "Entry"); TkSetClassProcs(entryPtr->tkwin, &entryClass, (ClientData) entryPtr); @@ -441,22 +572,22 @@ Tk_EntryCmd(clientData, interp, argc, argv) EntryEventProc, (ClientData) entryPtr); Tk_CreateSelHandler(entryPtr->tkwin, XA_PRIMARY, XA_STRING, EntryFetchSelection, (ClientData) entryPtr, XA_STRING); - if (ConfigureEntry(interp, entryPtr, argc-2, argv+2, 0) != TCL_OK) { - goto error; - } - interp->result = Tk_PathName(entryPtr->tkwin); + if ((Tk_InitOptions(interp, (char *) entryPtr, optionTable, tkwin) + != TCL_OK) || + (ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0) != TCL_OK)) { + Tk_DestroyWindow(entryPtr->tkwin); + return TCL_ERROR; + } + + Tcl_SetResult(interp, Tk_PathName(entryPtr->tkwin), TCL_STATIC); return TCL_OK; - - error: - Tk_DestroyWindow(entryPtr->tkwin); - return TCL_ERROR; } /* *-------------------------------------------------------------- * - * EntryWidgetCmd -- + * EntryWidgetObjCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a widget managed by this module. @@ -472,321 +603,414 @@ Tk_EntryCmd(clientData, interp, argc, argv) */ static int -EntryWidgetCmd(clientData, interp, argc, argv) - ClientData clientData; /* Information about entry widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ +EntryWidgetObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Information about entry widget. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - register Entry *entryPtr = (Entry *) clientData; - int result = TCL_OK; - size_t length; - int c; + Entry *entryPtr = (Entry *) clientData; + int cmdIndex, selIndex, result; + Tcl_Obj *objPtr; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } Tcl_Preserve((ClientData) entryPtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) { - int index; - int x, y, width, height; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " bbox index\"", - (char *) NULL); - goto error; - } - if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) { - goto error; - } - if ((index == entryPtr->numChars) && (index > 0)) { - index--; - } - Tk_CharBbox(entryPtr->textLayout, index, &x, &y, &width, &height); - sprintf(interp->result, "%d %d %d %d", - x + entryPtr->layoutX, y + entryPtr->layoutY, width, height); - } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, entryPtr->tkwin, configSpecs, - (char *) entryPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, entryPtr->tkwin, configSpecs, - (char *) entryPtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, entryPtr->tkwin, configSpecs, - (char *) entryPtr, argv[2], 0); - } else { - result = ConfigureEntry(interp, entryPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) { - int first, last; - - if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " delete firstIndex ?lastIndex?\"", - (char *) NULL); - goto error; - } - if (GetEntryIndex(interp, entryPtr, argv[2], &first) != TCL_OK) { - goto error; - } - if (argc == 3) { - last = first+1; - } else { - if (GetEntryIndex(interp, entryPtr, argv[3], &last) != TCL_OK) { + + /* + * Parse the widget command by looking up the second token in + * the list of valid command names. + */ + + result = Tcl_GetIndexFromObj(interp, objv[1], commandNames, + "option", 0, &cmdIndex); + if (result != TCL_OK) { + return result; + } + + switch (cmdIndex) { + case COMMAND_BBOX: { + int index, x, y, width, height; + char buf[TCL_INTEGER_SPACE * 4]; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index"); goto error; } - } - if ((last >= first) && (entryPtr->state == tkNormalUid)) { - DeleteChars(entryPtr, first, last-first); - } - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " get\"", (char *) NULL); - goto error; - } - interp->result = entryPtr->string; - } else if ((c == 'i') && (strncmp(argv[1], "icursor", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " icursor pos\"", - (char *) NULL); - goto error; - } - if (GetEntryIndex(interp, entryPtr, argv[2], &entryPtr->insertPos) - != TCL_OK) { - goto error; - } - EventuallyRedraw(entryPtr); - } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0) - && (length >= 3)) { - int index; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " index string\"", (char *) NULL); - goto error; - } - if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) { - goto error; - } - sprintf(interp->result, "%d", index); - } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0) - && (length >= 3)) { - int index; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " insert index text\"", - (char *) NULL); - goto error; - } - if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) { - goto error; - } - if (entryPtr->state == tkNormalUid) { - InsertChars(entryPtr, index, argv[3]); - } - } else if ((c == 's') && (length >= 2) - && (strncmp(argv[1], "scan", length) == 0)) { - int x; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scan mark|dragto x\"", (char *) NULL); - goto error; - } - if (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) { - goto error; - } - if ((argv[2][0] == 'm') - && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) { - entryPtr->scanMarkX = x; - entryPtr->scanMarkIndex = entryPtr->leftIndex; - } else if ((argv[2][0] == 'd') - && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) { - EntryScanTo(entryPtr, x); - } else { - Tcl_AppendResult(interp, "bad scan option \"", argv[2], - "\": must be mark or dragto", (char *) NULL); - goto error; - } - } else if ((c == 's') && (length >= 2) - && (strncmp(argv[1], "selection", length) == 0)) { - int index, index2; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " select option ?index?\"", (char *) NULL); - goto error; - } - length = strlen(argv[2]); - c = argv[2][0]; - if ((c == 'c') && (strncmp(argv[2], "clear", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection clear\"", (char *) NULL); - goto error; + if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]), + &index) != TCL_OK) { + goto error; } - if (entryPtr->selectFirst != -1) { - entryPtr->selectFirst = entryPtr->selectLast = -1; - EventuallyRedraw(entryPtr); + if ((index == entryPtr->numChars) && (index > 0)) { + index--; } - goto done; - } else if ((c == 'p') && (strncmp(argv[2], "present", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection present\"", (char *) NULL); + Tk_CharBbox(entryPtr->textLayout, index, &x, &y, + &width, &height); + sprintf(buf, "%d %d %d %d", x + entryPtr->layoutX, + y + entryPtr->layoutY, width, height); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + break; + } + + case COMMAND_CGET: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); goto error; } - if (entryPtr->selectFirst == -1) { - interp->result = "0"; + + objPtr = Tk_GetOptionValue(interp, (char *) entryPtr, + entryPtr->optionTable, objv[2], entryPtr->tkwin); + if (objPtr == NULL) { + goto error; } else { - interp->result = "1"; + Tcl_SetObjResult(interp, objPtr); } - goto done; + break; } - if (argc >= 4) { - if (GetEntryIndex(interp, entryPtr, argv[3], &index) != TCL_OK) { - goto error; + + case COMMAND_CONFIGURE: { + if (objc <= 3) { + objPtr = Tk_GetOptionInfo(interp, (char *) entryPtr, + entryPtr->optionTable, + (objc == 3) ? objv[2] : (Tcl_Obj *) NULL, + entryPtr->tkwin); + if (objPtr == NULL) { + goto error; + } else { + Tcl_SetObjResult(interp, objPtr); + } + } else { + result = ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0); } + break; } - if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection adjust index\"", - (char *) NULL); + + case COMMAND_DELETE: { + int first, last; + + if ((objc < 3) || (objc > 4)) { + Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?"); goto error; } - if (entryPtr->selectFirst >= 0) { - int half1, half2; - - half1 = (entryPtr->selectFirst + entryPtr->selectLast)/2; - half2 = (entryPtr->selectFirst + entryPtr->selectLast + 1)/2; - if (index < half1) { - entryPtr->selectAnchor = entryPtr->selectLast; - } else if (index > half2) { - entryPtr->selectAnchor = entryPtr->selectFirst; - } else { - /* - * We're at about the halfway point in the selection; - * just keep the existing anchor. - */ + if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]), + &first) != TCL_OK) { + goto error; + } + if (objc == 3) { + last = first + 1; + } else { + if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[3]), + &last) != TCL_OK) { + goto error; } } - EntrySelectTo(entryPtr, index); - } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection from index\"", - (char *) NULL); + if ((last >= first) && (entryPtr->state == STATE_NORMAL)) { + DeleteChars(entryPtr, first, last - first); + } + break; + } + + case COMMAND_GET: { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL); goto error; } - entryPtr->selectAnchor = index; - } else if ((c == 'r') && (strncmp(argv[2], "range", length) == 0)) { - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection range start end\"", - (char *) NULL); + Tcl_SetResult(interp, entryPtr->string, TCL_STATIC); + break; + } + + case COMMAND_ICURSOR: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "pos"); goto error; } - if (GetEntryIndex(interp, entryPtr, argv[4], &index2) != TCL_OK) { + if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]), + &entryPtr->insertPos) != TCL_OK) { + goto error; + } + EventuallyRedraw(entryPtr); + break; + } + + case COMMAND_INDEX: { + int index; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "string"); goto error; } - if (index >= index2) { - entryPtr->selectFirst = entryPtr->selectLast = -1; - } else { - entryPtr->selectFirst = index; - entryPtr->selectLast = index2; + if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]), + &index) != TCL_OK) { + goto error; } - if (!(entryPtr->flags & GOT_SELECTION) - && (entryPtr->exportSelection)) { - Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, - EntryLostSelection, (ClientData) entryPtr); - entryPtr->flags |= GOT_SELECTION; + Tcl_SetObjResult(interp, Tcl_NewIntObj(index)); + break; + } + + case COMMAND_INSERT: { + int index; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "index text"); + goto error; } - EventuallyRedraw(entryPtr); - } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection to index\"", - (char *) NULL); + if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]), + &index) != TCL_OK) { + goto error; + } + if (entryPtr->state == STATE_NORMAL) { + InsertChars(entryPtr, index, Tcl_GetString(objv[3])); + } + break; + } + + case COMMAND_SCAN: { + int x; + char *minorCmd; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x"); goto error; } - EntrySelectTo(entryPtr, index); - } else { - Tcl_AppendResult(interp, "bad selection option \"", argv[2], - "\": must be adjust, clear, from, present, range, or to", - (char *) NULL); - goto error; + if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) { + goto error; + } + + minorCmd = Tcl_GetString(objv[2]); + if (minorCmd[0] == 'm' + && (strncmp(minorCmd, "mark", strlen(minorCmd)) == 0)) { + entryPtr->scanMarkX = x; + entryPtr->scanMarkIndex = entryPtr->leftIndex; + } else if ((minorCmd[0] == 'd') + && (strncmp(minorCmd, "dragto", strlen(minorCmd)) == 0)) { + EntryScanTo(entryPtr, x); + } else { + Tcl_AppendResult(interp, "bad scan option \"", + Tcl_GetString(objv[2]), "\": must be mark or dragto", + (char *) NULL); + goto error; + } + break; } - } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) { - int index, type, count, charsPerPage; - double fraction, first, last; - - if (argc == 2) { - EntryVisibleRange(entryPtr, &first, &last); - sprintf(interp->result, "%g %g", first, last); - goto done; - } else if (argc == 3) { - if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) { + + case COMMAND_SELECTION: { + int index, index2; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option ?index?"); goto error; } - } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); - index = entryPtr->leftIndex; - switch (type) { - case TK_SCROLL_ERROR: - goto error; - case TK_SCROLL_MOVETO: - index = (int) ((fraction * entryPtr->numChars) + 0.5); + + /* + * Parse the selection sub-command, using the command + * table "selCommandNames" defined above. + */ + + result = Tcl_GetIndexFromObj(interp, objv[2], selCommandNames, + "selection option", 0, &selIndex); + if (result != TCL_OK) { + goto error; + } + + switch(selIndex) { + case SELECTION_ADJUST: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "index"); + goto error; + } + if (GetEntryIndex(interp, entryPtr, + Tcl_GetString(objv[3]), &index) != TCL_OK) { + goto error; + } + if (entryPtr->selectFirst >= 0) { + int half1, half2; + + half1 = (entryPtr->selectFirst + + entryPtr->selectLast)/2; + half2 = (entryPtr->selectFirst + + entryPtr->selectLast + 1)/2; + if (index < half1) { + entryPtr->selectAnchor = entryPtr->selectLast; + } else if (index > half2) { + entryPtr->selectAnchor = entryPtr->selectFirst; + } else { + /* + * We're at about the halfway point in the + * selection; just keep the existing anchor. + */ + } + } + EntrySelectTo(entryPtr, index); break; - case TK_SCROLL_PAGES: - charsPerPage = ((Tk_Width(entryPtr->tkwin) - - 2*entryPtr->inset) / entryPtr->avgWidth) - 2; - if (charsPerPage < 1) { - charsPerPage = 1; + } + + case SELECTION_CLEAR: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL); + goto error; } - index += charsPerPage*count; + if (entryPtr->selectFirst >= 0) { + entryPtr->selectFirst = -1; + entryPtr->selectLast = -1; + EventuallyRedraw(entryPtr); + } + goto done; + } + + case SELECTION_FROM: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "index"); + goto error; + } + if (GetEntryIndex(interp, entryPtr, + Tcl_GetString(objv[3]), &index) != TCL_OK) { + goto error; + } + entryPtr->selectAnchor = index; break; - case TK_SCROLL_UNITS: - index += count; + } + + case SELECTION_PRESENT: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL); + goto error; + } + if (entryPtr->selectFirst < 0) { + Tcl_SetResult(interp, "0", TCL_STATIC); + } else { + Tcl_SetResult(interp, "1", TCL_STATIC); + } + goto done; + } + + case SELECTION_RANGE: { + if (objc != 5) { + Tcl_WrongNumArgs(interp, 3, objv, "start end"); + goto error; + } + if (GetEntryIndex(interp, entryPtr, + Tcl_GetString(objv[3]), &index) != TCL_OK) { + goto error; + } + if (GetEntryIndex(interp, entryPtr, + Tcl_GetString(objv[4]),& index2) != TCL_OK) { + goto error; + } + if (index >= index2) { + entryPtr->selectFirst = -1; + entryPtr->selectLast = -1; + } else { + entryPtr->selectFirst = index; + entryPtr->selectLast = index2; + } + if (!(entryPtr->flags & GOT_SELECTION) + && (entryPtr->exportSelection)) { + Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, + EntryLostSelection, (ClientData) entryPtr); + entryPtr->flags |= GOT_SELECTION; + } + EventuallyRedraw(entryPtr); break; + } + + case SELECTION_TO: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "index"); + goto error; + } + if (GetEntryIndex(interp, entryPtr, + Tcl_GetString(objv[3]), &index) != TCL_OK) { + goto error; + } + EntrySelectTo(entryPtr, index); + break; + } } + break; } - if (index >= entryPtr->numChars) { - index = entryPtr->numChars-1; - } - if (index < 0) { - index = 0; + + case COMMAND_VALIDATE: { + int code; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL); + goto error; + } + selIndex = entryPtr->validate; + entryPtr->validate = VALIDATE_ALL; + code = EntryValidateChange(entryPtr, (char *) NULL, + entryPtr->string, -1, VALIDATE_FORCED); + if (entryPtr->validate != VALIDATE_NONE) { + entryPtr->validate = selIndex; + } + Tcl_SetObjResult(interp, Tcl_NewBooleanObj((code == TCL_OK))); + break; + } + + case COMMAND_XVIEW: { + int index; + + if (objc == 2) { + double first, last; + char buf[TCL_DOUBLE_SPACE * 2]; + + EntryVisibleRange(entryPtr, &first, &last); + sprintf(buf, "%g %g", first, last); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + goto done; + } else if (objc == 3) { + if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]), + &index) != TCL_OK) { + goto error; + } + } else { + double fraction; + int count; + + index = entryPtr->leftIndex; + switch (Tk_GetScrollInfoObj(interp, objc, objv, &fraction, + &count)) { + case TK_SCROLL_ERROR: { + goto error; + } + case TK_SCROLL_MOVETO: { + index = (int) ((fraction * entryPtr->numChars) + 0.5); + break; + } + case TK_SCROLL_PAGES: { + int charsPerPage; + + charsPerPage = ((Tk_Width(entryPtr->tkwin) + - 2 * entryPtr->inset) + / entryPtr->avgWidth) - 2; + if (charsPerPage < 1) { + charsPerPage = 1; + } + index += count * charsPerPage; + break; + } + case TK_SCROLL_UNITS: { + index += count; + break; + } + } + } + if (index >= entryPtr->numChars) { + index = entryPtr->numChars - 1; + } + if (index < 0) { + index = 0; + } + entryPtr->leftIndex = index; + entryPtr->flags |= UPDATE_SCROLLBAR; + EntryComputeGeometry(entryPtr); + EventuallyRedraw(entryPtr); + break; } - entryPtr->leftIndex = index; - entryPtr->flags |= UPDATE_SCROLLBAR; - EntryComputeGeometry(entryPtr); - EventuallyRedraw(entryPtr); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be bbox, cget, configure, delete, get, ", - "icursor, index, insert, scan, selection, or xview", - (char *) NULL); - goto error; } + done: Tcl_Release((ClientData) entryPtr); return result; @@ -818,7 +1042,13 @@ static void DestroyEntry(memPtr) char *memPtr; /* Info about entry widget. */ { - register Entry *entryPtr = (Entry *) memPtr; + Entry *entryPtr = (Entry *) memPtr; + entryPtr->flags |= ENTRY_DELETED; + + Tcl_DeleteCommandFromToken(entryPtr->interp, entryPtr->widgetCmd); + if (entryPtr->flags & REDRAW_PENDING) { + Tcl_CancelIdleCall(DisplayEntry, (ClientData) entryPtr); + } /* * Free up all the stuff that requires special handling, then @@ -839,11 +1069,13 @@ DestroyEntry(memPtr) Tk_FreeGC(entryPtr->display, entryPtr->selTextGC); } Tcl_DeleteTimerHandler(entryPtr->insertBlinkHandler); - if (entryPtr->displayString != NULL) { + if (entryPtr->displayString != entryPtr->string) { ckfree(entryPtr->displayString); } Tk_FreeTextLayout(entryPtr->textLayout); - Tk_FreeOptions(configSpecs, (char *) entryPtr, entryPtr->display, 0); + Tk_FreeConfigOptions((char *) entryPtr, entryPtr->optionTable, + entryPtr->tkwin); + entryPtr->tkwin = NULL; ckfree((char *) entryPtr); } @@ -858,7 +1090,7 @@ DestroyEntry(memPtr) * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as colors, border width, @@ -869,14 +1101,17 @@ DestroyEntry(memPtr) */ static int -ConfigureEntry(interp, entryPtr, argc, argv, flags) +ConfigureEntry(interp, entryPtr, objc, objv, flags) Tcl_Interp *interp; /* Used for error reporting. */ - register Entry *entryPtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ + Entry *entryPtr; /* Information about widget; may or may not + * already have values for some fields. */ + int objc; /* Number of valid entries in argv. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int error; int oldExport; /* @@ -890,9 +1125,83 @@ ConfigureEntry(interp, entryPtr, argc, argv, flags) } oldExport = entryPtr->exportSelection; - if (Tk_ConfigureWidget(interp, entryPtr->tkwin, configSpecs, - argc, argv, (char *) entryPtr, flags) != TCL_OK) { - return TCL_ERROR; + + for (error = 0; error <= 1; error++) { + if (!error) { + /* + * First pass: set options to new values. + */ + + if (Tk_SetOptions(interp, (char *) entryPtr, + entryPtr->optionTable, objc, objv, + entryPtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) { + continue; + } + } else { + /* + * Second pass: restore options to old values. + */ + + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + /* + * A few other options also need special processing, such as parsing + * the geometry and setting the background from a 3-D border. + */ + + Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder); + + if (entryPtr->insertWidth <= 0) { + entryPtr->insertWidth = 2; + } + if (entryPtr->insertBorderWidth > entryPtr->insertWidth/2) { + entryPtr->insertBorderWidth = entryPtr->insertWidth/2; + } + + /* + * Restart the cursor timing sequence in case the on-time or + * off-time just changed. Set validate temporarily to none, + * so the configure doesn't cause it to be triggered. + */ + + if (entryPtr->flags & GOT_FOCUS) { + int validate = entryPtr->validate; + entryPtr->validate = VALIDATE_NONE; + EntryFocusProc(entryPtr, 1); + entryPtr->validate = validate; + } + + /* + * Claim the selection if we've suddenly started exporting it. + */ + + if (entryPtr->exportSelection && (!oldExport) + && (entryPtr->selectFirst != -1) + && !(entryPtr->flags & GOT_SELECTION)) { + Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection, + (ClientData) entryPtr); + entryPtr->flags |= GOT_SELECTION; + } + + /* + * Recompute the window's geometry and arrange for it to be + * redisplayed. + */ + + Tk_SetInternalBorder(entryPtr->tkwin, + entryPtr->borderWidth + entryPtr->highlightWidth); + if (entryPtr->highlightWidth <= 0) { + entryPtr->highlightWidth = 0; + } + entryPtr->inset = entryPtr->highlightWidth + + entryPtr->borderWidth + XPAD; + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); } /* @@ -915,63 +1224,14 @@ ConfigureEntry(interp, entryPtr, argc, argv, flags) EntryTextVarProc, (ClientData) entryPtr); } - /* - * A few other options also need special processing, such as parsing - * the geometry and setting the background from a 3-D border. - */ - - if ((entryPtr->state != tkNormalUid) - && (entryPtr->state != tkDisabledUid)) { - Tcl_AppendResult(interp, "bad state value \"", entryPtr->state, - "\": must be normal or disabled", (char *) NULL); - entryPtr->state = tkNormalUid; + EntryWorldChanged((ClientData) entryPtr); + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); return TCL_ERROR; + } else { + return TCL_OK; } - - Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder); - - if (entryPtr->insertWidth <= 0) { - entryPtr->insertWidth = 2; - } - if (entryPtr->insertBorderWidth > entryPtr->insertWidth/2) { - entryPtr->insertBorderWidth = entryPtr->insertWidth/2; - } - - /* - * Restart the cursor timing sequence in case the on-time or off-time - * just changed. - */ - - if (entryPtr->flags & GOT_FOCUS) { - EntryFocusProc(entryPtr, 1); - } - - /* - * Claim the selection if we've suddenly started exporting it. - */ - - if (entryPtr->exportSelection && (!oldExport) - && (entryPtr->selectFirst != -1) - && !(entryPtr->flags & GOT_SELECTION)) { - Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection, - (ClientData) entryPtr); - entryPtr->flags |= GOT_SELECTION; - } - - /* - * Recompute the window's geometry and arrange for it to be - * redisplayed. - */ - - Tk_SetInternalBorder(entryPtr->tkwin, - entryPtr->borderWidth + entryPtr->highlightWidth); - if (entryPtr->highlightWidth <= 0) { - entryPtr->highlightWidth = 0; - } - entryPtr->inset = entryPtr->highlightWidth + entryPtr->borderWidth + XPAD; - - EntryWorldChanged((ClientData) entryPtr); - return TCL_OK; } /* @@ -997,7 +1257,7 @@ EntryWorldChanged(instanceData) ClientData instanceData; /* Information about widget. */ { XGCValues gcValues; - GC gc; + GC gc = None; unsigned long mask; Entry *entryPtr; @@ -1008,12 +1268,15 @@ EntryWorldChanged(instanceData) entryPtr->avgWidth = 1; } + if (entryPtr->normalBorder != NULL) { + Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder); + } + gcValues.foreground = entryPtr->fgColorPtr->pixel; gcValues.font = Tk_FontId(entryPtr->tkfont); gcValues.graphics_exposures = False; mask = GCForeground | GCFont | GCGraphicsExposures; - gc = Tk_GetGCColor(entryPtr->tkwin, mask, &gcValues, entryPtr->fgColorPtr, - NULL); + gc = Tk_GetGC(entryPtr->tkwin, mask, &gcValues); if (entryPtr->textGC != None) { Tk_FreeGC(entryPtr->display, entryPtr->textGC); } @@ -1022,8 +1285,7 @@ EntryWorldChanged(instanceData) gcValues.foreground = entryPtr->selFgColorPtr->pixel; gcValues.font = Tk_FontId(entryPtr->tkfont); mask = GCForeground | GCFont; - gc = Tk_GetGCColor(entryPtr->tkwin, mask, &gcValues, - entryPtr->selFgColorPtr, NULL); + gc = Tk_GetGC(entryPtr->tkwin, mask, &gcValues); if (entryPtr->selTextGC != None) { Tk_FreeGC(entryPtr->display, entryPtr->selTextGC); } @@ -1059,9 +1321,9 @@ static void DisplayEntry(clientData) ClientData clientData; /* Information about window. */ { - register Entry *entryPtr = (Entry *) clientData; - register Tk_Window tkwin = entryPtr->tkwin; - int baseY, selStartX, selEndX, cursorX, x, w; + Entry *entryPtr = (Entry *) clientData; + Tk_Window tkwin = entryPtr->tkwin; + int baseY, selStartX, selEndX, cursorX; int xBound; Tk_FontMetrics fm; Pixmap pixmap; @@ -1119,19 +1381,21 @@ DisplayEntry(clientData) */ Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder, - 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); - if (showSelection && (entryPtr->selectLast > entryPtr->leftIndex)) { + 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); + + if (showSelection + && (entryPtr->selectLast > entryPtr->leftIndex)) { if (entryPtr->selectFirst <= entryPtr->leftIndex) { selStartX = entryPtr->leftX; } else { Tk_CharBbox(entryPtr->textLayout, entryPtr->selectFirst, - &x, NULL, NULL, NULL); - selStartX = x + entryPtr->layoutX; + &selStartX, NULL, NULL, NULL); + selStartX += entryPtr->layoutX; } if ((selStartX - entryPtr->selBorderWidth) < xBound) { - Tk_CharBbox(entryPtr->textLayout, entryPtr->selectLast - 1, - &x, NULL, &w, NULL); - selEndX = x + w + entryPtr->layoutX; + Tk_CharBbox(entryPtr->textLayout, entryPtr->selectLast, + &selEndX, NULL, NULL, NULL); + selEndX += entryPtr->layoutX; Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->selBorder, selStartX - entryPtr->selBorderWidth, baseY - fm.ascent - entryPtr->selBorderWidth, @@ -1151,33 +1415,22 @@ DisplayEntry(clientData) */ if ((entryPtr->insertPos >= entryPtr->leftIndex) - && (entryPtr->state == tkNormalUid) + && (entryPtr->state == STATE_NORMAL) && (entryPtr->flags & GOT_FOCUS)) { - if (entryPtr->insertPos == 0) { - cursorX = 0; - } else if (entryPtr->insertPos >= entryPtr->numChars) { - int idx = entryPtr->numChars >= 1 ? entryPtr->numChars - 1 : 0; - Tk_CharBbox(entryPtr->textLayout, idx, - &x, NULL, &w, NULL); - cursorX = x + w; - } else { - Tk_CharBbox(entryPtr->textLayout, entryPtr->insertPos, - &x, NULL, NULL, NULL); - cursorX = x; - } + Tk_CharBbox(entryPtr->textLayout, entryPtr->insertPos, &cursorX, NULL, + NULL, NULL); cursorX += entryPtr->layoutX; cursorX -= (entryPtr->insertWidth)/2; if (cursorX < xBound) { if (entryPtr->flags & CURSOR_ON) { Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->insertBorder, - cursorX, baseY - fm.ascent, - entryPtr->insertWidth, fm.ascent + fm.descent, - entryPtr->insertBorderWidth, TK_RELIEF_RAISED); + cursorX, baseY - fm.ascent, entryPtr->insertWidth, + fm.ascent + fm.descent, entryPtr->insertBorderWidth, + TK_RELIEF_RAISED); } else if (entryPtr->insertBorder == entryPtr->selBorder) { Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder, - cursorX, baseY - fm.ascent, - entryPtr->insertWidth, fm.ascent + fm.descent, - 0, TK_RELIEF_FLAT); + cursorX, baseY - fm.ascent, entryPtr->insertWidth, + fm.ascent + fm.descent, 0, TK_RELIEF_FLAT); } } } @@ -1191,18 +1444,19 @@ DisplayEntry(clientData) entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY, entryPtr->leftIndex, entryPtr->numChars); - if (showSelection && (entryPtr->selTextGC != entryPtr->textGC) && - (entryPtr->selectFirst < entryPtr->selectLast)) { - int first; + if (showSelection + && (entryPtr->selTextGC != entryPtr->textGC) + && (entryPtr->selectFirst < entryPtr->selectLast)) { + int selFirst; - if (entryPtr->selectFirst - entryPtr->leftIndex < 0) { - first = entryPtr->leftIndex; + if (entryPtr->selectFirst < entryPtr->leftIndex) { + selFirst = entryPtr->leftIndex; } else { - first = entryPtr->selectFirst; + selFirst = entryPtr->selectFirst; } Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->selTextGC, entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY, - first, entryPtr->selectLast); + selFirst, entryPtr->selectLast); } /* @@ -1213,19 +1467,22 @@ DisplayEntry(clientData) if (entryPtr->relief != TK_RELIEF_FLAT) { Tk_Draw3DRectangle(tkwin, pixmap, entryPtr->normalBorder, entryPtr->highlightWidth, entryPtr->highlightWidth, - Tk_Width(tkwin) - 2*entryPtr->highlightWidth, - Tk_Height(tkwin) - 2*entryPtr->highlightWidth, + Tk_Width(tkwin) - 2 * entryPtr->highlightWidth, + Tk_Height(tkwin) - 2 * entryPtr->highlightWidth, entryPtr->borderWidth, entryPtr->relief); } if (entryPtr->highlightWidth != 0) { - GC gc; + GC fgGC, bgGC; + bgGC = Tk_GCForColor(entryPtr->highlightBgColorPtr, pixmap); if (entryPtr->flags & GOT_FOCUS) { - gc = Tk_GCForColor(entryPtr->highlightColorPtr, pixmap); + fgGC = Tk_GCForColor(entryPtr->highlightColorPtr, pixmap); + TkpDrawHighlightBorder(tkwin, fgGC, bgGC, + entryPtr->highlightWidth, pixmap); } else { - gc = Tk_GCForColor(entryPtr->highlightBgColorPtr, pixmap); + TkpDrawHighlightBorder(tkwin, bgGC, bgGC, + entryPtr->highlightWidth, pixmap); } - Tk_DrawFocusHighlight(tkwin, gc, entryPtr->highlightWidth, pixmap); } /* @@ -1262,38 +1519,53 @@ DisplayEntry(clientData) static void EntryComputeGeometry(entryPtr) - Entry *entryPtr; /* Widget record for entry. */ + Entry *entryPtr; /* Widget record for entry. */ { int totalLength, overflow, maxOffScreen, rightX; int height, width, i; Tk_FontMetrics fm; - char *p, *displayString; + char *p; + + if (entryPtr->displayString != entryPtr->string) { + ckfree(entryPtr->displayString); + entryPtr->displayString = entryPtr->string; + entryPtr->numDisplayBytes = entryPtr->numBytes; + } /* * If we're displaying a special character instead of the value of * the entry, recompute the displayString. */ - if (entryPtr->displayString != NULL) { - ckfree(entryPtr->displayString); - entryPtr->displayString = NULL; - } if (entryPtr->showChar != NULL) { - entryPtr->displayString = (char *) ckalloc((unsigned) - (entryPtr->numChars + 1)); - for (p = entryPtr->displayString, i = entryPtr->numChars; i > 0; - i--, p++) { - *p = entryPtr->showChar[0]; + Tcl_UniChar ch; + char buf[TCL_UTF_MAX]; + int size; + + /* + * Normalize the special character so we can safely duplicate it + * in the display string. If we didn't do this, then two malformed + * characters might end up looking like one valid UTF character in + * the resulting string. + */ + + Tcl_UtfToUniChar(entryPtr->showChar, &ch); + size = Tcl_UniCharToUtf(ch, buf); + + entryPtr->numDisplayBytes = entryPtr->numChars * size; + entryPtr->displayString = + (char *) ckalloc((unsigned) (entryPtr->numDisplayBytes + 1)); + + p = entryPtr->displayString; + for (i = entryPtr->numChars; --i >= 0; ) { + p += Tcl_UniCharToUtf(ch, p); } - *p = 0; - displayString = entryPtr->displayString; - } else { - displayString = entryPtr->string; + *p = '\0'; } Tk_FreeTextLayout(entryPtr->textLayout); entryPtr->textLayout = Tk_ComputeTextLayout(entryPtr->tkfont, - displayString, entryPtr->numChars, 0, entryPtr->justify, - TK_IGNORE_NEWLINES, &totalLength, &height); + entryPtr->displayString, entryPtr->numChars, 0, + entryPtr->justify, TK_IGNORE_NEWLINES, &totalLength, &height); entryPtr->layoutY = (Tk_Height(entryPtr->tkwin) - height) / 2; @@ -1328,13 +1600,13 @@ EntryComputeGeometry(entryPtr) Tk_CharBbox(entryPtr->textLayout, maxOffScreen, &rightX, NULL, NULL, NULL); if (rightX < overflow) { - maxOffScreen += 1; + maxOffScreen++; } if (entryPtr->leftIndex > maxOffScreen) { entryPtr->leftIndex = maxOffScreen; } - Tk_CharBbox(entryPtr->textLayout, entryPtr->leftIndex, - &rightX, NULL, NULL, NULL); + Tk_CharBbox(entryPtr->textLayout, entryPtr->leftIndex, &rightX, + NULL, NULL, NULL); entryPtr->leftX = entryPtr->inset; entryPtr->layoutX = entryPtr->leftX - rightX; } @@ -1371,28 +1643,59 @@ EntryComputeGeometry(entryPtr) */ static void -InsertChars(entryPtr, index, string) - register Entry *entryPtr; /* Entry that is to get the new - * elements. */ +InsertChars(entryPtr, index, value) + Entry *entryPtr; /* Entry that is to get the new elements. */ int index; /* Add the new elements before this - * element. */ - char *string; /* New characters to add (NULL-terminated + * character index. */ + char *value; /* New characters to add (NULL-terminated * string). */ { - int length; - char *new; + int byteIndex, byteCount, oldChars, charsAdded, newByteCount; + char *new, *string; - length = strlen(string); - if (length == 0) { + string = entryPtr->string; + byteIndex = Tcl_UtfAtIndex(string, index) - string; + byteCount = strlen(value); + if (byteCount == 0) { return; } - new = (char *) ckalloc((unsigned) (entryPtr->numChars + length + 1)); - strncpy(new, entryPtr->string, (size_t) index); - strcpy(new+index, string); - strcpy(new+index+length, entryPtr->string+index); - ckfree(entryPtr->string); + + newByteCount = entryPtr->numBytes + byteCount + 1; + new = (char *) ckalloc((unsigned) newByteCount); + memcpy(new, string, (size_t) byteIndex); + strcpy(new + byteIndex, value); + strcpy(new + byteIndex + byteCount, string + byteIndex); + + if ((entryPtr->validate == VALIDATE_KEY || + entryPtr->validate == VALIDATE_ALL) && + EntryValidateChange(entryPtr, value, new, index, + VALIDATE_INSERT) != TCL_OK) { + ckfree(new); + return; + } + + ckfree(string); entryPtr->string = new; - entryPtr->numChars += length; + + /* + * The following construction is used because inserting improperly + * formed UTF-8 sequences between other improperly formed UTF-8 + * sequences could result in actually forming valid UTF-8 sequences; + * the number of characters added may not be Tcl_NumUtfChars(string, -1), + * because of context. The actual number of characters added is how + * many characters are in the string now minus the number that + * used to be there. + */ + + oldChars = entryPtr->numChars; + entryPtr->numChars = Tcl_NumUtfChars(new, -1); + charsAdded = entryPtr->numChars - oldChars; + entryPtr->numBytes += byteCount; + + if (entryPtr->displayString == string) { + entryPtr->displayString = new; + entryPtr->numDisplayBytes = entryPtr->numBytes; + } /* * Inserting characters invalidates all indexes into the string. @@ -1403,19 +1706,20 @@ InsertChars(entryPtr, index, string) */ if (entryPtr->selectFirst >= index) { - entryPtr->selectFirst += length; + entryPtr->selectFirst += charsAdded; } if (entryPtr->selectLast > index) { - entryPtr->selectLast += length; + entryPtr->selectLast += charsAdded; } - if ((entryPtr->selectAnchor > index) || (entryPtr->selectFirst >= index)) { - entryPtr->selectAnchor += length; + if ((entryPtr->selectAnchor > index) + || (entryPtr->selectFirst >= index)) { + entryPtr->selectAnchor += charsAdded; } if (entryPtr->leftIndex > index) { - entryPtr->leftIndex += length; + entryPtr->leftIndex += charsAdded; } if (entryPtr->insertPos >= index) { - entryPtr->insertPos += length; + entryPtr->insertPos += charsAdded; } EntryValueChanged(entryPtr); } @@ -1439,11 +1743,12 @@ InsertChars(entryPtr, index, string) static void DeleteChars(entryPtr, index, count) - register Entry *entryPtr; /* Entry widget to modify. */ + Entry *entryPtr; /* Entry widget to modify. */ int index; /* Index of first character to delete. */ int count; /* How many characters to delete. */ { - char *new; + int byteIndex, byteCount, newByteCount; + char *new, *string, *todelete; if ((index + count) > entryPtr->numChars) { count = entryPtr->numChars - index; @@ -1452,12 +1757,38 @@ DeleteChars(entryPtr, index, count) return; } - new = (char *) ckalloc((unsigned) (entryPtr->numChars + 1 - count)); - strncpy(new, entryPtr->string, (size_t) index); - strcpy(new+index, entryPtr->string+index+count); + string = entryPtr->string; + byteIndex = Tcl_UtfAtIndex(string, index) - string; + byteCount = Tcl_UtfAtIndex(string + byteIndex, count) - (string + byteIndex); + + newByteCount = entryPtr->numBytes + 1 - byteCount; + new = (char *) ckalloc((unsigned) newByteCount); + memcpy(new, string, (size_t) byteIndex); + strcpy(new + byteIndex, string + byteIndex + byteCount); + + todelete = (char *) ckalloc((unsigned) (byteCount + 1)); + memcpy(todelete, string + byteIndex, (size_t) byteCount); + todelete[byteCount] = '\0'; + + if ((entryPtr->validate == VALIDATE_KEY || + entryPtr->validate == VALIDATE_ALL) && + EntryValidateChange(entryPtr, todelete, new, index, + VALIDATE_DELETE) != TCL_OK) { + ckfree(new); + ckfree(todelete); + return; + } + + ckfree(todelete); ckfree(entryPtr->string); entryPtr->string = new; entryPtr->numChars -= count; + entryPtr->numBytes -= byteCount; + + if (entryPtr->displayString == string) { + entryPtr->displayString = new; + entryPtr->numDisplayBytes = entryPtr->numBytes; + } /* * Deleting characters results in the remaining characters being @@ -1466,21 +1797,22 @@ DeleteChars(entryPtr, index, count) */ if (entryPtr->selectFirst >= index) { - if (entryPtr->selectFirst >= (index+count)) { + if (entryPtr->selectFirst >= (index + count)) { entryPtr->selectFirst -= count; } else { entryPtr->selectFirst = index; } } if (entryPtr->selectLast >= index) { - if (entryPtr->selectLast >= (index+count)) { + if (entryPtr->selectLast >= (index + count)) { entryPtr->selectLast -= count; } else { entryPtr->selectLast = index; } } if (entryPtr->selectLast <= entryPtr->selectFirst) { - entryPtr->selectFirst = entryPtr->selectLast = -1; + entryPtr->selectFirst = -1; + entryPtr->selectLast = -1; } if (entryPtr->selectAnchor >= index) { if (entryPtr->selectAnchor >= (index+count)) { @@ -1490,14 +1822,14 @@ DeleteChars(entryPtr, index, count) } } if (entryPtr->leftIndex > index) { - if (entryPtr->leftIndex >= (index+count)) { + if (entryPtr->leftIndex >= (index + count)) { entryPtr->leftIndex -= count; } else { entryPtr->leftIndex = index; } } if (entryPtr->insertPos >= index) { - if (entryPtr->insertPos >= (index+count)) { + if (entryPtr->insertPos >= (index + count)) { entryPtr->insertPos -= count; } else { entryPtr->insertPos = index; @@ -1583,24 +1915,74 @@ EntryValueChanged(entryPtr) static void EntrySetValue(entryPtr, value) - register Entry *entryPtr; /* Entry whose value is to be - * changed. */ - char *value; /* New text to display in entry. */ + Entry *entryPtr; /* Entry whose value is to be changed. */ + char *value; /* New text to display in entry. */ { + char *oldSource; + int code, valueLen, malloced = 0; + + if (strcmp(value, entryPtr->string) == 0) { + return; + } + valueLen = strlen(value); + + if (entryPtr->flags & VALIDATE_VAR) { + entryPtr->flags |= VALIDATE_ABORT; + } else { + /* + * If we validate, we create a copy of the value, as it may + * point to volatile memory, like the value of the -textvar + * which may get freed during validation + */ + oldSource = (char *) ckalloc((unsigned) (valueLen + 1)); + strcpy(oldSource, value); + value = oldSource; + malloced = 1; + + entryPtr->flags |= VALIDATE_VAR; + code = EntryValidateChange(entryPtr, (char *) NULL, value, -1, + VALIDATE_FORCED); + entryPtr->flags &= ~VALIDATE_VAR; + /* + * If VALIDATE_ABORT has been set, then this operation should be + * aborted because the validatecommand did something else instead + */ + if (entryPtr->flags & VALIDATE_ABORT) { + entryPtr->flags &= ~VALIDATE_ABORT; + ckfree(value); + return; + } + } + + oldSource = entryPtr->string; ckfree(entryPtr->string); - entryPtr->numChars = strlen(value); - entryPtr->string = (char *) ckalloc((unsigned) (entryPtr->numChars + 1)); - strcpy(entryPtr->string, value); - if (entryPtr->selectFirst != -1) { + + if (malloced) { + entryPtr->string = value; + } else { + entryPtr->string = (char *) ckalloc((unsigned) (valueLen + 1)); + strcpy(entryPtr->string, value); + } + entryPtr->numBytes = valueLen; + entryPtr->numChars = Tcl_NumUtfChars(value, valueLen); + + if (entryPtr->displayString == oldSource) { + entryPtr->displayString = entryPtr->string; + entryPtr->numDisplayBytes = entryPtr->numBytes; + } + + if (entryPtr->selectFirst >= 0) { if (entryPtr->selectFirst >= entryPtr->numChars) { - entryPtr->selectFirst = entryPtr->selectLast = -1; + entryPtr->selectFirst = -1; + entryPtr->selectLast = -1; } else if (entryPtr->selectLast > entryPtr->numChars) { entryPtr->selectLast = entryPtr->numChars; } } if (entryPtr->leftIndex >= entryPtr->numChars) { - entryPtr->leftIndex = entryPtr->numChars-1; - if (entryPtr->leftIndex < 0) { + if (entryPtr->numChars > 0) { + entryPtr->leftIndex = entryPtr->numChars - 1; + } else { entryPtr->leftIndex = 0; } } @@ -1641,14 +2023,7 @@ EntryEventProc(clientData, eventPtr) EventuallyRedraw(entryPtr); entryPtr->flags |= BORDER_NEEDED; } else if (eventPtr->type == DestroyNotify) { - if (entryPtr->tkwin != NULL) { - entryPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(entryPtr->interp, entryPtr->widgetCmd); - } - if (entryPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayEntry, (ClientData) entryPtr); - } - Tcl_EventuallyFree((ClientData) entryPtr, DestroyEntry); + DestroyEntry((char *) clientData); } else if (eventPtr->type == ConfigureNotify) { Tcl_Preserve((ClientData) entryPtr); entryPtr->flags |= UPDATE_SCROLLBAR; @@ -1689,7 +2064,6 @@ EntryCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Entry *entryPtr = (Entry *) clientData; - Tk_Window tkwin = entryPtr->tkwin; /* * This procedure could be invoked either because the window was @@ -1698,14 +2072,13 @@ EntryCmdDeletedProc(clientData) * destroys the widget. */ - if (tkwin != NULL) { - entryPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); + if (!(entryPtr->flags & ENTRY_DELETED)) { + Tk_DestroyWindow(entryPtr->tkwin); } } /* - *-------------------------------------------------------------- + *--------------------------------------------------------------------------- * * GetEntryIndex -- * @@ -1714,15 +2087,15 @@ EntryCmdDeletedProc(clientData) * * Results: * A standard Tcl result. If all went well, then *indexPtr is - * filled in with the index (into entryPtr) corresponding to + * filled in with the character index (into entryPtr) corresponding to * string. The index value is guaranteed to lie between 0 and * the number of characters in the string, inclusive. If an - * error occurs then an error message is left in interp->result. + * error occurs then an error message is left in the interp's result. * * Side effects: * None. * - *-------------------------------------------------------------- + *--------------------------------------------------------------------------- */ static int @@ -1731,7 +2104,8 @@ GetEntryIndex(interp, entryPtr, string, indexPtr) Entry *entryPtr; /* Entry for which the index is being * specified. */ char *string; /* Specifies character in entryPtr. */ - int *indexPtr; /* Where to store converted index. */ + int *indexPtr; /* Where to store converted character + * index. */ { size_t length; @@ -1744,7 +2118,7 @@ GetEntryIndex(interp, entryPtr, string, indexPtr) badIndex: /* - * Some of the paths here leave messages in interp->result, + * Some of the paths here leave messages in the interp's result, * so we have to clear it out before storing our own message. */ @@ -1766,8 +2140,8 @@ GetEntryIndex(interp, entryPtr, string, indexPtr) goto badIndex; } } else if (string[0] == 's') { - if (entryPtr->selectFirst == -1) { - interp->result = "selection isn't in entry"; + if (entryPtr->selectFirst < 0) { + Tcl_SetResult(interp, "selection isn't in entry", TCL_STATIC); return TCL_ERROR; } if (length < 5) { @@ -1783,7 +2157,7 @@ GetEntryIndex(interp, entryPtr, string, indexPtr) } else if (string[0] == '@') { int x, roundUp; - if (Tcl_GetInt(interp, string+1, &x) != TCL_OK) { + if (Tcl_GetInt(interp, string + 1, &x) != TCL_OK) { goto badIndex; } if (x < entryPtr->inset) { @@ -1815,7 +2189,7 @@ GetEntryIndex(interp, entryPtr, string, indexPtr) *indexPtr = 0; } else if (*indexPtr > entryPtr->numChars) { *indexPtr = entryPtr->numChars; - } + } } if(*indexPtr > entryPtr->numChars) *indexPtr = entryPtr->numChars; @@ -1841,9 +2215,8 @@ GetEntryIndex(interp, entryPtr, string, indexPtr) static void EntryScanTo(entryPtr, x) - register Entry *entryPtr; /* Information about widget. */ - int x; /* X-coordinate to use for scan - * operation. */ + Entry *entryPtr; /* Information about widget. */ + int x; /* X-coordinate to use for scan operation. */ { int newLeftIndex; @@ -1859,19 +2232,24 @@ EntryScanTo(entryPtr, x) */ newLeftIndex = entryPtr->scanMarkIndex - - (10*(x - entryPtr->scanMarkX))/entryPtr->avgWidth; + - (10 * (x - entryPtr->scanMarkX)) / entryPtr->avgWidth; if (newLeftIndex >= entryPtr->numChars) { - newLeftIndex = entryPtr->scanMarkIndex = entryPtr->numChars-1; + newLeftIndex = entryPtr->scanMarkIndex = entryPtr->numChars - 1; entryPtr->scanMarkX = x; } if (newLeftIndex < 0) { newLeftIndex = entryPtr->scanMarkIndex = 0; entryPtr->scanMarkX = x; } + if (newLeftIndex != entryPtr->leftIndex) { entryPtr->leftIndex = newLeftIndex; entryPtr->flags |= UPDATE_SCROLLBAR; EntryComputeGeometry(entryPtr); + if (newLeftIndex != entryPtr->leftIndex) { + entryPtr->scanMarkIndex = entryPtr->leftIndex; + entryPtr->scanMarkX = x; + } EventuallyRedraw(entryPtr); } } @@ -1895,10 +2273,9 @@ EntryScanTo(entryPtr, x) static void EntrySelectTo(entryPtr, index) - register Entry *entryPtr; /* Information about widget. */ - int index; /* Index of element that is to - * become the "other" end of the - * selection. */ + Entry *entryPtr; /* Information about widget. */ + int index; /* Character index of element that is to + * become the "other" end of the selection. */ { int newFirst, newLast; @@ -1961,38 +2338,35 @@ EntrySelectTo(entryPtr, index) static int EntryFetchSelection(clientData, offset, buffer, maxBytes) - ClientData clientData; /* Information about entry widget. */ - int offset; /* Offset within selection of first - * character to be returned. */ - char *buffer; /* Location in which to place - * selection. */ - int maxBytes; /* Maximum number of bytes to place - * at buffer, not including terminating - * NULL character. */ + ClientData clientData; /* Information about entry widget. */ + int offset; /* Byte offset within selection of first + * character to be returned. */ + char *buffer; /* Location in which to place selection. */ + int maxBytes; /* Maximum number of bytes to place at + * buffer, not including terminating NULL + * character. */ { Entry *entryPtr = (Entry *) clientData; - int count; - char *displayString; + int byteCount; + char *string, *selStart, *selEnd; if ((entryPtr->selectFirst < 0) || !(entryPtr->exportSelection)) { return -1; } - count = entryPtr->selectLast - entryPtr->selectFirst - offset; - if (count > maxBytes) { - count = maxBytes; + string = entryPtr->displayString; + selStart = Tcl_UtfAtIndex(string, entryPtr->selectFirst); + selEnd = Tcl_UtfAtIndex(selStart, + entryPtr->selectLast - entryPtr->selectFirst); + byteCount = selEnd - selStart - offset; + if (byteCount > maxBytes) { + byteCount = maxBytes; } - if (count <= 0) { + if (byteCount <= 0) { return 0; } - if (entryPtr->displayString == NULL) { - displayString = entryPtr->string; - } else { - displayString = entryPtr->displayString; - } - strncpy(buffer, displayString + entryPtr->selectFirst + offset, - (size_t) count); - buffer[count] = '\0'; - return count; + memcpy(buffer, selStart + offset, (size_t) byteCount); + buffer[byteCount] = '\0'; + return byteCount; } /* @@ -2015,7 +2389,7 @@ EntryFetchSelection(clientData, offset, buffer, maxBytes) static void EntryLostSelection(clientData) - ClientData clientData; /* Information about entry widget. */ + ClientData clientData; /* Information about entry widget. */ { Entry *entryPtr = (Entry *) clientData; @@ -2028,7 +2402,7 @@ EntryLostSelection(clientData) */ #ifdef ALWAYS_SHOW_SELECTION - if ((entryPtr->selectFirst != -1) && entryPtr->exportSelection) { + if ((entryPtr->selectFirst >= 0) && entryPtr->exportSelection) { entryPtr->selectFirst = -1; entryPtr->selectLast = -1; EventuallyRedraw(entryPtr); @@ -2057,7 +2431,7 @@ EntryLostSelection(clientData) static void EventuallyRedraw(entryPtr) - register Entry *entryPtr; /* Information about widget. */ + Entry *entryPtr; /* Information about widget. */ { if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(entryPtr->tkwin)) { return; @@ -2096,11 +2470,11 @@ EventuallyRedraw(entryPtr) static void EntryVisibleRange(entryPtr, firstPtr, lastPtr) - Entry *entryPtr; /* Information about widget. */ - double *firstPtr; /* Return position of first visible - * character in widget. */ - double *lastPtr; /* Return position of char just after - * last visible one. */ + Entry *entryPtr; /* Information about widget. */ + double *firstPtr; /* Return position of first visible + * character in widget. */ + double *lastPtr; /* Return position of char just after last + * visible one. */ { int charsInWindow; @@ -2110,22 +2484,18 @@ EntryVisibleRange(entryPtr, firstPtr, lastPtr) } else { charsInWindow = Tk_PointToChar(entryPtr->textLayout, Tk_Width(entryPtr->tkwin) - entryPtr->inset - - entryPtr->layoutX - 1, 0) + 1; - if (charsInWindow > entryPtr->numChars) { - /* - * If all chars were visible, then charsInWindow will be - * the index just after the last char that was visible. - */ - - charsInWindow = entryPtr->numChars; + - entryPtr->layoutX - 1, 0); + if (charsInWindow < entryPtr->numChars) { + charsInWindow++; } charsInWindow -= entryPtr->leftIndex; if (charsInWindow == 0) { charsInWindow = 1; } - *firstPtr = ((double) entryPtr->leftIndex)/entryPtr->numChars; - *lastPtr = ((double) (entryPtr->leftIndex + charsInWindow)) - /entryPtr->numChars; + + *firstPtr = (double) entryPtr->leftIndex / entryPtr->numChars; + *lastPtr = (double) (entryPtr->leftIndex + charsInWindow) + / entryPtr->numChars; } } @@ -2153,7 +2523,7 @@ static void EntryUpdateScrollbar(entryPtr) Entry *entryPtr; /* Information about widget. */ { - char args[100]; + char args[TCL_DOUBLE_SPACE * 2]; int code; double first, last; Tcl_Interp *interp; @@ -2198,9 +2568,10 @@ static void EntryBlinkProc(clientData) ClientData clientData; /* Pointer to record describing entry. */ { - register Entry *entryPtr = (Entry *) clientData; + Entry *entryPtr = (Entry *) clientData; - if (!(entryPtr->flags & GOT_FOCUS) || (entryPtr->insertOffTime == 0)) { + if ((entryPtr->state == STATE_DISABLED) || + !(entryPtr->flags & GOT_FOCUS) || (entryPtr->insertOffTime == 0)) { return; } if (entryPtr->flags & CURSOR_ON) { @@ -2235,7 +2606,7 @@ EntryBlinkProc(clientData) static void EntryFocusProc(entryPtr, gotFocus) - register Entry *entryPtr; /* Entry that got or lost focus. */ + Entry *entryPtr; /* Entry that got or lost focus. */ int gotFocus; /* 1 means window is getting focus, 0 means * it's losing it. */ { @@ -2247,9 +2618,21 @@ EntryFocusProc(entryPtr, gotFocus) entryPtr->insertOnTime, EntryBlinkProc, (ClientData) entryPtr); } + if (entryPtr->validate == VALIDATE_ALL || + entryPtr->validate == VALIDATE_FOCUS || + entryPtr->validate == VALIDATE_FOCUSIN) { + EntryValidateChange(entryPtr, (char *) NULL, + entryPtr->string, -1, VALIDATE_FOCUSIN); + } } else { entryPtr->flags &= ~(GOT_FOCUS | CURSOR_ON); entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; + if (entryPtr->validate == VALIDATE_ALL || + entryPtr->validate == VALIDATE_FOCUS || + entryPtr->validate == VALIDATE_FOCUSOUT) { + EntryValidateChange(entryPtr, (char *) NULL, + entryPtr->string, -1, VALIDATE_FOCUSOUT); + } } EventuallyRedraw(entryPtr); } @@ -2281,7 +2664,7 @@ EntryTextVarProc(clientData, interp, name1, name2, flags) char *name2; /* Not used. */ int flags; /* Information about what happened. */ { - register Entry *entryPtr = (Entry *) clientData; + Entry *entryPtr = (Entry *) clientData; char *value; /* @@ -2311,8 +2694,308 @@ EntryTextVarProc(clientData, interp, name1, name2, flags) if (value == NULL) { value = ""; } - if (strcmp(value, entryPtr->string) != 0) { - EntrySetValue(entryPtr, value); - } + EntrySetValue(entryPtr, value); return (char *) NULL; } + +/* + *-------------------------------------------------------------- + * + * EntryValidate -- + * + * This procedure is invoked when any character is added or + * removed from the entry widget, or a focus has trigerred validation. + * + * Results: + * TCL_OK if the validatecommand passes the new string. + * TCL_BREAK if the vcmd executed OK, but rejects the string. + * TCL_ERROR if an error occurred while executing the vcmd + * or a valid Tcl_Bool is not returned. + * + * Side effects: + * An error condition may arise + * + *-------------------------------------------------------------- + */ + +static int +EntryValidate(entryPtr, cmd) + register Entry *entryPtr; /* Entry that needs validation. */ + register char *cmd; /* Validation command (NULL-terminated + * string). */ +{ + register Tcl_Interp *interp = entryPtr->interp; + int code, bool; + + code = Tcl_EvalEx(interp, cmd, -1, TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT); + + if (code != TCL_OK && code != TCL_RETURN) { + Tcl_AddErrorInfo(interp, + "\n\t(in validation command executed by entry)"); + Tcl_BackgroundError(interp); + return TCL_ERROR; + } + + if (Tcl_GetBooleanFromObj(interp, Tcl_GetObjResult(interp), + &bool) != TCL_OK) { + Tcl_AddErrorInfo(interp, + "\nvalid boolean not returned by validation command"); + Tcl_BackgroundError(interp); + Tcl_SetResult(interp, NULL, 0); + return TCL_ERROR; + } + + Tcl_SetResult(interp, NULL, 0); + return (bool ? TCL_OK : TCL_BREAK); +} + +/* + *-------------------------------------------------------------- + * + * EntryValidateChange -- + * + * This procedure is invoked when any character is added or + * removed from the entry widget, or a focus has trigerred validation. + * + * Results: + * TCL_OK if the validatecommand accepts the new string, + * TCL_ERROR if any problems occured with validatecommand. + * + * Side effects: + * The insertion/deletion may be aborted, and the + * validatecommand might turn itself off (if an error + * or loop condition arises). + * + *-------------------------------------------------------------- + */ + +static int +EntryValidateChange(entryPtr, change, new, index, type) + register Entry *entryPtr; /* Entry that needs validation. */ + char *change; /* Characters to be added/deleted + * (NULL-terminated string). */ + char *new; /* Potential new value of entry string */ + int index; /* index of insert/delete, -1 otherwise */ + int type; /* forced, delete, insert, + * focusin or focusout */ +{ + int code, varValidate = (entryPtr->flags & VALIDATE_VAR); + char *p; + Tcl_DString script; + + if (entryPtr->validateCmd == NULL || + entryPtr->validate == VALIDATE_NONE) { + return (varValidate ? TCL_ERROR : TCL_OK); + } + + /* + * If we're already validating, then we're hitting a loop condition + * Return and set validate to 0 to disallow further validations + * and prevent current validation from finishing + */ + if (entryPtr->flags & VALIDATING) { + entryPtr->validate = VALIDATE_NONE; + return (varValidate ? TCL_ERROR : TCL_OK); + } + + entryPtr->flags |= VALIDATING; + + /* + * Now form command string and run through the -validatecommand + */ + + Tcl_DStringInit(&script); + ExpandPercents(entryPtr, entryPtr->validateCmd, + change, new, index, type, &script); + Tcl_DStringAppend(&script, "", 1); + + p = Tcl_DStringValue(&script); + code = EntryValidate(entryPtr, p); + Tcl_DStringFree(&script); + + /* + * If e->validate has become VALIDATE_NONE during the validation, or + * we now have VALIDATE_VAR set (from EntrySetValue) and didn't before, + * it means that a loop condition almost occured. Do not allow + * this validation result to finish. + */ + if (entryPtr->validate == VALIDATE_NONE + || (!varValidate && (entryPtr->flags & VALIDATE_VAR))) { + code = TCL_ERROR; + } + /* + * If validate will return ERROR, then disallow further validations + * Otherwise, if it didn't accept the new string (returned TCL_BREAK) + * then eval the invalidCmd (if it's set) + */ + if (code == TCL_ERROR) { + entryPtr->validate = VALIDATE_NONE; + } else if (code == TCL_BREAK) { + /* + * If we were doing forced validation (like via a variable + * trace) and the command returned 0, the we turn off validation + * because we assume that textvariables have precedence in + * managing the value. We also don't call the invcmd, as it + * may want to do entry manipulation which the setting of the + * var will later wipe anyway. + */ + if (varValidate) { + entryPtr->validate = VALIDATE_NONE; + } else if (entryPtr->invalidCmd != NULL) { + Tcl_DStringInit(&script); + ExpandPercents(entryPtr, entryPtr->invalidCmd, + change, new, index, type, &script); + Tcl_DStringAppend(&script, "", 1); + p = Tcl_DStringValue(&script); + if (Tcl_EvalEx(entryPtr->interp, p, -1, + TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT) != TCL_OK) { + Tcl_AddErrorInfo(entryPtr->interp, + "\n\t(in invalidcommand executed by entry)"); + Tcl_BackgroundError(entryPtr->interp); + code = TCL_ERROR; + entryPtr->validate = VALIDATE_NONE; + } + Tcl_DStringFree(&script); + } + } + + entryPtr->flags &= ~VALIDATING; + + return code; +} + +/* + *-------------------------------------------------------------- + * + * ExpandPercents -- + * + * Given a command and an event, produce a new command + * by replacing % constructs in the original command + * with information from the X event. + * + * Results: + * The new expanded command is appended to the dynamic string + * given by dsPtr. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static void +ExpandPercents(entryPtr, before, change, new, index, type, dsPtr) + register Entry *entryPtr; /* Entry that needs validation. */ + register char *before; /* Command containing percent + * expressions to be replaced. */ + char *change; /* Characters to added/deleted + * (NULL-terminated string). */ + char *new; /* Potential new value of entry string */ + int index; /* index of insert/delete */ + int type; /* INSERT or DELETE */ + Tcl_DString *dsPtr; /* Dynamic string in which to append + * new command. */ +{ + int spaceNeeded, cvtFlags; /* Used to substitute string as proper Tcl + * list element. */ + int number, length; + register char *string; + Tcl_UniChar ch; + char numStorage[2*TCL_INTEGER_SPACE]; + + while (1) { + if (*before == '\0') { + break; + } + /* + * Find everything up to the next % character and append it + * to the result string. + */ + + string = before; + /* No need to convert '%', as it is in ascii range */ + string = Tcl_UtfFindFirst(before, '%'); + if (string == (char *) NULL) { + Tcl_DStringAppend(dsPtr, before, -1); + break; + } else if (string != before) { + Tcl_DStringAppend(dsPtr, before, string-before); + before = string; + } + + /* + * There's a percent sequence here. Process it. + */ + + before++; /* skip over % */ + if (*before != '\0') { + before += Tcl_UtfToUniChar(before, &ch); + } else { + ch = '%'; + } + switch (ch) { + case 'd': /* Type of call that caused validation */ + switch (type) { + case VALIDATE_INSERT: + number = 1; + break; + case VALIDATE_DELETE: + number = 0; + break; + default: + number = -1; + break; + } + sprintf(numStorage, "%d", number); + string = numStorage; + break; + case 'i': /* index of insert/delete */ + sprintf(numStorage, "%d", index); + string = numStorage; + break; + case 'P': /* 'Peeked' new value of the string */ + string = new; + break; + case 's': /* Current string value of entry */ + string = entryPtr->string; + break; + case 'S': /* string to be inserted/deleted, if any */ + string = change; + break; + case 'v': /* type of validation currently set */ + string = validateStrings[entryPtr->validate]; + break; + case 'V': /* type of validation in effect */ + switch (type) { + case VALIDATE_INSERT: + case VALIDATE_DELETE: + string = validateStrings[VALIDATE_KEY]; + break; + case VALIDATE_FORCED: + string = "forced"; + break; + default: + string = validateStrings[type]; + break; + } + break; + case 'W': /* widget name */ + string = Tk_PathName(entryPtr->tkwin); + break; + default: + length = Tcl_UniCharToUtf(ch, numStorage); + numStorage[length] = '\0'; + string = numStorage; + break; + } + + spaceNeeded = Tcl_ScanCountedElement(string, -1, &cvtFlags); + length = Tcl_DStringLength(dsPtr); + Tcl_DStringSetLength(dsPtr, length + spaceNeeded); + spaceNeeded = Tcl_ConvertCountedElement(string, -1, + Tcl_DStringValue(dsPtr) + length, + cvtFlags | TCL_DONT_USE_BRACES); + Tcl_DStringSetLength(dsPtr, length + spaceNeeded); + } +} + diff --git a/tk/generic/tkError.c b/tk/generic/tkError.c index 77909331a6f..aaf7c10b351 100644 --- a/tk/generic/tkError.c +++ b/tk/generic/tkError.c @@ -305,3 +305,4 @@ ErrorProc(display, errEventPtr) couldntHandle: return (*defaultHandler)(display, errEventPtr); } + diff --git a/tk/generic/tkEvent.c b/tk/generic/tkEvent.c index 2d10dccc69c..bd70e881bae 100644 --- a/tk/generic/tkEvent.c +++ b/tk/generic/tkEvent.c @@ -39,10 +39,6 @@ typedef struct InProgress { struct InProgress *nextPtr; /* Next higher nested search. */ } InProgress; -static InProgress *pendingPtr = NULL; - /* Topmost search in progress, or - * NULL if none. */ - /* * For each call to Tk_CreateGenericHandler, an instance of the following * structure will be created. All of the active handlers are linked into a @@ -58,11 +54,6 @@ typedef struct GenericHandler { * handlers, or NULL for end of list. */ } GenericHandler; -static GenericHandler *genericList = NULL; - /* First handler in the list, or NULL. */ -static GenericHandler *lastGenericPtr = NULL; - /* Last handler in list. */ - /* * There's a potential problem if Tk_HandleEvent is entered recursively. * A handler cannot be deleted physically until we have returned from @@ -70,11 +61,8 @@ static GenericHandler *lastGenericPtr = NULL; * its `next' entry. We deal with the problem by using the `delete flag' and * deleting handlers only when it's known that there's no handler active. * - * The following variable has a non-zero value when a handler is active. */ -static int genericHandlersActive = 0; - /* * The following structure is used for queueing X-style events on the * Tcl event queue. @@ -134,15 +122,37 @@ static unsigned long eventMasks[TK_LASTEVENT] = { MouseWheelMask /* MouseWheelEvent */ }; + /* - * If someone has called Tk_RestrictEvents, the information below - * keeps track of it. + * The structure below is used to store Data for the Event module that + * must be kept thread-local. The "dataKey" is used to fetch the + * thread-specific storage for the current thread. */ -static Tk_RestrictProc *restrictProc; +typedef struct ThreadSpecificData { + + int genericHandlersActive; + /* The following variable has a non-zero + * value when a handler is active. */ + InProgress *pendingPtr; + /* Topmost search in progress, or + * NULL if none. */ + GenericHandler *genericList; + /* First handler in the list, or NULL. */ + GenericHandler *lastGenericPtr; + /* Last handler in list. */ + + /* + * If someone has called Tk_RestrictEvents, the information below + * keeps track of it. + */ + + Tk_RestrictProc *restrictProc; /* Procedure to call. NULL means no * restrictProc is currently in effect. */ -static ClientData restrictArg; /* Argument to pass to restrictProc. */ + ClientData restrictArg; /* Argument to pass to restrictProc. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; /* * Prototypes for procedures that are only referenced locally within @@ -266,6 +276,8 @@ Tk_DeleteEventHandler(token, mask, proc, clientData) register InProgress *ipPtr; TkEventHandler *prevPtr; register TkWindow *winPtr = (TkWindow *) token; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * Find the event handler to be deleted, or return @@ -288,7 +300,7 @@ Tk_DeleteEventHandler(token, mask, proc, clientData) * process the next one instead. */ - for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { + for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { if (ipPtr->nextHandler == handlerPtr) { ipPtr->nextHandler = handlerPtr->nextPtr; } @@ -337,6 +349,8 @@ Tk_CreateGenericHandler(proc, clientData) ClientData clientData; /* One-word value to pass to proc. */ { GenericHandler *handlerPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); handlerPtr = (GenericHandler *) ckalloc (sizeof (GenericHandler)); @@ -344,12 +358,12 @@ Tk_CreateGenericHandler(proc, clientData) handlerPtr->clientData = clientData; handlerPtr->deleteFlag = 0; handlerPtr->nextPtr = NULL; - if (genericList == NULL) { - genericList = handlerPtr; + if (tsdPtr->genericList == NULL) { + tsdPtr->genericList = handlerPtr; } else { - lastGenericPtr->nextPtr = handlerPtr; + tsdPtr->lastGenericPtr->nextPtr = handlerPtr; } - lastGenericPtr = handlerPtr; + tsdPtr->lastGenericPtr = handlerPtr; } /* @@ -377,8 +391,10 @@ Tk_DeleteGenericHandler(proc, clientData) ClientData clientData; { GenericHandler * handler; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - for (handler = genericList; handler; handler = handler->nextPtr) { + for (handler = tsdPtr->genericList; handler; handler = handler->nextPtr) { if ((handler->proc == proc) && (handler->clientData == clientData)) { handler->deleteFlag = 1; } @@ -388,6 +404,39 @@ Tk_DeleteGenericHandler(proc, clientData) /* *-------------------------------------------------------------- * + * TkEventInit -- + * + * This procedures initializes all the event module + * structures used by the current thread. It must be + * called before any other procedure in this file is + * called. + * + * Results: + * None. + * + * Side Effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +TkEventInit _ANSI_ARGS_((void)) +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + tsdPtr->genericHandlersActive = 0; + tsdPtr->pendingPtr = NULL; + tsdPtr->genericList = NULL; + tsdPtr->lastGenericPtr = NULL; + tsdPtr->restrictProc = NULL; + tsdPtr->restrictArg = NULL; +} + +/* + *-------------------------------------------------------------- + * * Tk_HandleEvent -- * * Given an event, invoke all the handlers that have @@ -415,6 +464,35 @@ Tk_HandleEvent(eventPtr) Window handlerWindow; TkDisplay *dispPtr; Tcl_Interp *interp = (Tcl_Interp *) NULL; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + /* + * Hack for simulated X-events: Correct the state field + * of the event record to match with the ButtonPress + * and ButtonRelease events. + */ + + if (eventPtr->type==ButtonPress) { + dispPtr = TkGetDisplay(eventPtr->xbutton.display); + eventPtr->xbutton.state |= dispPtr->mouseButtonState; + switch (eventPtr->xbutton.button) { + case 1: dispPtr->mouseButtonState |= Button1Mask; break; + case 2: dispPtr->mouseButtonState |= Button2Mask; break; + case 3: dispPtr->mouseButtonState |= Button3Mask; break; + } + } else if (eventPtr->type==ButtonRelease) { + dispPtr = TkGetDisplay(eventPtr->xbutton.display); + switch (eventPtr->xbutton.button) { + case 1: dispPtr->mouseButtonState &= ~Button1Mask; break; + case 2: dispPtr->mouseButtonState &= ~Button2Mask; break; + case 3: dispPtr->mouseButtonState &= ~Button3Mask; break; + } + eventPtr->xbutton.state |= dispPtr->mouseButtonState; + } else if (eventPtr->type==MotionNotify) { + dispPtr = TkGetDisplay(eventPtr->xmotion.display); + eventPtr->xmotion.state |= dispPtr->mouseButtonState; + } /* * Next, invoke all the generic event handlers (those that are @@ -422,9 +500,10 @@ Tk_HandleEvent(eventPtr) * an event is fully processed, go no further. */ - for (genPrevPtr = NULL, genericPtr = genericList; genericPtr != NULL; ) { + for (genPrevPtr = NULL, genericPtr = tsdPtr->genericList; + genericPtr != NULL; ) { if (genericPtr->deleteFlag) { - if (!genericHandlersActive) { + if (!tsdPtr->genericHandlersActive) { GenericHandler *tmpPtr; /* @@ -435,12 +514,12 @@ Tk_HandleEvent(eventPtr) tmpPtr = genericPtr->nextPtr; if (genPrevPtr == NULL) { - genericList = tmpPtr; + tsdPtr->genericList = tmpPtr; } else { genPrevPtr->nextPtr = tmpPtr; } if (tmpPtr == NULL) { - lastGenericPtr = genPrevPtr; + tsdPtr->lastGenericPtr = genPrevPtr; } (void) ckfree((char *) genericPtr); genericPtr = tmpPtr; @@ -449,9 +528,9 @@ Tk_HandleEvent(eventPtr) } else { int done; - genericHandlersActive++; + tsdPtr->genericHandlersActive++; done = (*genericPtr->proc)(genericPtr->clientData, eventPtr); - genericHandlersActive--; + tsdPtr->genericHandlersActive--; if (done) { return; } @@ -590,19 +669,20 @@ Tk_HandleEvent(eventPtr) * input context for the window if it hasn't already been done * (XFilterEvent needs this context). */ - - if (!(winPtr->flags & TK_CHECKED_IC)) { - if (winPtr->dispPtr->inputMethod != NULL) { - winPtr->inputContext = XCreateIC( + if (winPtr->dispPtr->useInputMethods) { + if (!(winPtr->flags & TK_CHECKED_IC)) { + if (winPtr->dispPtr->inputMethod != NULL) { + winPtr->inputContext = XCreateIC( winPtr->dispPtr->inputMethod, XNInputStyle, XIMPreeditNothing|XIMStatusNothing, XNClientWindow, winPtr->window, XNFocusWindow, winPtr->window, NULL); + } + winPtr->flags |= TK_CHECKED_IC; + } + if (XFilterEvent(eventPtr, None)) { + goto done; } - winPtr->flags |= TK_CHECKED_IC; - } - if (XFilterEvent(eventPtr, None)) { - goto done; } #endif /* TK_USE_INPUT_METHODS */ @@ -623,8 +703,8 @@ Tk_HandleEvent(eventPtr) ip.eventPtr = eventPtr; ip.winPtr = winPtr; ip.nextHandler = NULL; - ip.nextPtr = pendingPtr; - pendingPtr = &ip; + ip.nextPtr = tsdPtr->pendingPtr; + tsdPtr->pendingPtr = &ip; if (mask == 0) { if ((eventPtr->type == SelectionClear) || (eventPtr->type == SelectionRequest) @@ -657,7 +737,7 @@ Tk_HandleEvent(eventPtr) TkBindEventProc(winPtr, eventPtr); } } - pendingPtr = ip.nextPtr; + tsdPtr->pendingPtr = ip.nextPtr; done: /* @@ -695,6 +775,8 @@ TkEventDeadWindow(winPtr) { register TkEventHandler *handlerPtr; register InProgress *ipPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * While deleting all the handlers, be careful to check for @@ -706,7 +788,8 @@ TkEventDeadWindow(winPtr) while (winPtr->handlerList != NULL) { handlerPtr = winPtr->handlerList; winPtr->handlerList = handlerPtr->nextPtr; - for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { + for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; + ipPtr = ipPtr->nextPtr) { if (ipPtr->nextHandler == handlerPtr) { ipPtr->nextHandler = NULL; } @@ -744,11 +827,13 @@ TkCurrentTime(dispPtr) TkDisplay *dispPtr; /* Display for which the time is desired. */ { register XEvent *eventPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - if (pendingPtr == NULL) { + if (tsdPtr->pendingPtr == NULL) { return dispPtr->lastEventTime; } - eventPtr = pendingPtr->eventPtr; + eventPtr = tsdPtr->pendingPtr->eventPtr; switch (eventPtr->type) { case ButtonPress: case ButtonRelease: @@ -798,11 +883,13 @@ Tk_RestrictEvents(proc, arg, prevArgPtr) * argument. */ { Tk_RestrictProc *prev; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - prev = restrictProc; - *prevArgPtr = restrictArg; - restrictProc = proc; - restrictArg = arg; + prev = tsdPtr->restrictProc; + *prevArgPtr = tsdPtr->restrictArg; + tsdPtr->restrictProc = proc; + tsdPtr->restrictArg = arg; return prev; } @@ -841,7 +928,7 @@ Tk_QueueWindowEvent(eventPtr, position) * Find our display structure for the event's display. */ - for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) { + for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) { if (dispPtr == NULL) { return; } @@ -962,12 +1049,14 @@ WindowEventProc(evPtr, flags) { TkWindowEvent *wevPtr = (TkWindowEvent *) evPtr; Tk_RestrictAction result; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (!(flags & TCL_WINDOW_EVENTS)) { return 0; } - if (restrictProc != NULL) { - result = (*restrictProc)(restrictArg, &wevPtr->event); + if (tsdPtr->restrictProc != NULL) { + result = (*tsdPtr->restrictProc)(tsdPtr->restrictArg, &wevPtr->event); if (result != TK_PROCESS_EVENT) { if (result == TK_DEFER_EVENT) { return 0; @@ -1041,3 +1130,4 @@ Tk_MainLoop() Tcl_DoOneEvent(0); } } + diff --git a/tk/generic/tkFileFilter.c b/tk/generic/tkFileFilter.c index 258f6fdf604..7604746bf9f 100644 --- a/tk/generic/tkFileFilter.c +++ b/tk/generic/tkFileFilter.c @@ -10,7 +10,6 @@ * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id$ - * */ #include "tkInt.h" @@ -484,3 +483,4 @@ FreeMacFileTypes(clausePtr) } clausePtr->macTypes = NULL; } + diff --git a/tk/generic/tkFileFilter.h b/tk/generic/tkFileFilter.h index 1550d76b45b..ec4d43f9c76 100644 --- a/tk/generic/tkFileFilter.h +++ b/tk/generic/tkFileFilter.h @@ -90,3 +90,4 @@ EXTERN int TkGetFileFilters _ANSI_ARGS_ ((Tcl_Interp *interp, # define TCL_STORAGE_CLASS DLLIMPORT #endif + diff --git a/tk/generic/tkFocus.c b/tk/generic/tkFocus.c index 4cd35ce9fe2..8ed77cbb309 100644 --- a/tk/generic/tkFocus.c +++ b/tk/generic/tkFocus.c @@ -76,12 +76,6 @@ typedef struct TkDisplayFocusInfo { } DisplayFocusInfo; /* - * Global used for debugging. - */ - -int tclFocusDebug = 0; - -/* * The following magic value is stored in the "send_event" field of * FocusIn and FocusOut events that are generated in this file. This * allows us to separate "real" events coming from the server from @@ -101,12 +95,11 @@ static void FocusMapProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static void GenerateFocusEvents _ANSI_ARGS_((TkWindow *sourcePtr, TkWindow *destPtr)); -static void SetFocus _ANSI_ARGS_((TkWindow *winPtr, int force)); /* *-------------------------------------------------------------- * - * Tk_FocusCmd -- + * Tk_FocusObjCmd -- * * This procedure is invoked to process the "focus" Tcl command. * See the user documentation for details on what it does. @@ -121,28 +114,30 @@ static void SetFocus _ANSI_ARGS_((TkWindow *winPtr, int force)); */ int -Tk_FocusCmd(clientData, interp, argc, argv) +Tk_FocusObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { + static char *focusOptions[] = {"-displayof", "-force", "-lastfor", + (char *) NULL}; Tk_Window tkwin = (Tk_Window) clientData; TkWindow *winPtr = (TkWindow *) clientData; TkWindow *newPtr, *focusWinPtr, *topLevelPtr; ToplevelFocusInfo *tlFocusPtr; - char c; - size_t length; + char *windowName; + int index; /* * If invoked with no arguments, just return the current focus window. */ - if (argc == 1) { + if (objc == 1) { focusWinPtr = TkGetFocusWin(winPtr); if (focusWinPtr != NULL) { - interp->result = focusWinPtr->pathName; + Tcl_SetResult(interp, focusWinPtr->pathName, TCL_STATIC); } return TCL_OK; } @@ -152,81 +147,94 @@ Tk_FocusCmd(clientData, interp, argc, argv) * on that window. */ - if (argc == 2) { - if (argv[1][0] == 0) { + if (objc == 2) { + windowName = Tcl_GetStringFromObj(objv[1], (int *) NULL); + + /* + * The empty string case exists for backwards compatibility. + */ + + if (windowName[0] == '\0') { return TCL_OK; } - if (argv[1][0] == '.') { - newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin); + if (windowName[0] == '.') { + newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin); if (newPtr == NULL) { return TCL_ERROR; } if (!(newPtr->flags & TK_ALREADY_DEAD)) { - SetFocus(newPtr, 0); + TkSetFocusWin(newPtr, 0); } return TCL_OK; } } - length = strlen(argv[1]); - c = argv[1][1]; - if ((c == 'd') && (strncmp(argv[1], "-displayof", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " -displayof window\"", (char *) NULL); - return TCL_ERROR; - } - newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); - if (newPtr == NULL) { - return TCL_ERROR; - } - newPtr = TkGetFocusWin(newPtr); - if (newPtr != NULL) { - interp->result = newPtr->pathName; - } - } else if ((c == 'f') && (strncmp(argv[1], "-force", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " -force window\"", (char *) NULL); - return TCL_ERROR; - } - if (argv[2][0] == 0) { - return TCL_OK; - } - newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); - if (newPtr == NULL) { - return TCL_ERROR; - } - SetFocus(newPtr, 1); - } else if ((c == 'l') && (strncmp(argv[1], "-lastfor", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " -lastfor window\"", (char *) NULL); - return TCL_ERROR; + if (Tcl_GetIndexFromObj(interp, objv[1], focusOptions, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "window"); + return TCL_ERROR; + } + switch (index) { + case 0: { /* -displayof */ + windowName = Tcl_GetStringFromObj(objv[2], (int *) NULL); + newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin); + if (newPtr == NULL) { + return TCL_ERROR; + } + newPtr = TkGetFocusWin(newPtr); + if (newPtr != NULL) { + Tcl_SetResult(interp, newPtr->pathName, TCL_STATIC); + } + break; } - newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); - if (newPtr == NULL) { - return TCL_ERROR; + case 1: { /* -force */ + windowName = Tcl_GetStringFromObj(objv[2], (int *) NULL); + + /* + * The empty string case exists for backwards compatibility. + */ + + if (windowName[0] == '\0') { + return TCL_OK; + } + newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin); + if (newPtr == NULL) { + return TCL_ERROR; + } + TkSetFocusWin(newPtr, 1); + break; } - for (topLevelPtr = newPtr; topLevelPtr != NULL; - topLevelPtr = topLevelPtr->parentPtr) { - if (topLevelPtr->flags & TK_TOP_LEVEL) { - for (tlFocusPtr = newPtr->mainPtr->tlFocusPtr; - tlFocusPtr != NULL; - tlFocusPtr = tlFocusPtr->nextPtr) { - if (tlFocusPtr->topLevelPtr == topLevelPtr) { - interp->result = tlFocusPtr->focusWinPtr->pathName; - return TCL_OK; + case 2: { /* -lastfor */ + windowName = Tcl_GetStringFromObj(objv[2], (int *) NULL); + newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin); + if (newPtr == NULL) { + return TCL_ERROR; + } + for (topLevelPtr = newPtr; topLevelPtr != NULL; + topLevelPtr = topLevelPtr->parentPtr) { + if (topLevelPtr->flags & TK_TOP_LEVEL) { + for (tlFocusPtr = newPtr->mainPtr->tlFocusPtr; + tlFocusPtr != NULL; + tlFocusPtr = tlFocusPtr->nextPtr) { + if (tlFocusPtr->topLevelPtr == topLevelPtr) { + Tcl_SetResult(interp, + tlFocusPtr->focusWinPtr->pathName, + TCL_STATIC); + return TCL_OK; + } } + Tcl_SetResult(interp, topLevelPtr->pathName, TCL_STATIC); + return TCL_OK; } - interp->result = topLevelPtr->pathName; - return TCL_OK; } + break; + } + default: { + panic("bad const entries to focusOptions in focus command"); } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be -displayof, -force, or -lastfor", (char *) NULL); - return TCL_ERROR; } return TCL_OK; } @@ -300,7 +308,7 @@ TkFocusFilterEvent(winPtr, eventPtr) if ((eventPtr->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS) && (eventPtr->type == FocusIn)) { - SetFocus(winPtr, eventPtr->xfocus.detail); + TkSetFocusWin(winPtr, eventPtr->xfocus.detail); return 0; } @@ -479,7 +487,7 @@ TkFocusFilterEvent(winPtr, eventPtr) if (eventPtr->xcrossing.focus && (displayFocusPtr->focusWinPtr == NULL) && !(winPtr->flags & TK_EMBEDDED)) { - if (tclFocusDebug) { + if (dispPtr->focusDebug) { printf("Focussed implicitly on %s\n", newFocusPtr->pathName); } @@ -504,7 +512,7 @@ TkFocusFilterEvent(winPtr, eventPtr) if ((dispPtr->implicitWinPtr != NULL) && !(winPtr->flags & TK_EMBEDDED)) { - if (tclFocusDebug) { + if (dispPtr->focusDebug) { printf("Defocussed implicit Async\n"); } GenerateFocusEvents(displayFocusPtr->focusWinPtr, @@ -521,7 +529,7 @@ TkFocusFilterEvent(winPtr, eventPtr) /* *---------------------------------------------------------------------- * - * SetFocus -- + * TkSetFocusWin -- * * This procedure is invoked to change the focus window for a * given display in a given application. @@ -536,8 +544,8 @@ TkFocusFilterEvent(winPtr, eventPtr) *---------------------------------------------------------------------- */ -static void -SetFocus(winPtr, force) +void +TkSetFocusWin(winPtr, force) TkWindow *winPtr; /* Window that is to be the new focus for * its display and application. */ int force; /* If non-zero, set the X focus to this @@ -550,8 +558,14 @@ SetFocus(winPtr, force) int allMapped, serial; displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr); - /* CYGNUS LOCAL: We can't just return if force is set. */ - if (winPtr == displayFocusPtr->focusWinPtr && ! force) { + + /* + * If force is set, we should make sure we grab the focus regardless + * of the current focus window since under Windows, we may need to + * take control away from another application. + */ + + if (winPtr == displayFocusPtr->focusWinPtr && !force) { return; } @@ -814,7 +828,7 @@ TkFocusDeadWindow(winPtr) */ if (dispPtr->implicitWinPtr == winPtr) { - if (tclFocusDebug) { + if (dispPtr->focusDebug) { printf("releasing focus to root after %s died\n", tlFocusPtr->topLevelPtr->pathName); } @@ -842,7 +856,7 @@ TkFocusDeadWindow(winPtr) tlFocusPtr->focusWinPtr = tlFocusPtr->topLevelPtr; if ((displayFocusPtr->focusWinPtr == winPtr) && !(tlFocusPtr->topLevelPtr->flags & TK_ALREADY_DEAD)) { - if (tclFocusDebug) { + if (dispPtr->focusDebug) { printf("forwarding focus to %s after %s died\n", tlFocusPtr->topLevelPtr->pathName, winPtr->pathName); @@ -937,14 +951,14 @@ FocusMapProc(clientData, eventPtr) if (eventPtr->type == VisibilityNotify) { displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr); - if (tclFocusDebug) { + if (winPtr->dispPtr->focusDebug) { printf("auto-focussing on %s, force %d\n", winPtr->pathName, displayFocusPtr->forceFocus); } Tk_DeleteEventHandler((Tk_Window) winPtr, VisibilityChangeMask, FocusMapProc, clientData); displayFocusPtr->focusOnMapPtr = NULL; - SetFocus(winPtr, displayFocusPtr->forceFocus); + TkSetFocusWin(winPtr, displayFocusPtr->forceFocus); } } @@ -997,3 +1011,4 @@ FindDisplayFocusInfo(mainPtr, dispPtr) mainPtr->displayFocusPtr = displayFocusPtr; return displayFocusPtr; } + diff --git a/tk/generic/tkFont.c b/tk/generic/tkFont.c index 018199f6c2b..4ced32a9e59 100644 --- a/tk/generic/tkFont.c +++ b/tk/generic/tkFont.c @@ -6,7 +6,7 @@ * displaying text. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -14,6 +14,7 @@ * RCS: @(#) $Id$ */ +#include "tkPort.h" #include "tkInt.h" #include "tkFont.h" @@ -25,26 +26,19 @@ typedef struct TkFontInfo { Tcl_HashTable fontCache; /* Map a string to an existing Tk_Font. - * Keys are CachedFontKey structs, values are - * TkFont structs. */ + * Keys are string font names, values are + * TkFont pointers. */ Tcl_HashTable namedTable; /* Map a name to a set of attributes for a * font, used when constructing a Tk_Font from * a named font description. Keys are - * Tk_Uids, values are NamedFont structs. */ + * strings, values are NamedFont pointers. */ TkMainInfo *mainPtr; /* Application that owns this structure. */ - int updatePending; + int updatePending; /* Non-zero when a World Changed event has + * already been queued to handle a change to + * a named font. */ } TkFontInfo; /* - * The following structure is used as a key in the fontCache. - */ - -typedef struct CachedFontKey { - Display *display; /* Display for which font was constructed. */ - Tk_Uid string; /* String that describes font. */ -} CachedFontKey; - -/* * The following data structure is used to keep track of the font attributes * for each named font that has been defined. The named font is only deleted * when the last reference to it goes away. @@ -77,6 +71,7 @@ typedef struct LayoutChunk { CONST char *start; /* Pointer to simple string to be displayed. * This is a pointer into the TkTextLayout's * string. */ + int numBytes; /* The number of bytes in this chunk. */ int numChars; /* The number of characters in this chunk. */ int numDisplayChars; /* The number of characters to display when * this chunk is displayed. Can be less than @@ -168,13 +163,6 @@ static TkStateMap xlfdSetwidthMap[] = { {TK_SW_UNKNOWN, NULL} }; -static TkStateMap xlfdCharsetMap[] = { - {TK_CS_NORMAL, "iso8859"}, - {TK_CS_SYMBOL, "adobe"}, - {TK_CS_SYMBOL, "sun"}, - {TK_CS_OTHER, NULL} -}; - /* * The following structure and defines specify the valid builtin options * when configuring a set of font attributes. @@ -196,7 +184,136 @@ static char *fontOpt[] = { #define FONT_SLANT 3 #define FONT_UNDERLINE 4 #define FONT_OVERSTRIKE 5 -#define FONT_NUMFIELDS 6 /* Length of fontOpt array. */ +#define FONT_NUMFIELDS 6 + +/* + * Hardcoded font aliases. These are used to describe (mostly) identical + * fonts whose names differ from platform to platform. If the + * user-supplied font name matches any of the names in one of the alias + * lists, the other names in the alias list are also automatically tried. + */ + +static char *timesAliases[] = { + "Times", /* Unix. */ + "Times New Roman", /* Windows. */ + "New York", /* Mac. */ + NULL +}; + +static char *helveticaAliases[] = { + "Helvetica", /* Unix. */ + "Arial", /* Windows. */ + "Geneva", /* Mac. */ + NULL +}; + +static char *courierAliases[] = { + "Courier", /* Unix and Mac. */ + "Courier New", /* Windows. */ + NULL +}; + +static char *minchoAliases[] = { + "mincho", /* Unix. */ + "\357\274\255\357\274\263 \346\230\216\346\234\235", + /* Windows (MS mincho). */ + "\346\234\254\346\230\216\346\234\235\342\210\222\357\274\255", + /* Mac (honmincho-M). */ + NULL +}; + +static char *gothicAliases[] = { + "gothic", /* Unix. */ + "\357\274\255\357\274\263 \343\202\264\343\202\267\343\203\203\343\202\257", + /* Windows (MS goshikku). */ + "\344\270\270\343\202\264\343\202\267\343\203\203\343\202\257\342\210\222\357\274\255", + /* Mac (goshikku-M). */ + NULL +}; + +static char *dingbatsAliases[] = { + "dingbats", "zapfdingbats", "itc zapfdingbats", + /* Unix. */ + /* Windows. */ + "zapf dingbats", /* Mac. */ + NULL +}; + +static char **fontAliases[] = { + timesAliases, + helveticaAliases, + courierAliases, + minchoAliases, + gothicAliases, + dingbatsAliases, + NULL +}; + +/* + * Hardcoded font classes. If the character cannot be found in the base + * font, the classes are examined in order to see if some other similar + * font should be examined also. + */ + +static char *systemClass[] = { + "fixed", /* Unix. */ + /* Windows. */ + "chicago", "osaka", "sistemny", /* Mac. */ + NULL +}; + +static char *serifClass[] = { + "times", "palatino", "mincho", /* All platforms. */ + "song ti", /* Unix. */ + "ms serif", "simplified arabic", /* Windows. */ + "latinski", /* Mac. */ + NULL +}; + +static char *sansClass[] = { + "helvetica", "gothic", /* All platforms. */ + /* Unix. */ + "ms sans serif", "traditional arabic", + /* Windows. */ + "bastion", /* Mac. */ + NULL +}; + +static char *monoClass[] = { + "courier", "gothic", /* All platforms. */ + "fangsong ti", /* Unix. */ + "simplified arabic fixed", /* Windows. */ + "monaco", "pryamoy", /* Mac. */ + NULL +}; + +static char *symbolClass[] = { + "symbol", "dingbats", "wingdings", NULL +}; + +static char **fontFallbacks[] = { + systemClass, + serifClass, + sansClass, + monoClass, + symbolClass, + NULL +}; + +/* + * Global fallbacks. If the character could not be found in the preferred + * fallback list, this list is examined. If the character still cannot be + * found, all font families in the system are examined. + */ + +static char *globalFontClass[] = { + "symbol", /* All platforms. */ + /* Unix. */ + "lucida sans unicode", /* Windows. */ + "bitstream cyberbit", /* Windows popular CJK font */ + "chicago", /* Mac. */ + NULL +}; #define GetFontAttributes(tkfont) \ ((CONST TkFontAttributes *) &((TkFont *) (tkfont))->fa) @@ -208,7 +325,13 @@ static char *fontOpt[] = { static int ConfigAttributesObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, int objc, Tcl_Obj *CONST objv[], TkFontAttributes *faPtr)); +static int CreateNamedFont _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, CONST char *name, + TkFontAttributes *faPtr)); +static void DupFontObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr, + Tcl_Obj *dupObjPtr)); static int FieldSpecified _ANSI_ARGS_((CONST char *field)); +static void FreeFontObjProc _ANSI_ARGS_((Tcl_Obj *objPtr)); static int GetAttributeInfoObj _ANSI_ARGS_((Tcl_Interp *interp, CONST TkFontAttributes *faPtr, Tcl_Obj *objPtr)); static LayoutChunk * NewChunk _ANSI_ARGS_((TextLayout **layoutPtrPtr, @@ -218,12 +341,27 @@ static int ParseFontNameObj _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, TkFontAttributes *faPtr)); static void RecomputeWidgets _ANSI_ARGS_((TkWindow *winPtr)); +static int SetFontFromAny _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr)); static void TheWorldHasChanged _ANSI_ARGS_(( ClientData clientData)); -static void UpdateDependantFonts _ANSI_ARGS_((TkFontInfo *fiPtr, +static void UpdateDependentFonts _ANSI_ARGS_((TkFontInfo *fiPtr, Tk_Window tkwin, Tcl_HashEntry *namedHashPtr)); - +/* + * The following structure defines the implementation of the "font" Tcl + * object, used for drawing. The internalRep.twoPtrValue.ptr1 field of + * each font object points to the TkFont structure for the font, or + * NULL. + */ + +static Tcl_ObjType fontObjType = { + "font", /* name */ + FreeFontObjProc, /* freeIntRepProc */ + DupFontObjProc, /* dupIntRepProc */ + NULL, /* updateStringProc */ + SetFontFromAny /* setFromAnyProc */ +}; /* @@ -236,8 +374,8 @@ static void UpdateDependantFonts _ANSI_ARGS_((TkFontInfo *fiPtr, * package on a per application basis. * * Results: - * Returns a token that must be stored in the TkMainInfo for this - * application. + * Stores a token in the mainPtr to hold information needed by this + * package on a per application basis. * * Side effects: * Memory allocated. @@ -251,11 +389,13 @@ TkFontPkgInit(mainPtr) TkFontInfo *fiPtr; fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo)); - Tcl_InitHashTable(&fiPtr->fontCache, sizeof(CachedFontKey) / sizeof(int)); - Tcl_InitHashTable(&fiPtr->namedTable, TCL_ONE_WORD_KEYS); + Tcl_InitHashTable(&fiPtr->fontCache, TCL_STRING_KEYS); + Tcl_InitHashTable(&fiPtr->namedTable, TCL_STRING_KEYS); fiPtr->mainPtr = mainPtr; fiPtr->updatePending = 0; mainPtr->fontInfoPtr = fiPtr; + + TkpFontPkgInit(mainPtr); } /* @@ -281,12 +421,21 @@ TkFontPkgFree(mainPtr) TkMainInfo *mainPtr; /* The application being deleted. */ { TkFontInfo *fiPtr; - Tcl_HashEntry *hPtr; + Tcl_HashEntry *hPtr, *searchPtr; Tcl_HashSearch search; + int fontsLeft; fiPtr = mainPtr->fontInfoPtr; - if (fiPtr->fontCache.numEntries != 0) { + fontsLeft = 0; + for (searchPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search); + searchPtr != NULL; + searchPtr = Tcl_NextHashEntry(&search)) { + fontsLeft++; + fprintf(stderr, "Font %s still in cache.\n", + Tcl_GetHashKey(&fiPtr->fontCache, searchPtr)); + } + if (fontsLeft) { panic("TkFontPkgFree: all fonts should have been freed already"); } Tcl_DeleteHashTable(&fiPtr->fontCache); @@ -368,7 +517,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) "font ?-displayof window? ?option?"); return TCL_ERROR; } - tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]); + tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); if (tkfont == NULL) { return TCL_ERROR; } @@ -394,14 +543,14 @@ Tk_FontObjCmd(clientData, interp, objc, objv) Tcl_WrongNumArgs(interp, 2, objv, "fontname ?options?"); return TCL_ERROR; } - string = Tk_GetUid(Tcl_GetStringFromObj(objv[2], NULL)); + string = Tcl_GetString(objv[2]); namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string); nfPtr = NULL; /* lint. */ if (namedHashPtr != NULL) { nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); } if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "named font \"", string, + Tcl_AppendResult(interp, "named font \"", string, "\" doesn't exist", NULL); return TCL_ERROR; } @@ -412,7 +561,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) } else { result = ConfigAttributesObj(interp, tkwin, objc - 3, objv + 3, &nfPtr->fa); - UpdateDependantFonts(fiPtr, tkwin, namedHashPtr); + UpdateDependentFonts(fiPtr, tkwin, namedHashPtr); return result; } return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr); @@ -420,7 +569,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) case FONT_CREATE: { int skip, i; char *name; - char buf[32]; + char buf[16 + TCL_INTEGER_SPACE]; TkFontAttributes fa; Tcl_HashEntry *namedHashPtr; @@ -428,7 +577,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) if (objc < 3) { name = NULL; } else { - name = Tcl_GetStringFromObj(objv[2], NULL); + name = Tcl_GetString(objv[2]); if (name[0] == '-') { name = NULL; } @@ -440,8 +589,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) for (i = 1; ; i++) { sprintf(buf, "font%d", i); - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, - Tk_GetUid(buf)); + namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, buf); if (namedHashPtr == NULL) { break; } @@ -454,10 +602,10 @@ Tk_FontObjCmd(clientData, interp, objc, objv) &fa) != TCL_OK) { return TCL_ERROR; } - if (TkCreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) { + if (CreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) { return TCL_ERROR; } - Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1); + Tcl_AppendResult(interp, name, NULL); break; } case FONT_DELETE: { @@ -476,10 +624,10 @@ Tk_FontObjCmd(clientData, interp, objc, objv) return TCL_ERROR; } for (i = 2; i < objc; i++) { - string = Tk_GetUid(Tcl_GetStringFromObj(objv[i], NULL)); + string = Tcl_GetString(objv[i]); namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string); if (namedHashPtr == NULL) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "named font \"", string, + Tcl_AppendResult(interp, "named font \"", string, "\" doesn't exist", (char *) NULL); return TCL_ERROR; } @@ -511,6 +659,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) char *string; Tk_Font tkfont; int length, skip; + Tcl_Obj *resultPtr; skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin); if (skip < 0) { @@ -521,17 +670,17 @@ Tk_FontObjCmd(clientData, interp, objc, objv) "font ?-displayof window? text"); return TCL_ERROR; } - tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]); + tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); if (tkfont == NULL) { return TCL_ERROR; } string = Tcl_GetStringFromObj(objv[3 + skip], &length); - Tcl_SetIntObj(Tcl_GetObjResult(interp), Tk_TextWidth(tkfont, string, length)); + resultPtr = Tcl_GetObjResult(interp); + Tcl_SetIntObj(resultPtr, Tk_TextWidth(tkfont, string, length)); Tk_FreeFont(tkfont); break; } case FONT_METRICS: { - char buf[64]; Tk_Font tkfont; int skip, index, i; CONST TkFontMetrics *fmPtr; @@ -548,7 +697,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) "font ?-displayof window? ?option?"); return TCL_ERROR; } - tkfont = Tk_GetFontFromObj(interp, tkwin, objv[2]); + tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); if (tkfont == NULL) { return TCL_ERROR; } @@ -556,11 +705,13 @@ Tk_FontObjCmd(clientData, interp, objc, objv) objv += skip; fmPtr = GetFontMetrics(tkfont); if (objc == 3) { + char buf[64 + TCL_INTEGER_SPACE * 4]; + sprintf(buf, "-ascent %d -descent %d -linespace %d -fixed %d", fmPtr->ascent, fmPtr->descent, fmPtr->ascent + fmPtr->descent, fmPtr->fixed); - Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1); + Tcl_AppendResult(interp, buf, NULL); } else { if (Tcl_GetIndexFromObj(interp, objv[3], switches, "metric", 0, &index) != TCL_OK) { @@ -582,22 +733,23 @@ Tk_FontObjCmd(clientData, interp, objc, objv) } case FONT_NAMES: { char *string; - Tcl_Obj *strPtr; NamedFont *nfPtr; Tcl_HashSearch search; Tcl_HashEntry *namedHashPtr; + Tcl_Obj *strPtr, *resultPtr; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "names"); return TCL_ERROR; } + resultPtr = Tcl_GetObjResult(interp); namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search); while (namedHashPtr != NULL) { nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); if (nfPtr->deletePending == 0) { string = Tcl_GetHashKey(&fiPtr->namedTable, namedHashPtr); strPtr = Tcl_NewStringObj(string, -1); - Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), strPtr); + Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); } namedHashPtr = Tcl_NextHashEntry(&search); } @@ -610,7 +762,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) /* *--------------------------------------------------------------------------- * - * UpdateDependantFonts, TheWorldHasChanged, RecomputeWidgets -- + * UpdateDependentFonts, TheWorldHasChanged, RecomputeWidgets -- * * Called when the attributes of a named font changes. Updates all * the instantiated fonts that depend on that named font and then @@ -627,7 +779,7 @@ Tk_FontObjCmd(clientData, interp, objc, objv) */ static void -UpdateDependantFonts(fiPtr, tkwin, namedHashPtr) +UpdateDependentFonts(fiPtr, tkwin, namedHashPtr) TkFontInfo *fiPtr; /* Info about application's fonts. */ Tk_Window tkwin; /* A window in the application. */ Tcl_HashEntry *namedHashPtr;/* The named font that is changing. */ @@ -647,15 +799,16 @@ UpdateDependantFonts(fiPtr, tkwin, namedHashPtr) return; } - cacheHashPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search); while (cacheHashPtr != NULL) { - fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); - if (fontPtr->namedHashPtr == namedHashPtr) { - TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa); - if (fiPtr->updatePending == 0) { - fiPtr->updatePending = 1; - Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr); + for (fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); + fontPtr != NULL; fontPtr = fontPtr->nextPtr) { + if (fontPtr->namedHashPtr == namedHashPtr) { + TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa); + if (fiPtr->updatePending == 0) { + fiPtr->updatePending = 1; + Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr); + } } } cacheHashPtr = Tcl_NextHashEntry(&search); @@ -690,7 +843,7 @@ RecomputeWidgets(winPtr) /* *--------------------------------------------------------------------------- * - * TkCreateNamedFont -- + * CreateNamedFont -- * * Create the specified named font with the given attributes in the * named font table associated with the interp. @@ -698,7 +851,7 @@ RecomputeWidgets(winPtr) * Results: * Returns TCL_OK if the font was successfully created, or TCL_ERROR * if the named font already existed. If TCL_ERROR is returned, an - * error message is left in interp->result. + * error message is left in the interp's result. * * Side effects: * Assume there used to exist a named font by the specified name, and @@ -711,8 +864,8 @@ RecomputeWidgets(winPtr) *--------------------------------------------------------------------------- */ -int -TkCreateNamedFont(interp, tkwin, name, faPtr) +static int +CreateNamedFont(interp, tkwin, name, faPtr) Tcl_Interp *interp; /* Interp for error return. */ Tk_Window tkwin; /* A window associated with interp. */ CONST char *name; /* Name for the new named font. */ @@ -725,14 +878,13 @@ TkCreateNamedFont(interp, tkwin, name, faPtr) fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - name = Tk_GetUid(name); namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &new); if (new == 0) { nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); if (nfPtr->deletePending == 0) { - interp->result[0] = '\0'; - Tcl_AppendResult(interp, "font \"", name, + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "named font \"", name, "\" already exists", (char *) NULL); return TCL_ERROR; } @@ -745,7 +897,7 @@ TkCreateNamedFont(interp, tkwin, name, faPtr) nfPtr->fa = *faPtr; nfPtr->deletePending = 0; - UpdateDependantFonts(fiPtr, tkwin, namedHashPtr); + UpdateDependentFonts(fiPtr, tkwin, namedHashPtr); return TCL_OK; } @@ -769,13 +921,13 @@ TkCreateNamedFont(interp, tkwin, name, faPtr) * Results: * The return value is token for the font, or NULL if an error * prevented the font from being created. If NULL is returned, an - * error message will be left in interp->result. + * error message will be left in the interp's result. * * Side effects: - * Calls Tk_GetFontFromObj(), which modifies interp's result object, - * then copies the string from the result object into interp->result. - * This procedure will go away when Tk_ConfigureWidget() is - * made into an object command. + * The font is added to an internal database with a reference + * count. For each call to this procedure, there should eventually + * be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the + * database is cleaned up when fonts aren't in use anymore. * *--------------------------------------------------------------------------- */ @@ -787,26 +939,20 @@ Tk_GetFont(interp, tkwin, string) CONST char *string; /* String describing font, as: named font, * native format, or parseable string. */ { + Tk_Font tkfont; Tcl_Obj *strPtr; - Tk_Font tkfont; - - strPtr = Tcl_NewStringObj((char *) string, -1); - - tkfont = Tk_GetFontFromObj(interp, tkwin, strPtr); - if (tkfont == NULL) { - Tcl_SetResult(interp, - Tcl_GetStringFromObj(Tcl_GetObjResult(interp), NULL), - TCL_VOLATILE); - } - Tcl_DecrRefCount(strPtr); /* done with object */ + strPtr = Tcl_NewStringObj((char *) string, -1); + Tcl_IncrRefCount(strPtr); + tkfont = Tk_AllocFontFromObj(interp, tkwin, strPtr); + Tcl_DecrRefCount(strPtr); return tkfont; } /* *--------------------------------------------------------------------------- * - * Tk_GetFontFromObj -- + * Tk_AllocFontFromObj -- * * Given a string description of a font, map the description to a * corresponding Tk_Font that represents the font. @@ -819,46 +965,77 @@ Tk_GetFont(interp, tkwin, string) * Side effects: * The font is added to an internal database with a reference * count. For each call to this procedure, there should eventually - * be a call to Tk_FreeFont() so that the database is cleaned up when - * fonts aren't in use anymore. + * be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the + * database is cleaned up when fonts aren't in use anymore. * *--------------------------------------------------------------------------- */ Tk_Font -Tk_GetFontFromObj(interp, tkwin, objPtr) +Tk_AllocFontFromObj(interp, tkwin, objPtr) Tcl_Interp *interp; /* Interp for database and error return. */ - Tk_Window tkwin; /* For display on which font will be used. */ + Tk_Window tkwin; /* For screen on which font will be used. */ Tcl_Obj *objPtr; /* Object describing font, as: named font, * native format, or parseable string. */ { TkFontInfo *fiPtr; - CachedFontKey key; Tcl_HashEntry *cacheHashPtr, *namedHashPtr; - TkFont *fontPtr; + TkFont *fontPtr, *firstFontPtr, *oldFontPtr; int new, descent; NamedFont *nfPtr; - char *string; - + fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; - string = Tcl_GetStringFromObj(objPtr, NULL); + if (objPtr->typePtr != &fontObjType) { + SetFontFromAny(interp, objPtr); + } - key.display = Tk_Display(tkwin); - key.string = Tk_GetUid(string); - cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache, (char *) &key, &new); + oldFontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; - if (new == 0) { - /* - * We have already constructed a font with this description for - * this display. Bump the reference count of the cached font. - */ + if (oldFontPtr != NULL) { + if (oldFontPtr->resourceRefCount == 0) { + /* + * This is a stale reference: it refers to a TkFont that's + * no longer in use. Clear the reference. + */ - fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); - fontPtr->refCount++; - return (Tk_Font) fontPtr; + FreeFontObjProc(objPtr); + oldFontPtr = NULL; + } else if (Tk_Screen(tkwin) == oldFontPtr->screen) { + oldFontPtr->resourceRefCount++; + return (Tk_Font) oldFontPtr; + } } - namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, key.string); + /* + * Next, search the list of fonts that have the name we want, to see + * if one of them is for the right screen. + */ + + new = 0; + if (oldFontPtr != NULL) { + cacheHashPtr = oldFontPtr->cacheHashPtr; + FreeFontObjProc(objPtr); + } else { + cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache, + Tcl_GetString(objPtr), &new); + } + firstFontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr); + for (fontPtr = firstFontPtr; (fontPtr != NULL); + fontPtr = fontPtr->nextPtr) { + if (Tk_Screen(tkwin) == fontPtr->screen) { + fontPtr->resourceRefCount++; + fontPtr->objRefCount++; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; + return (Tk_Font) fontPtr; + } + } + + /* + * The desired font isn't in the table. Make a new one. + */ + + namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, + Tcl_GetString(objPtr)); if (namedHashPtr != NULL) { /* * Construct a font based on a named font. @@ -873,15 +1050,19 @@ Tk_GetFontFromObj(interp, tkwin, objPtr) * Native font? */ - fontPtr = TkpGetNativeFont(tkwin, string); + fontPtr = TkpGetNativeFont(tkwin, Tcl_GetString(objPtr)); if (fontPtr == NULL) { TkFontAttributes fa; + Tcl_Obj *dupObjPtr = Tcl_DuplicateObj(objPtr); - TkInitFontAttributes(&fa); - if (ParseFontNameObj(interp, tkwin, objPtr, &fa) != TCL_OK) { - Tcl_DeleteHashEntry(cacheHashPtr); + if (ParseFontNameObj(interp, tkwin, dupObjPtr, &fa) != TCL_OK) { + if (new) { + Tcl_DeleteHashEntry(cacheHashPtr); + } + Tcl_DecrRefCount(dupObjPtr); return NULL; } + Tcl_DecrRefCount(dupObjPtr); /* * String contained the attributes inline. @@ -890,13 +1071,16 @@ Tk_GetFontFromObj(interp, tkwin, objPtr) fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa); } } - Tcl_SetHashValue(cacheHashPtr, fontPtr); - fontPtr->refCount = 1; - fontPtr->cacheHashPtr = cacheHashPtr; - fontPtr->namedHashPtr = namedHashPtr; + fontPtr->resourceRefCount = 1; + fontPtr->objRefCount = 1; + fontPtr->cacheHashPtr = cacheHashPtr; + fontPtr->namedHashPtr = namedHashPtr; + fontPtr->screen = Tk_Screen(tkwin); + fontPtr->nextPtr = firstFontPtr; + Tcl_SetHashValue(cacheHashPtr, fontPtr); - Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, 0, 0, &fontPtr->tabWidth); + Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, -1, 0, &fontPtr->tabWidth); if (fontPtr->tabWidth == 0) { fontPtr->tabWidth = fontPtr->fm.maxWidth; } @@ -918,7 +1102,7 @@ Tk_GetFontFromObj(interp, tkwin, objPtr) descent = fontPtr->fm.descent; fontPtr->underlinePos = descent / 2; - fontPtr->underlineHeight = fontPtr->fa.pointsize / 10; + fontPtr->underlineHeight = TkFontGetPixels(tkwin, fontPtr->fa.size) / 10; if (fontPtr->underlineHeight == 0) { fontPtr->underlineHeight = 1; } @@ -936,10 +1120,125 @@ Tk_GetFontFromObj(interp, tkwin, objPtr) } } + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; return (Tk_Font) fontPtr; } /* + *---------------------------------------------------------------------- + * + * Tk_GetFontFromObj -- + * + * Find the font that corresponds to a given object. The font must + * have already been created by Tk_GetFont or Tk_AllocFontFromObj. + * + * Results: + * The return value is a token for the font that matches objPtr + * and is suitable for use in tkwin. + * + * Side effects: + * If the object is not already a font ref, the conversion will free + * any old internal representation. + * + *---------------------------------------------------------------------- + */ + +Tk_Font +Tk_GetFontFromObj(tkwin, objPtr) + Tk_Window tkwin; /* The window that the font will be used in. */ + Tcl_Obj *objPtr; /* The object from which to get the font. */ +{ + TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr; + TkFont *fontPtr; + Tcl_HashEntry *hashPtr; + + if (objPtr->typePtr != &fontObjType) { + SetFontFromAny((Tcl_Interp *) NULL, objPtr); + } + + fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; + + if (fontPtr != NULL) { + if (fontPtr->resourceRefCount == 0) { + /* + * This is a stale reference: it refers to a TkFont that's + * no longer in use. Clear the reference. + */ + + FreeFontObjProc(objPtr); + fontPtr = NULL; + } else if (Tk_Screen(tkwin) == fontPtr->screen) { + return (Tk_Font) fontPtr; + } + } + + /* + * Next, search the list of fonts that have the name we want, to see + * if one of them is for the right screen. + */ + + if (fontPtr != NULL) { + hashPtr = fontPtr->cacheHashPtr; + FreeFontObjProc(objPtr); + } else { + hashPtr = Tcl_FindHashEntry(&fiPtr->fontCache, Tcl_GetString(objPtr)); + } + if (hashPtr != NULL) { + for (fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); fontPtr != NULL; + fontPtr = fontPtr->nextPtr) { + if (Tk_Screen(tkwin) == fontPtr->screen) { + fontPtr->objRefCount++; + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; + return (Tk_Font) fontPtr; + } + } + } + + panic("Tk_GetFontFromObj called with non-existent font!"); + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * SetFontFromAny -- + * + * Convert the internal representation of a Tcl object to the + * font internal form. + * + * Results: + * Always returns TCL_OK. + * + * Side effects: + * The object is left with its typePtr pointing to fontObjType. + * The TkFont pointer is NULL. + * + *---------------------------------------------------------------------- + */ + +static int +SetFontFromAny(interp, objPtr) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + Tcl_Obj *objPtr; /* The object to convert. */ +{ + Tcl_ObjType *typePtr; + + /* + * Free the old internalRep before setting the new one. + */ + + Tcl_GetString(objPtr); + typePtr = objPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(objPtr); + } + objPtr->typePtr = &fontObjType; + objPtr->internalRep.twoPtrValue.ptr1 = NULL; + + return TCL_OK; +} + +/* *--------------------------------------------------------------------------- * * Tk_NameOfFont -- @@ -963,14 +1262,9 @@ Tk_NameOfFont(tkfont) Tk_Font tkfont; /* Font whose name is desired. */ { TkFont *fontPtr; - Tcl_HashEntry *hPtr; - CachedFontKey *keyPtr; fontPtr = (TkFont *) tkfont; - hPtr = fontPtr->cacheHashPtr; - - keyPtr = (CachedFontKey *) Tcl_GetHashKey(hPtr->tablePtr, hPtr); - return (char *) keyPtr->string; + return fontPtr->cacheHashPtr->key.string; } /* @@ -994,30 +1288,144 @@ void Tk_FreeFont(tkfont) Tk_Font tkfont; /* Font to be released. */ { - TkFont *fontPtr; + TkFont *fontPtr, *prevPtr; NamedFont *nfPtr; if (tkfont == NULL) { return; } fontPtr = (TkFont *) tkfont; - fontPtr->refCount--; - if (fontPtr->refCount == 0) { - if (fontPtr->namedHashPtr != NULL) { - /* - * The font is being deleted. Determine if the associated named - * font definition should and/or can be deleted too. - */ + fontPtr->resourceRefCount--; + if (fontPtr->resourceRefCount > 0) { + return; + } + if (fontPtr->namedHashPtr != NULL) { + /* + * This font derived from a named font. Reduce the reference + * count on the named font and free it if no-one else is + * using it. + */ - nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr); - nfPtr->refCount--; - if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) { - Tcl_DeleteHashEntry(fontPtr->namedHashPtr); - ckfree((char *) nfPtr); - } + nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr); + nfPtr->refCount--; + if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) { + Tcl_DeleteHashEntry(fontPtr->namedHashPtr); + ckfree((char *) nfPtr); + } + } + + prevPtr = (TkFont *) Tcl_GetHashValue(fontPtr->cacheHashPtr); + if (prevPtr == fontPtr) { + if (fontPtr->nextPtr == NULL) { + Tcl_DeleteHashEntry(fontPtr->cacheHashPtr); + } else { + Tcl_SetHashValue(fontPtr->cacheHashPtr, fontPtr->nextPtr); + } + } else { + while (prevPtr->nextPtr != fontPtr) { + prevPtr = prevPtr->nextPtr; } - Tcl_DeleteHashEntry(fontPtr->cacheHashPtr); - TkpDeleteFont(fontPtr); + prevPtr->nextPtr = fontPtr->nextPtr; + } + + TkpDeleteFont(fontPtr); + if (fontPtr->objRefCount == 0) { + ckfree((char *) fontPtr); + } +} + +/* + *--------------------------------------------------------------------------- + * + * Tk_FreeFontFromObj -- + * + * Called to release a font inside a Tcl_Obj *. Decrements the refCount + * of the font and removes it from the hash tables if necessary. + * + * Results: + * None. + * + * Side effects: + * The reference count associated with font is decremented, and + * only deallocated when no one is using it. + * + *--------------------------------------------------------------------------- + */ + +void +Tk_FreeFontFromObj(tkwin, objPtr) + Tk_Window tkwin; /* The window this font lives in. Needed + * for the screen value. */ + Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */ +{ + Tk_FreeFont(Tk_GetFontFromObj(tkwin, objPtr)); +} + +/* + *--------------------------------------------------------------------------- + * + * FreeFontObjProc -- + * + * This proc is called to release an object reference to a font. + * Called when the object's internal rep is released or when + * the cached fontPtr needs to be changed. + * + * Results: + * None. + * + * Side effects: + * The object reference count is decremented. When both it + * and the hash ref count go to zero, the font's resources + * are released. + * + *--------------------------------------------------------------------------- + */ + +static void +FreeFontObjProc(objPtr) + Tcl_Obj *objPtr; /* The object we are releasing. */ +{ + TkFont *fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1; + + if (fontPtr != NULL) { + fontPtr->objRefCount--; + if ((fontPtr->resourceRefCount == 0) && (fontPtr->objRefCount == 0)) { + ckfree((char *) fontPtr); + objPtr->internalRep.twoPtrValue.ptr1 = NULL; + } + } +} + +/* + *--------------------------------------------------------------------------- + * + * DupFontObjProc -- + * + * When a cached font object is duplicated, this is called to + * update the internal reps. + * + * Results: + * None. + * + * Side effects: + * The font's objRefCount is incremented and the internal rep + * of the copy is set to point to it. + * + *--------------------------------------------------------------------------- + */ + +static void +DupFontObjProc(srcObjPtr, dupObjPtr) + Tcl_Obj *srcObjPtr; /* The object we are copying from. */ + Tcl_Obj *dupObjPtr; /* The object we are copying to. */ +{ + TkFont *fontPtr = (TkFont *) srcObjPtr->internalRep.twoPtrValue.ptr1; + + dupObjPtr->typePtr = srcObjPtr->typePtr; + dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr; + + if (fontPtr != NULL) { + fontPtr->objRefCount++; } } @@ -1112,7 +1520,6 @@ Tk_GetFontMetrics(tkfont, fmPtr) *--------------------------------------------------------------------------- */ - int Tk_PostscriptFontName(tkfont, dsPtr) Tk_Font tkfont; /* Font in which text will be printed. */ @@ -1154,6 +1561,8 @@ Tk_PostscriptFontName(tkfont, dsPtr) } else if (strcasecmp(family, "ZapfDingbats") == 0) { family = "ZapfDingbats"; } else { + Tcl_UniChar ch; + /* * Inline, capitalize the first letter of each word, lowercase the * rest of the letters in each word, and then take out the spaces @@ -1165,16 +1574,19 @@ Tk_PostscriptFontName(tkfont, dsPtr) src = dest = Tcl_DStringValue(dsPtr) + len; upper = 1; - for (; *src != '\0'; src++, dest++) { - while (isspace(UCHAR(*src))) { + for (; *src != '\0'; ) { + while (isspace(UCHAR(*src))) { /* INTL: ISO space */ src++; upper = 1; } - *dest = *src; - if ((upper != 0) && (islower(UCHAR(*src)))) { - *dest = toupper(UCHAR(*src)); + src += Tcl_UtfToUniChar(src, &ch); + if (upper) { + ch = Tcl_UniCharToUpper(ch); + upper = 0; + } else { + ch = Tcl_UniCharToLower(ch); } - upper = 0; + dest += Tcl_UniCharToUtf(ch, dest); } *dest = '\0'; Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr)); @@ -1251,7 +1663,7 @@ Tk_PostscriptFontName(tkfont, dsPtr) } } - return fontPtr->fa.pointsize; + return fontPtr->fa.size; } /* @@ -1273,18 +1685,18 @@ Tk_PostscriptFontName(tkfont, dsPtr) */ int -Tk_TextWidth(tkfont, string, numChars) +Tk_TextWidth(tkfont, string, numBytes) Tk_Font tkfont; /* Font in which text will be measured. */ CONST char *string; /* String whose width will be computed. */ - int numChars; /* Number of characters to consider from + int numBytes; /* Number of bytes to consider from * string, or < 0 for strlen(). */ { int width; - if (numChars < 0) { - numChars = strlen(string); + if (numBytes < 0) { + numBytes = strlen(string); } - Tk_MeasureChars(tkfont, string, numChars, 0, 0, &width); + Tk_MeasureChars(tkfont, string, numBytes, -1, 0, &width); return width; } @@ -1311,8 +1723,8 @@ Tk_TextWidth(tkfont, string, numChars) */ void -Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstChar, - lastChar) +Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstByte, + lastByte) Display *display; /* Display on which to draw. */ Drawable drawable; /* Window or pixmap in which to draw. */ GC gc; /* Graphics context for actually drawing @@ -1324,16 +1736,17 @@ Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstChar, * underlined or overstruck. */ int x, y; /* Coordinates at which first character of * string is drawn. */ - int firstChar; /* Index of first character. */ - int lastChar; /* Index of one after the last character. */ + int firstByte; /* Index of first byte of first character. */ + int lastByte; /* Index of first byte after the last + * character. */ { TkFont *fontPtr; int startX, endX; fontPtr = (TkFont *) tkfont; - Tk_MeasureChars(tkfont, string, firstChar, 0, 0, &startX); - Tk_MeasureChars(tkfont, string, lastChar, 0, 0, &endX); + Tk_MeasureChars(tkfont, string, firstByte, -1, 0, &startX); + Tk_MeasureChars(tkfont, string, lastByte, -1, 0, &endX); XFillRectangle(display, drawable, gc, x + startX, y + fontPtr->underlinePos, (unsigned int) (endX - startX), @@ -1394,26 +1807,37 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, { TkFont *fontPtr; CONST char *start, *end, *special; - int n, y, charsThisChunk, maxChunks; + int n, y, bytesThisChunk, maxChunks; int baseline, height, curX, newX, maxWidth; TextLayout *layoutPtr; LayoutChunk *chunkPtr; CONST TkFontMetrics *fmPtr; -#define MAX_LINES 50 - int staticLineLengths[MAX_LINES]; + Tcl_DString lineBuffer; int *lineLengths; - int maxLines, curLine, layoutHeight; + int curLine, layoutHeight; - lineLengths = staticLineLengths; - maxLines = MAX_LINES; + Tcl_DStringInit(&lineBuffer); fontPtr = (TkFont *) tkfont; + if ((fontPtr == NULL) || (string == NULL)) { + if (widthPtr != NULL) { + *widthPtr = 0; + } + if (heightPtr != NULL) { + *heightPtr = 0; + } + return NULL; + } + fmPtr = &fontPtr->fm; height = fmPtr->ascent + fmPtr->descent; if (numChars < 0) { - numChars = strlen(string); + numChars = Tcl_NumUtfChars(string, -1); + } + if (wrapLength == 0) { + wrapLength = -1; } maxChunks = 1; @@ -1433,16 +1857,20 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, curX = 0; - end = string + numChars; + end = Tcl_UtfAtIndex(string, numChars); special = string; flags &= TK_IGNORE_TABS | TK_IGNORE_NEWLINES; flags |= TK_WHOLE_WORDS | TK_AT_LEAST_ONE; - curLine = 0; for (start = string; start < end; ) { if (start >= special) { /* * Find the next special character in the string. + * + * INTL: Note that it is safe to increment by byte, because we are + * looking for 7-bit characters that will appear unchanged in + * UTF-8. At some point we may need to support the full Unicode + * whitespace set. */ for (special = start; special < end; special++) { @@ -1466,15 +1894,15 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, chunkPtr = NULL; if (start < special) { - charsThisChunk = Tk_MeasureChars(tkfont, start, special - start, + bytesThisChunk = Tk_MeasureChars(tkfont, start, special - start, wrapLength - curX, flags, &newX); newX += curX; flags &= ~TK_AT_LEAST_ONE; - if (charsThisChunk > 0) { + if (bytesThisChunk > 0) { chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, - charsThisChunk, curX, newX, baseline); + bytesThisChunk, curX, newX, baseline); - start += charsThisChunk; + start += bytesThisChunk; curX = newX; } } @@ -1482,6 +1910,9 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, if ((start == special) && (special < end)) { /* * Handle the special character. + * + * INTL: Special will be pointing at a 7-bit character so we + * can safely treat it as a single byte. */ chunkPtr = NULL; @@ -1502,7 +1933,7 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, continue; } } else { - NewChunk(&layoutPtr, &maxChunks, start, 1, curX, 1000000000, + NewChunk(&layoutPtr, &maxChunks, start, 1, curX, curX, baseline)->numDisplayChars = -1; start++; goto wrapLine; @@ -1515,7 +1946,7 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, * Consume all extra spaces at end of line. */ - while ((start < end) && isspace(UCHAR(*start))) { + while ((start < end) && isspace(UCHAR(*start))) { /* INTL: ISO space */ if (!(flags & TK_IGNORE_NEWLINES)) { if ((*start == '\n') || (*start == '\r')) { break; @@ -1529,15 +1960,21 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, start++; } if (chunkPtr != NULL) { + CONST char *end; + /* * Append all the extra spaces on this line to the end of the - * last text chunk. + * last text chunk. This is a little tricky because we are + * switching back and forth between characters and bytes. */ - charsThisChunk = start - (chunkPtr->start + chunkPtr->numChars); - if (charsThisChunk > 0) { - chunkPtr->numChars += Tk_MeasureChars(tkfont, - chunkPtr->start + chunkPtr->numChars, charsThisChunk, - 0, 0, &chunkPtr->totalWidth); + + end = chunkPtr->start + chunkPtr->numBytes; + bytesThisChunk = start - end; + if (bytesThisChunk > 0) { + bytesThisChunk = Tk_MeasureChars(tkfont, end, bytesThisChunk, + -1, 0, &chunkPtr->totalWidth); + chunkPtr->numBytes += bytesThisChunk; + chunkPtr->numChars += Tcl_NumUtfChars(end, bytesThisChunk); chunkPtr->totalWidth += curX; } } @@ -1559,19 +1996,7 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, * can be centered or right justified, if necessary. */ - if (curLine >= maxLines) { - int *newLengths; - - newLengths = (int *) ckalloc(2 * maxLines * sizeof(int)); - memcpy((void *) newLengths, lineLengths, maxLines * sizeof(int)); - if (lineLengths != staticLineLengths) { - ckfree((char *) lineLengths); - } - lineLengths = newLengths; - maxLines *= 2; - } - lineLengths[curLine] = curX; - curLine++; + Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX)); curX = 0; baseline += height; @@ -1586,36 +2011,13 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, if ((layoutPtr->numChunks > 0) && ((flags & TK_IGNORE_NEWLINES) == 0)) { if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == '\n') { chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 0, curX, - 1000000000, baseline); + curX, baseline); chunkPtr->numDisplayChars = -1; + Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX)); baseline += height; } } - /* - * Using maximum line length, shift all the chunks so that the lines are - * all justified correctly. - */ - - curLine = 0; - chunkPtr = layoutPtr->chunks; - y = chunkPtr->y; - for (n = 0; n < layoutPtr->numChunks; n++) { - int extra; - - if (chunkPtr->y != y) { - curLine++; - y = chunkPtr->y; - } - extra = maxWidth - lineLengths[curLine]; - if (justify == TK_JUSTIFY_CENTER) { - chunkPtr->x += extra / 2; - } else if (justify == TK_JUSTIFY_RIGHT) { - chunkPtr->x += extra; - } - chunkPtr++; - } - layoutPtr->width = maxWidth; layoutHeight = baseline - fmPtr->ascent; if (layoutPtr->numChunks == 0) { @@ -1629,12 +2031,38 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, layoutPtr->numChunks = 1; layoutPtr->chunks[0].start = string; + layoutPtr->chunks[0].numBytes = 0; layoutPtr->chunks[0].numChars = 0; layoutPtr->chunks[0].numDisplayChars = -1; layoutPtr->chunks[0].x = 0; layoutPtr->chunks[0].y = fmPtr->ascent; layoutPtr->chunks[0].totalWidth = 0; layoutPtr->chunks[0].displayWidth = 0; + } else { + /* + * Using maximum line length, shift all the chunks so that the lines + * are all justified correctly. + */ + + curLine = 0; + chunkPtr = layoutPtr->chunks; + y = chunkPtr->y; + lineLengths = (int *) Tcl_DStringValue(&lineBuffer); + for (n = 0; n < layoutPtr->numChunks; n++) { + int extra; + + if (chunkPtr->y != y) { + curLine++; + y = chunkPtr->y; + } + extra = maxWidth - lineLengths[curLine]; + if (justify == TK_JUSTIFY_CENTER) { + chunkPtr->x += extra / 2; + } else if (justify == TK_JUSTIFY_RIGHT) { + chunkPtr->x += extra; + } + chunkPtr++; + } } if (widthPtr != NULL) { @@ -1643,9 +2071,7 @@ Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags, if (heightPtr != NULL) { *heightPtr = layoutHeight; } - if (lineLengths != staticLineLengths) { - ckfree((char *) lineLengths); - } + Tcl_DStringFree(&lineBuffer); return (Tk_TextLayout) layoutPtr; } @@ -1718,6 +2144,8 @@ Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar) { TextLayout *layoutPtr; int i, numDisplayChars, drawX; + CONST char *firstByte; + CONST char *lastByte; LayoutChunk *chunkPtr; layoutPtr = (TextLayout *) layout; @@ -1735,15 +2163,18 @@ Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar) if (firstChar <= 0) { drawX = 0; firstChar = 0; + firstByte = chunkPtr->start; } else { - Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start, firstChar, - 0, 0, &drawX); + firstByte = Tcl_UtfAtIndex(chunkPtr->start, firstChar); + Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start, + firstByte - chunkPtr->start, -1, 0, &drawX); } if (lastChar < numDisplayChars) { numDisplayChars = lastChar; } + lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars); Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont, - chunkPtr->start + firstChar, numDisplayChars - firstChar, + firstByte, lastByte - firstByte, x + chunkPtr->x + drawX, y + chunkPtr->y); } firstChar -= chunkPtr->numChars; @@ -1791,18 +2222,21 @@ Tk_UnderlineTextLayout(display, drawable, gc, layout, x, y, underline) int underline; /* Index of the single character to * underline, or -1 for no underline. */ { - TextLayout *layoutPtr; + TextLayout *layoutPtr = (TextLayout *) layout; TkFont *fontPtr; - int xx, yy, width, height; + int xx, yy, width, height, underlineByte; - if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0) - && (width != 0)) { - layoutPtr = (TextLayout *) layout; - fontPtr = (TkFont *) layoutPtr->tkfont; + if (underline > -1) { + underlineByte = Tcl_UtfAtIndex(layoutPtr->string, underline) + - layoutPtr->string; + if ((Tk_CharBbox(layout, underlineByte, &xx, &yy, &width, &height) != 0) + && (width != 0)) { + fontPtr = (TkFont *) layoutPtr->tkfont; - XFillRectangle(display, drawable, gc, x + xx, - y + yy + fontPtr->fm.ascent + fontPtr->underlinePos, - (unsigned int) width, (unsigned int) fontPtr->underlineHeight); + XFillRectangle(display, drawable, gc, x + xx, + y + yy + fontPtr->fm.ascent + fontPtr->underlinePos, + (unsigned int) width, (unsigned int) fontPtr->underlineHeight); + } } } @@ -1849,7 +2283,7 @@ Tk_PointToChar(layout, x, y) TextLayout *layoutPtr; LayoutChunk *chunkPtr, *lastPtr; TkFont *fontPtr; - int i, n, dummy, baseline, pos; + int i, n, dummy, baseline, pos, numChars; if (y < 0) { /* @@ -1867,6 +2301,7 @@ Tk_PointToChar(layout, x, y) layoutPtr = (TextLayout *) layout; fontPtr = (TkFont *) layoutPtr->tkfont; lastPtr = chunkPtr = layoutPtr->chunks; + numChars = 0; for (i = 0; i < layoutPtr->numChunks; i++) { baseline = chunkPtr->y; if (y < baseline + fontPtr->fm.descent) { @@ -1876,7 +2311,7 @@ Tk_PointToChar(layout, x, y) * the index of the first character on this line. */ - return chunkPtr->start - layoutPtr->string; + return numChars; } if (x >= layoutPtr->width) { /* @@ -1907,13 +2342,14 @@ Tk_PointToChar(layout, x, y) * tab or newline char. */ - return chunkPtr->start - layoutPtr->string; + return numChars; } n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start, - chunkPtr->numChars, x + 1 - chunkPtr->x, - TK_PARTIAL_OK, &dummy); - return (chunkPtr->start + n - 1) - layoutPtr->string; + chunkPtr->numBytes, x - chunkPtr->x, + 0, &dummy); + return numChars + Tcl_NumUtfChars(chunkPtr->start, n); } + numChars += chunkPtr->numChars; lastPtr = chunkPtr; chunkPtr++; i++; @@ -1925,12 +2361,13 @@ Tk_PointToChar(layout, x, y) * chunk on this line. */ - pos = (lastPtr->start + lastPtr->numChars) - layoutPtr->string; + pos = numChars; if (i < layoutPtr->numChunks) { pos--; } return pos; } + numChars += chunkPtr->numChars; lastPtr = chunkPtr; chunkPtr++; } @@ -1997,6 +2434,7 @@ Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr) int i, x, w; Tk_Font tkfont; TkFont *fontPtr; + CONST char *end; if (index < 0) { if (xPtr) @@ -2023,12 +2461,15 @@ Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr) goto check; } } else if (index < chunkPtr->numChars) { + end = Tcl_UtfAtIndex(chunkPtr->start, index); if (xPtr != NULL) { - Tk_MeasureChars(tkfont, chunkPtr->start, index, 0, 0, &x); + Tk_MeasureChars(tkfont, chunkPtr->start, + end - chunkPtr->start, -1, 0, &x); x += chunkPtr->x; } if (widthPtr != NULL) { - Tk_MeasureChars(tkfont, chunkPtr->start + index, 1, 0, 0, &w); + Tk_MeasureChars(tkfont, end, Tcl_UtfNext(end) - end, + -1, 0, &w); } goto check; } @@ -2284,7 +2725,7 @@ Tk_IntersectTextLayout(layout, x, y, width, height) * location of the baseline for the string. * * Results: - * Interp->result is modified to hold the Postscript code that + * The interp's result is modified to hold the Postscript code that * will render the text layout. * * Side effects: @@ -2302,6 +2743,8 @@ Tk_TextLayoutToPostscript(interp, layout) char buf[MAXUSE+10]; LayoutChunk *chunkPtr; int i, j, used, c, baseline; + Tcl_UniChar ch; + CONST char *p; TextLayout *layoutPtr; layoutPtr = (TextLayout *) layout; @@ -2322,8 +2765,16 @@ Tk_TextLayoutToPostscript(interp, layout) buf[used++] = 't'; } } else { + p = chunkPtr->start; for (j = 0; j < chunkPtr->numDisplayChars; j++) { - c = UCHAR(chunkPtr->start[j]); + /* + * INTL: For now we just treat the characters as binary + * data and display the lower byte. Eventually this should + * be revised to handle international postscript fonts. + */ + + p += Tcl_UtfToUniChar(p, &ch); + c = UCHAR(ch & 0xff); if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20) || (c >= UCHAR(0x7f))) { /* @@ -2367,36 +2818,6 @@ Tk_TextLayoutToPostscript(interp, layout) /* *--------------------------------------------------------------------------- * - * TkInitFontAttributes -- - * - * Initialize the font attributes structure to contain sensible - * values. This must be called before using any other font - * attributes functions. - * - * Results: - * None. - * - * Side effects. - * None. - * - *--------------------------------------------------------------------------- - */ - -void -TkInitFontAttributes(faPtr) - TkFontAttributes *faPtr; /* The attributes structure to initialize. */ -{ - faPtr->family = NULL; - faPtr->pointsize = 0; - faPtr->weight = TK_FW_NORMAL; - faPtr->slant = TK_FS_ROMAN; - faPtr->underline = 0; - faPtr->overstrike = 0; -} - -/* - *--------------------------------------------------------------------------- - * * ConfigAttributesObj -- * * Process command line options to fill in fields of a properly @@ -2427,68 +2848,74 @@ ConfigAttributesObj(interp, tkwin, objc, objv, faPtr) * be properly initialized. */ { int i, n, index; - Tcl_Obj *value; - char *option, *string; + Tcl_Obj *optionPtr, *valuePtr; + char *value; - if (objc & 1) { - string = Tcl_GetStringFromObj(objv[objc - 1], NULL); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "missing value for \"", - string, "\" option", (char *) NULL); - return TCL_ERROR; - } - for (i = 0; i < objc; i += 2) { - option = Tcl_GetStringFromObj(objv[i], NULL); - value = objv[i + 1]; + optionPtr = objv[i]; + valuePtr = objv[i + 1]; - if (Tcl_GetIndexFromObj(interp, objv[i], fontOpt, "option", 1, + if (Tcl_GetIndexFromObj(interp, optionPtr, fontOpt, "option", 1, &index) != TCL_OK) { return TCL_ERROR; } + if ((i+2 >= objc) && (objc & 1)) { + /* + * This test occurs after Tcl_GetIndexFromObj() so that + * "font create xyz -xyz" will return the error message + * that "-xyz" is a bad option, rather than that the value + * for "-xyz" is missing. + */ + + Tcl_AppendResult(interp, "value for \"", + Tcl_GetString(optionPtr), "\" option missing", + (char *) NULL); + return TCL_ERROR; + } + switch (index) { - case FONT_FAMILY: - string = Tcl_GetStringFromObj(value, NULL); - faPtr->family = Tk_GetUid(string); + case FONT_FAMILY: { + value = Tcl_GetString(valuePtr); + faPtr->family = Tk_GetUid(value); break; - - case FONT_SIZE: - if (Tcl_GetIntFromObj(interp, value, &n) != TCL_OK) { + } + case FONT_SIZE: { + if (Tcl_GetIntFromObj(interp, valuePtr, &n) != TCL_OK) { return TCL_ERROR; } - faPtr->pointsize = n; + faPtr->size = n; break; - - case FONT_WEIGHT: - string = Tcl_GetStringFromObj(value, NULL); - n = TkFindStateNum(interp, option, weightMap, string); + } + case FONT_WEIGHT: { + n = TkFindStateNumObj(interp, optionPtr, weightMap, valuePtr); if (n == TK_FW_UNKNOWN) { return TCL_ERROR; } faPtr->weight = n; break; - - case FONT_SLANT: - string = Tcl_GetStringFromObj(value, NULL); - n = TkFindStateNum(interp, option, slantMap, string); + } + case FONT_SLANT: { + n = TkFindStateNumObj(interp, optionPtr, slantMap, valuePtr); if (n == TK_FS_UNKNOWN) { return TCL_ERROR; } faPtr->slant = n; break; - - case FONT_UNDERLINE: - if (Tcl_GetBooleanFromObj(interp, value, &n) != TCL_OK) { + } + case FONT_UNDERLINE: { + if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) { return TCL_ERROR; } faPtr->underline = n; break; - - case FONT_OVERSTRIKE: - if (Tcl_GetBooleanFromObj(interp, value, &n) != TCL_OK) { + } + case FONT_OVERSTRIKE: { + if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) { return TCL_ERROR; } faPtr->overstrike = n; break; + } } } return TCL_OK; @@ -2523,18 +2950,19 @@ GetAttributeInfoObj(interp, faPtr, objPtr) CONST TkFontAttributes *faPtr; /* The font attributes to inspect. */ Tcl_Obj *objPtr; /* If non-NULL, indicates the single * option whose value is to be - * returned. Otherwise - * information is returned for - * all options. */ + * returned. Otherwise information is + * returned for all options. */ { - int i, index, start, end, num; + int i, index, start, end; char *str; - Tcl_Obj *newPtr; + Tcl_Obj *optionPtr, *valuePtr, *resultPtr; + + resultPtr = Tcl_GetObjResult(interp); start = 0; end = FONT_NUMFIELDS; if (objPtr != NULL) { - if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", 1, + if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } @@ -2542,55 +2970,43 @@ GetAttributeInfoObj(interp, faPtr, objPtr) end = index + 1; } + valuePtr = NULL; for (i = start; i < end; i++) { - str = NULL; - num = 0; /* Needed only to prevent compiler - * warning. */ switch (i) { case FONT_FAMILY: str = faPtr->family; - if (str == NULL) { - str = ""; - } + valuePtr = Tcl_NewStringObj(str, ((str == NULL) ? 0 : -1)); break; case FONT_SIZE: - num = faPtr->pointsize; + valuePtr = Tcl_NewIntObj(faPtr->size); break; case FONT_WEIGHT: str = TkFindStateString(weightMap, faPtr->weight); + valuePtr = Tcl_NewStringObj(str, -1); break; case FONT_SLANT: str = TkFindStateString(slantMap, faPtr->slant); + valuePtr = Tcl_NewStringObj(str, -1); break; case FONT_UNDERLINE: - num = faPtr->underline; + valuePtr = Tcl_NewBooleanObj(faPtr->underline); break; case FONT_OVERSTRIKE: - num = faPtr->overstrike; + valuePtr = Tcl_NewBooleanObj(faPtr->overstrike); break; } - if (objPtr == NULL) { - Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), - Tcl_NewStringObj(fontOpt[i], -1)); - if (str != NULL) { - newPtr = Tcl_NewStringObj(str, -1); - } else { - newPtr = Tcl_NewIntObj(num); - } - Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(interp), - newPtr); - } else { - if (str != NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), str, -1); - } else { - Tcl_SetIntObj(Tcl_GetObjResult(interp), num); - } + if (objPtr != NULL) { + Tcl_SetObjResult(interp, valuePtr); + return TCL_OK; } + optionPtr = Tcl_NewStringObj(fontOpt[i], -1); + Tcl_ListObjAppendElement(NULL, resultPtr, optionPtr); + Tcl_ListObjAppendElement(NULL, resultPtr, valuePtr); } return TCL_OK; } @@ -2605,7 +3021,7 @@ GetAttributeInfoObj(interp, faPtr, objPtr) * * The string rep of the object can be one of the following forms: * XLFD (see X documentation) - * "Family [size [style] [style ...]]" + * "family [size] [style1 [style2 ...]" * "-option value [-option value ...]" * * Results: @@ -2622,20 +3038,23 @@ GetAttributeInfoObj(interp, faPtr, objPtr) static int ParseFontNameObj(interp, tkwin, objPtr, faPtr) - Tcl_Interp *interp; /* Interp for error return. */ + Tcl_Interp *interp; /* Interp for error return. Must not be + * NULL. */ Tk_Window tkwin; /* For display on which font is used. */ Tcl_Obj *objPtr; /* Parseable font description object. */ - TkFontAttributes *faPtr; /* Font attributes structure whose fields - * are to be modified. Structure must already - * be properly initialized. */ + TkFontAttributes *faPtr; /* Filled with attributes parsed from font + * name. Any attributes that were not + * specified in font name are filled with + * default values. */ { char *dash; int objc, result, i, n; Tcl_Obj **objv; - TkXLFDAttributes xa; char *string; - string = Tcl_GetStringFromObj(objPtr, NULL); + TkInitFontAttributes(faPtr); + + string = Tcl_GetString(objPtr); if (*string == '-') { /* * This may be an XLFD or an "-option value" string. @@ -2648,7 +3067,8 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) goto xlfd; } dash = strchr(string + 1, '-'); - if ((dash != NULL) && (!isspace(UCHAR(dash[-1])))) { + if ((dash != NULL) + && (!isspace(UCHAR(dash[-1])))) { /* INTL: ISO space */ goto xlfd; } @@ -2661,15 +3081,16 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) if (*string == '*') { /* - * This appears to be an XLFD. + * This is appears to be an XLFD. Under Unix, all valid XLFDs were + * already handled by TkpGetNativeFont. If we are here, either we + * have something that initially looks like an XLFD but isn't or we + * have encountered an XLFD on Windows or Mac. */ xlfd: - xa.fa = *faPtr; - result = TkParseXLFD(string, &xa); + result = TkFontParseXLFD(string, faPtr, NULL); if (result == TCL_OK) { - *faPtr = xa.fa; - return result; + return TCL_OK; } } @@ -2678,21 +3099,19 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) * "font size style" list. */ - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } - if (objc < 1) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "font \"", string, - "\" doesn't exist", (char *) NULL); + if ((Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK) + || (objc < 1)) { + Tcl_AppendResult(interp, "font \"", string, "\" doesn't exist", + (char *) NULL); return TCL_ERROR; } - faPtr->family = Tk_GetUid(Tcl_GetStringFromObj(objv[0], NULL)); + faPtr->family = Tk_GetUid(Tcl_GetString(objv[0])); if (objc > 1) { if (Tcl_GetIntFromObj(interp, objv[1], &n) != TCL_OK) { return TCL_ERROR; } - faPtr->pointsize = n; + faPtr->size = n; } i = 2; @@ -2703,23 +3122,22 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) i = 0; } for ( ; i < objc; i++) { - string = Tcl_GetStringFromObj(objv[i], NULL); - n = TkFindStateNum(NULL, NULL, weightMap, string); + n = TkFindStateNumObj(NULL, NULL, weightMap, objv[i]); if (n != TK_FW_UNKNOWN) { faPtr->weight = n; continue; } - n = TkFindStateNum(NULL, NULL, slantMap, string); + n = TkFindStateNumObj(NULL, NULL, slantMap, objv[i]); if (n != TK_FS_UNKNOWN) { faPtr->slant = n; continue; } - n = TkFindStateNum(NULL, NULL, underlineMap, string); + n = TkFindStateNumObj(NULL, NULL, underlineMap, objv[i]); if (n != 0) { faPtr->underline = n; continue; } - n = TkFindStateNum(NULL, NULL, overstrikeMap, string); + n = TkFindStateNumObj(NULL, NULL, overstrikeMap, objv[i]); if (n != 0) { faPtr->overstrike = n; continue; @@ -2729,9 +3147,8 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) * Unknown style. */ - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "unknown font style \"", string, "\"", - (char *) NULL); + Tcl_AppendResult(interp, "unknown font style \"", + Tcl_GetString(objv[i]), "\"", (char *) NULL); return TCL_ERROR; } return TCL_OK; @@ -2740,7 +3157,69 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) /* *--------------------------------------------------------------------------- * - * TkParseXLFD -- + * NewChunk -- + * + * Helper function for Tk_ComputeTextLayout(). Encapsulates a + * measured set of characters in a chunk that can be quickly + * drawn. + * + * Results: + * A pointer to the new chunk in the text layout. + * + * Side effects: + * The text layout is reallocated to hold more chunks as necessary. + * + * Currently, Tk_ComputeTextLayout() stores contiguous ranges of + * "normal" characters in a chunk, along with individual tab + * and newline chars in their own chunks. All characters in the + * text layout are accounted for. + * + *--------------------------------------------------------------------------- + */ +static LayoutChunk * +NewChunk(layoutPtrPtr, maxPtr, start, numBytes, curX, newX, y) + TextLayout **layoutPtrPtr; + int *maxPtr; + CONST char *start; + int numBytes; + int curX; + int newX; + int y; +{ + TextLayout *layoutPtr; + LayoutChunk *chunkPtr; + int maxChunks, numChars; + size_t s; + + layoutPtr = *layoutPtrPtr; + maxChunks = *maxPtr; + if (layoutPtr->numChunks == maxChunks) { + maxChunks *= 2; + s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk)); + layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s); + + *layoutPtrPtr = layoutPtr; + *maxPtr = maxChunks; + } + numChars = Tcl_NumUtfChars(start, numBytes); + chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks]; + chunkPtr->start = start; + chunkPtr->numBytes = numBytes; + chunkPtr->numChars = numChars; + chunkPtr->numDisplayChars = numChars; + chunkPtr->x = curX; + chunkPtr->y = y; + chunkPtr->totalWidth = newX - curX; + chunkPtr->displayWidth = newX - curX; + layoutPtr->numChunks++; + + return chunkPtr; +} + +/* + *--------------------------------------------------------------------------- + * + * TkFontParseXLFD -- * * Break up a fully specified XLFD into a set of font attributes. * @@ -2756,18 +3235,31 @@ ParseFontNameObj(interp, tkwin, objPtr, faPtr) */ int -TkParseXLFD(string, xaPtr) +TkFontParseXLFD(string, faPtr, xaPtr) CONST char *string; /* Parseable font description string. */ - TkXLFDAttributes *xaPtr; /* XLFD attributes structure whose fields - * are to be modified. Structure must already - * be properly initialized. */ + TkFontAttributes *faPtr; /* Filled with attributes parsed from font + * name. Any attributes that were not + * specified in font name are filled with + * default values. */ + TkXLFDAttributes *xaPtr; /* Filled with X-specific attributes parsed + * from font name. Any attributes that were + * not specified in font name are filled with + * default values. May be NULL if such + * information is not desired. */ { char *src; CONST char *str; int i, j; char *field[XLFD_NUMFIELDS + 2]; Tcl_DString ds; + TkXLFDAttributes xa; + if (xaPtr == NULL) { + xaPtr = &xa; + } + TkInitFontAttributes(faPtr); + TkInitXLFDAttributes(xaPtr); + memset(field, '\0', sizeof(field)); str = string; @@ -2781,27 +3273,32 @@ TkParseXLFD(string, xaPtr) field[0] = src; for (i = 0; *src != '\0'; src++) { - if (isupper(UCHAR(*src))) { - *src = tolower(UCHAR(*src)); + if (!(*src & 0x80) + && Tcl_UniCharIsUpper(UCHAR(*src))) { + *src = (char) Tcl_UniCharToLower(UCHAR(*src)); } if (*src == '-') { i++; - if (i > XLFD_NUMFIELDS) { - break; + if (i == XLFD_NUMFIELDS) { + continue; } *src = '\0'; field[i] = src + 1; + if (i > XLFD_NUMFIELDS) { + break; + } } } /* - * An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common, + * An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common, * but it is (strictly) malformed, because the first * is eliding both * the Setwidth and the Addstyle fields. If the Addstyle field is a * number, then assume the above incorrect form was used and shift all - * the rest of the fields up by one, so the number gets interpreted + * the rest of the fields right by one, so the number gets interpreted * as a pixelsize. This fix is so that we don't get a million reports - * that "it works under X, but gives a syntax error under Windows". + * that "it works under X (as a native font name), but gives a syntax + * error under Windows (as a parsed set of attributes)". */ if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) { @@ -2828,19 +3325,19 @@ TkParseXLFD(string, xaPtr) } if (FieldSpecified(field[XLFD_FAMILY])) { - xaPtr->fa.family = Tk_GetUid(field[XLFD_FAMILY]); + faPtr->family = Tk_GetUid(field[XLFD_FAMILY]); } if (FieldSpecified(field[XLFD_WEIGHT])) { - xaPtr->fa.weight = TkFindStateNum(NULL, NULL, xlfdWeightMap, + faPtr->weight = TkFindStateNum(NULL, NULL, xlfdWeightMap, field[XLFD_WEIGHT]); } if (FieldSpecified(field[XLFD_SLANT])) { xaPtr->slant = TkFindStateNum(NULL, NULL, xlfdSlantMap, field[XLFD_SLANT]); if (xaPtr->slant == TK_FS_ROMAN) { - xaPtr->fa.slant = TK_FS_ROMAN; + faPtr->slant = TK_FS_ROMAN; } else { - xaPtr->fa.slant = TK_FS_ITALIC; + faPtr->slant = TK_FS_ITALIC; } } if (FieldSpecified(field[XLFD_SETWIDTH])) { @@ -2851,9 +3348,12 @@ TkParseXLFD(string, xaPtr) /* XLFD_ADD_STYLE ignored. */ /* - * Pointsize in tenths of a point, but treat it as tenths of a pixel. + * Pointsize in tenths of a point, but treat it as tenths of a pixel + * for historical compatibility. */ + faPtr->size = 12; + if (FieldSpecified(field[XLFD_POINT_SIZE])) { if (field[XLFD_POINT_SIZE][0] == '[') { /* @@ -2866,10 +3366,10 @@ TkParseXLFD(string, xaPtr) * the purpose of, so I ignore them. */ - xaPtr->fa.pointsize = atoi(field[XLFD_POINT_SIZE] + 1); + faPtr->size = atoi(field[XLFD_POINT_SIZE] + 1); } else if (Tcl_GetInt(NULL, field[XLFD_POINT_SIZE], - &xaPtr->fa.pointsize) == TCL_OK) { - xaPtr->fa.pointsize /= 10; + &faPtr->size) == TCL_OK) { + faPtr->size /= 10; } else { return TCL_ERROR; } @@ -2891,14 +3391,14 @@ TkParseXLFD(string, xaPtr) * the purpose of, so I ignore them. */ - xaPtr->fa.pointsize = atoi(field[XLFD_PIXEL_SIZE] + 1); + faPtr->size = atoi(field[XLFD_PIXEL_SIZE] + 1); } else if (Tcl_GetInt(NULL, field[XLFD_PIXEL_SIZE], - &xaPtr->fa.pointsize) != TCL_OK) { + &faPtr->size) != TCL_OK) { return TCL_ERROR; } } - xaPtr->fa.pointsize = -xaPtr->fa.pointsize; + faPtr->size = -faPtr->size; /* XLFD_RESOLUTION_X ignored. */ @@ -2908,14 +3408,11 @@ TkParseXLFD(string, xaPtr) /* XLFD_AVERAGE_WIDTH ignored. */ - if (FieldSpecified(field[XLFD_REGISTRY])) { - xaPtr->charset = TkFindStateNum(NULL, NULL, xlfdCharsetMap, - field[XLFD_REGISTRY]); - } - if (FieldSpecified(field[XLFD_ENCODING])) { - xaPtr->encoding = atoi(field[XLFD_ENCODING]); + if (FieldSpecified(field[XLFD_CHARSET])) { + xaPtr->charset = Tk_GetUid(field[XLFD_CHARSET]); + } else { + xaPtr->charset = Tk_GetUid("iso8859-1"); } - Tcl_DStringFree(&ds); return TCL_OK; } @@ -2957,61 +3454,225 @@ FieldSpecified(field) /* *--------------------------------------------------------------------------- * - * NewChunk -- + * TkFontGetPixels -- * - * Helper function for Tk_ComputeTextLayout(). Encapsulates a - * measured set of characters in a chunk that can be quickly - * drawn. + * Given a font size specification (as described in the TkFontAttributes + * structure) return the number of pixels it represents. * * Results: - * A pointer to the new chunk in the text layout. + * As above. * * Side effects: - * The text layout is reallocated to hold more chunks as necessary. + * None. * - * Currently, Tk_ComputeTextLayout() stores contiguous ranges of - * "normal" characters in a chunk, along with individual tab - * and newline chars in their own chunks. All characters in the - * text layout are accounted for. + *--------------------------------------------------------------------------- + */ + +int +TkFontGetPixels(tkwin, size) + Tk_Window tkwin; /* For point->pixel conversion factor. */ + int size; /* Font size. */ +{ + double d; + + if (size < 0) { + return -size; + } + + d = size * 25.4 / 72.0; + d *= WidthOfScreen(Tk_Screen(tkwin)); + d /= WidthMMOfScreen(Tk_Screen(tkwin)); + return (int) (d + 0.5); +} + +/* + *--------------------------------------------------------------------------- + * + * TkFontGetPoints -- + * + * Given a font size specification (as described in the TkFontAttributes + * structure) return the number of points it represents. + * + * Results: + * As above. + * + * Side effects: + * None. * *--------------------------------------------------------------------------- */ -static LayoutChunk * -NewChunk(layoutPtrPtr, maxPtr, start, numChars, curX, newX, y) - TextLayout **layoutPtrPtr; - int *maxPtr; - CONST char *start; - int numChars; - int curX; - int newX; - int y; + +int +TkFontGetPoints(tkwin, size) + Tk_Window tkwin; /* For pixel->point conversion factor. */ + int size; /* Font size. */ { - TextLayout *layoutPtr; - LayoutChunk *chunkPtr; - int maxChunks; - size_t s; - - layoutPtr = *layoutPtrPtr; - maxChunks = *maxPtr; - if (layoutPtr->numChunks == maxChunks) { - maxChunks *= 2; - s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk)); - layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s); + double d; - *layoutPtrPtr = layoutPtr; - *maxPtr = maxChunks; + if (size >= 0) { + return size; } - chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks]; - chunkPtr->start = start; - chunkPtr->numChars = numChars; - chunkPtr->numDisplayChars = numChars; - chunkPtr->x = curX; - chunkPtr->y = y; - chunkPtr->totalWidth = newX - curX; - chunkPtr->displayWidth = newX - curX; - layoutPtr->numChunks++; - return chunkPtr; + d = -size * 72.0 / 25.4; + d *= WidthMMOfScreen(Tk_Screen(tkwin)); + d /= WidthOfScreen(Tk_Screen(tkwin)); + return (int) (d + 0.5); +} + +/* + *------------------------------------------------------------------------- + * + * TkFontGetAliasList -- + * + * Given a font name, find the list of all aliases for that font + * name. One of the names in this list will probably be the name + * that this platform expects when asking for the font. + * + * Results: + * As above. The return value is NULL if the font name has no + * aliases. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +char ** +TkFontGetAliasList(faceName) + CONST char *faceName; /* Font name to test for aliases. */ +{ + int i, j; + + for (i = 0; fontAliases[i] != NULL; i++) { + for (j = 0; fontAliases[i][j] != NULL; j++) { + if (strcasecmp(faceName, fontAliases[i][j]) == 0) { + return fontAliases[i]; + } + } + } + return NULL; +} + +/* + *------------------------------------------------------------------------- + * + * TkFontGetFallbacks -- + * + * Get the list of font fallbacks that the platform-specific code + * can use to try to find the closest matching font the name + * requested. + * + * Results: + * As above. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +char *** +TkFontGetFallbacks() +{ + return fontFallbacks; +} + +/* + *------------------------------------------------------------------------- + * + * TkFontGetGlobalClass -- + * + * Get the list of fonts to try if the requested font name does not + * exist and no fallbacks for that font name could be used either. + * The names in this list are considered preferred over all the other + * font names in the system when looking for a last-ditch fallback. + * + * Results: + * As above. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +char ** +TkFontGetGlobalClass() +{ + return globalFontClass; +} + +/* + *------------------------------------------------------------------------- + * + * TkFontGetSymbolClass -- + * + * Get the list of fonts that are symbolic; used if the operating + * system cannot apriori identify symbolic fonts on its own. + * + * Results: + * As above. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +char ** +TkFontGetSymbolClass() +{ + return symbolClass; +} + +/* + *---------------------------------------------------------------------- + * + * TkDebugFont -- + * + * This procedure returns debugging information about a font. + * + * Results: + * The return value is a list with one sublist for each TkFont + * corresponding to "name". Each sublist has two elements that + * contain the resourceRefCount and objRefCount fields from the + * TkFont structure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_Obj * +TkDebugFont(tkwin, name) + Tk_Window tkwin; /* The window in which the font will be + * used (not currently used). */ + char *name; /* Name of the desired color. */ +{ + TkFont *fontPtr; + Tcl_HashEntry *hashPtr; + Tcl_Obj *resultPtr, *objPtr; + + resultPtr = Tcl_NewObj(); + hashPtr = Tcl_FindHashEntry( + &((TkWindow *) tkwin)->mainPtr->fontInfoPtr->fontCache, name); + if (hashPtr != NULL) { + fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); + if (fontPtr == NULL) { + panic("TkDebugFont found empty hash table entry"); + } + for ( ; (fontPtr != NULL); fontPtr = fontPtr->nextPtr) { + objPtr = Tcl_NewObj(); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewIntObj(fontPtr->resourceRefCount)); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewIntObj(fontPtr->objRefCount)); + Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); + } + } + return resultPtr; } /* CYGNUS LOCAL: This routine is called on Windows to update a named @@ -3033,8 +3694,9 @@ TkUpdateFonts(tkwin, changed) while (namedHashPtr != NULL) { nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr); if ((*changed)(&nfPtr->fa)) { - UpdateDependantFonts(fiPtr, tkwin, namedHashPtr); + UpdateDependentFonts(fiPtr, tkwin, namedHashPtr); } namedHashPtr = Tcl_NextHashEntry(&search); } } + diff --git a/tk/generic/tkFont.h b/tk/generic/tkFont.h index 7bd9928fbea..5c891e3e8e5 100644 --- a/tk/generic/tkFont.h +++ b/tk/generic/tkFont.h @@ -5,7 +5,7 @@ * specific parts of the font package. This information is not * visible outside of the font package. * - * Copyright (c) 1996 Sun Microsystems, Inc. + * Copyright (c) 1996-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -28,8 +28,9 @@ */ typedef struct TkFontAttributes { - Tk_Uid family; /* Font family. The most important field. */ - int pointsize; /* Pointsize of font, 0 for default size, or + Tk_Uid family; /* Font family, or NULL to represent + * plaform-specific default system font. */ + int size; /* Pointsize of font, 0 for default size, or * negative number meaning pixel size. */ int weight; /* Weight flag; see below for def'n. */ int slant; /* Slant flag; see below for def'n. */ @@ -91,13 +92,25 @@ typedef struct TkFont { * Fields used and maintained exclusively by generic code. */ - int refCount; /* Number of users of the TkFont. */ + int resourceRefCount; /* Number of active uses of this font (each + * active use corresponds to a call to + * Tk_AllocFontFromTable or Tk_GetFont). + * If this count is 0, then this TkFont + * structure is no longer valid and it isn't + * present in a hash table: it is being + * kept around only because there are objects + * referring to it. The structure is freed + * when resourceRefCount and objRefCount + * are both 0. */ + int objRefCount; /* The number of Tcl objects that reference + * this structure. */ Tcl_HashEntry *cacheHashPtr;/* Entry in font cache for this structure, * used when deleting it. */ Tcl_HashEntry *namedHashPtr;/* Pointer to hash table entry that * corresponds to the named font that the * tkfont was based on, or NULL if the tkfont * was not based on a named font. */ + Screen *screen; /* The screen where this font is valid. */ int tabWidth; /* Width of tabs in this font (pixels). */ int underlinePos; /* Offset from baseline to origin of * underline bar (used for drawing underlines @@ -106,7 +119,7 @@ typedef struct TkFont { * underlines on a non-underlined font). */ /* - * Fields in the generic font structure that are filled in by + * Fields used in the generic code that are filled in by * platform-specific code. */ @@ -121,6 +134,11 @@ typedef struct TkFont { * that was used to create this font. */ TkFontMetrics fm; /* Font metrics determined when font was * created. */ + struct TkFont *nextPtr; /* Points to the next TkFont structure with + * the same name. All fonts with the + * same name (but different displays) are + * chained together off a single entry in + * a hash table. */ } TkFont; /* @@ -130,16 +148,12 @@ typedef struct TkFont { */ typedef struct TkXLFDAttributes { - TkFontAttributes fa; /* Standard set of font attributes. */ Tk_Uid foundry; /* The foundry of the font. */ int slant; /* The tristate value for the slant, which * is significant under X. */ int setwidth; /* The proportionate width, see below for * definition. */ - int charset; /* The character set encoding (the glyph - * family), see below for definition. */ - int encoding; /* Variations within a charset for the - * glyphs above character 127. */ + Tk_Uid charset; /* The actual charset string. */ } TkXLFDAttributes; /* @@ -155,15 +169,6 @@ typedef struct TkXLFDAttributes { * stored in the setwidth field. */ /* - * Possible values for the "charset" field in a TkXLFDAttributes structure. - * The charset is the set of glyphs that are used in the font. - */ - -#define TK_CS_NORMAL 0 -#define TK_CS_SYMBOL 1 -#define TK_CS_OTHER 2 - -/* * The following defines specify the meaning of the fields in a fully * qualified XLFD. */ @@ -180,28 +185,33 @@ typedef struct TkXLFDAttributes { #define XLFD_RESOLUTION_Y 9 #define XLFD_SPACING 10 #define XLFD_AVERAGE_WIDTH 11 -#define XLFD_REGISTRY 12 -#define XLFD_ENCODING 13 -#define XLFD_NUMFIELDS 14 /* Number of fields in XLFD. */ +#define XLFD_CHARSET 12 +#define XLFD_NUMFIELDS 13 /* Number of fields in XLFD. */ /* - * Exported from generic code to platform-specific code. + * Low-level API exported by generic code to platform-specific code. */ -EXTERN int TkCreateNamedFont _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, CONST char *name, - TkFontAttributes *faPtr)); -EXTERN void TkInitFontAttributes _ANSI_ARGS_(( - TkFontAttributes *faPtr)); -EXTERN int TkParseXLFD _ANSI_ARGS_((CONST char *string, - TkXLFDAttributes *xaPtr)); +#define TkInitFontAttributes(fa) memset((fa), 0, sizeof(TkFontAttributes)); +#define TkInitXLFDAttributes(xa) memset((xa), 0, sizeof(TkXLFDAttributes)); + +EXTERN int TkFontParseXLFD _ANSI_ARGS_((CONST char *string, + TkFontAttributes *faPtr, TkXLFDAttributes *xaPtr)); +EXTERN char ** TkFontGetAliasList _ANSI_ARGS_((CONST char *faceName)); +EXTERN char *** TkFontGetFallbacks _ANSI_ARGS_((void)); +EXTERN int TkFontGetPixels _ANSI_ARGS_((Tk_Window tkwin, + int size)); +EXTERN int TkFontGetPoints _ANSI_ARGS_((Tk_Window tkwin, + int size)); +EXTERN char ** TkFontGetGlobalClass _ANSI_ARGS_((void)); +EXTERN char ** TkFontGetSymbolClass _ANSI_ARGS_((void)); /* - * Common APIs exported to tkFont.c from all platform-specific - * implementations. + * Low-level API exported by platform-specific code to generic code. */ EXTERN void TkpDeleteFont _ANSI_ARGS_((TkFont *tkFontPtr)); +EXTERN void TkpFontPkgInit _ANSI_ARGS_((TkMainInfo *mainPtr)); EXTERN TkFont * TkpGetFontFromAttributes _ANSI_ARGS_(( TkFont *tkFontPtr, Tk_Window tkwin, CONST TkFontAttributes *faPtr)); @@ -218,3 +228,5 @@ EXTERN void TkUpdateFonts _ANSI_ARGS_((Tk_Window tkwin, # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TKFONT */ + + diff --git a/tk/generic/tkFrame.c b/tk/generic/tkFrame.c index ded4e4ca4bd..949fb18c226 100644 --- a/tk/generic/tkFrame.c +++ b/tk/generic/tkFrame.c @@ -7,7 +7,7 @@ * attributes. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -167,22 +167,25 @@ static Tk_ConfigSpec configSpecs[] = { */ static int ConfigureFrame _ANSI_ARGS_((Tcl_Interp *interp, - Frame *framePtr, int argc, char **argv, + Frame *framePtr, int objc, Tcl_Obj *CONST objv[], int flags)); +static int CreateFrame _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST argv[], + int toplevel, char *appName)); static void DestroyFrame _ANSI_ARGS_((char *memPtr)); static void DisplayFrame _ANSI_ARGS_((ClientData clientData)); static void FrameCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static void FrameEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); -static int FrameWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); +static int FrameWidgetObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static void MapFrame _ANSI_ARGS_((ClientData clientData)); /* *-------------------------------------------------------------- * - * Tk_FrameCmd, Tk_ToplevelCmd -- + * Tk_FrameObjCmd, Tk_ToplevelObjCmd -- * * These procedures are invoked to process the "frame" and * "toplevel" Tcl commands. See the user documentation for @@ -199,31 +202,31 @@ static void MapFrame _ANSI_ARGS_((ClientData clientData)); */ int -Tk_FrameCmd(clientData, interp, argc, argv) +Tk_FrameObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - return TkCreateFrame(clientData, interp, argc, argv, 0, (char *) NULL); + return CreateFrame(clientData, interp, objc, objv, 0, (char *) NULL); } int -Tk_ToplevelCmd(clientData, interp, argc, argv) +Tk_ToplevelObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - return TkCreateFrame(clientData, interp, argc, argv, 1, (char *) NULL); + return CreateFrame(clientData, interp, objc, objv, 1, (char *) NULL); } /* *-------------------------------------------------------------- * - * TkFrameCreate -- + * TkCreateFrame -- * * This procedure is invoked to process the "frame" and "toplevel" * Tcl commands; it is also invoked directly by Tk_Init to create @@ -253,18 +256,47 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) * NULL: gives the base name to use for the * new application. */ { + int result, i; + Tcl_Obj **objv = (Tcl_Obj **) ckalloc((argc+1) * sizeof(Tcl_Obj **)); + for (i=0; i<argc; i++) { + objv[i] = Tcl_NewStringObj(argv[i], -1); + Tcl_IncrRefCount(objv[i]); + } + objv[argc] = NULL; + result = CreateFrame(clientData, interp, argc, objv, toplevel, appName); + for (i=0; i<argc; i++) { + Tcl_DecrRefCount(objv[i]); + } + ckfree((char *) objv); + return result; +} + +static int +CreateFrame(clientData, interp, objc, objv, toplevel, appName) + ClientData clientData; /* Main window associated with interpreter. + * If we're called by Tk_Init to create a + * new application, then this is NULL. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ + int toplevel; /* Non-zero means create a toplevel window, + * zero means create a frame. */ + char *appName; /* Should only be non-NULL if clientData is + * NULL: gives the base name to use for the + * new application. */ +{ Tk_Window tkwin = (Tk_Window) clientData; Frame *framePtr; Tk_Window new; char *className, *screenName, *visualName, *colormapName, *arg, *useOption; - int i, c, length, depth; + int i, c, depth; + size_t length; unsigned int mask; Colormap colormap; Visual *visual; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } @@ -277,28 +309,27 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) className = colormapName = screenName = visualName = useOption = NULL; colormap = None; - for (i = 2; i < argc; i += 2) { - arg = argv[i]; - length = strlen(arg); + for (i = 2; i < objc; i += 2) { + arg = Tcl_GetStringFromObj(objv[i], (int *) &length); if (length < 2) { continue; } c = arg[1]; - if ((c == 'c') && (strncmp(arg, "-class", strlen(arg)) == 0) + if ((c == 'c') && (strncmp(arg, "-class", length) == 0) && (length >= 3)) { - className = argv[i+1]; + className = Tcl_GetString(objv[i+1]); } else if ((c == 'c') - && (strncmp(arg, "-colormap", strlen(arg)) == 0)) { - colormapName = argv[i+1]; + && (strncmp(arg, "-colormap", length) == 0)) { + colormapName = Tcl_GetString(objv[i+1]); } else if ((c == 's') && toplevel - && (strncmp(arg, "-screen", strlen(arg)) == 0)) { - screenName = argv[i+1]; + && (strncmp(arg, "-screen", length) == 0)) { + screenName = Tcl_GetString(objv[i+1]); } else if ((c == 'u') && toplevel - && (strncmp(arg, "-use", strlen(arg)) == 0)) { - useOption = argv[i+1]; + && (strncmp(arg, "-use", length) == 0)) { + useOption = Tcl_GetString(objv[i+1]); } else if ((c == 'v') - && (strncmp(arg, "-visual", strlen(arg)) == 0)) { - visualName = argv[i+1]; + && (strncmp(arg, "-visual", length) == 0)) { + visualName = Tcl_GetString(objv[i+1]); } } @@ -321,7 +352,8 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) screenName = (toplevel) ? "" : NULL; } if (tkwin != NULL) { - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], screenName); + new = Tk_CreateWindowFromPath(interp, tkwin, Tcl_GetString(objv[1]), + screenName); } else { /* * We were called from Tk_Init; create a new application. @@ -392,8 +424,8 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) framePtr->tkwin = new; framePtr->display = Tk_Display(new); framePtr->interp = interp; - framePtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(new), FrameWidgetCmd, + framePtr->widgetCmd = Tcl_CreateObjCommand(interp, + Tk_PathName(new), FrameWidgetObjCmd, (ClientData) framePtr, FrameCmdDeletedProc); framePtr->className = NULL; framePtr->mask = (toplevel) ? TOPLEVEL : FRAME; @@ -426,7 +458,7 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) mask |= ActivateMask; } Tk_CreateEventHandler(new, mask, FrameEventProc, (ClientData) framePtr); - if (ConfigureFrame(interp, framePtr, argc-2, argv+2, 0) != TCL_OK) { + if (ConfigureFrame(interp, framePtr, objc-2, objv+2, 0) != TCL_OK) { goto error; } if ((framePtr->isContainer)) { @@ -441,7 +473,7 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) if (toplevel) { Tcl_DoWhenIdle(MapFrame, (ClientData) framePtr); } - interp->result = Tk_PathName(new); + Tcl_SetResult(interp, Tk_PathName(new), TCL_STATIC); return TCL_OK; error: @@ -454,7 +486,7 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) /* *-------------------------------------------------------------- * - * FrameWidgetCmd -- + * FrameWidgetObjCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a frame widget. See the user @@ -470,83 +502,87 @@ TkCreateFrame(clientData, interp, argc, argv, toplevel, appName) */ static int -FrameWidgetCmd(clientData, interp, argc, argv) +FrameWidgetObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about frame widget. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { + static char *frameOptions[] = { + "cget", "configure", (char *) NULL + }; + enum options { + FRAME_CGET, FRAME_CONFIGURE + }; register Frame *framePtr = (Frame *) clientData; - int result; + int result = TCL_OK, index; size_t length; int c, i; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], frameOptions, "option", 0, + &index) != TCL_OK) { return TCL_ERROR; } Tcl_Preserve((ClientData) framePtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); + switch ((enum options) index) { + case FRAME_CGET: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); result = TCL_ERROR; goto done; } result = Tk_ConfigureValue(interp, framePtr->tkwin, configSpecs, - (char *) framePtr, argv[2], framePtr->mask); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { + (char *) framePtr, Tcl_GetString(objv[2]), framePtr->mask); + break; + } + case FRAME_CONFIGURE: { + if (objc == 2) { result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs, (char *) framePtr, (char *) NULL, framePtr->mask); - } else if (argc == 3) { + } else if (objc == 3) { result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs, - (char *) framePtr, argv[2], framePtr->mask); + (char *) framePtr, Tcl_GetString(objv[2]), framePtr->mask); } else { /* * Don't allow the options -class, -colormap, -container, * -newcmap, -screen, -use, or -visual to be changed. */ - for (i = 2; i < argc; i++) { - length = strlen(argv[i]); + for (i = 2; i < objc; i++) { + char *arg = Tcl_GetStringFromObj(objv[i], (int *) &length); if (length < 2) { continue; } - c = argv[i][1]; - if (((c == 'c') && (strncmp(argv[i], "-class", length) == 0) + c = arg[1]; + if (((c == 'c') && (strncmp(arg, "-class", length) == 0) && (length >= 2)) || ((c == 'c') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-colormap", length) == 0) + && (strncmp(arg, "-colormap", length) == 0) && (length >= 3)) || ((c == 'c') - && (strncmp(argv[i], "-container", length) == 0) + && (strncmp(arg, "-container", length) == 0) && (length >= 3)) || ((c == 's') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-screen", length) == 0)) + && (strncmp(arg, "-screen", length) == 0)) || ((c == 'u') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-use", length) == 0)) + && (strncmp(arg, "-use", length) == 0)) || ((c == 'v') && (framePtr->mask == TOPLEVEL) - && (strncmp(argv[i], "-visual", length) == 0))) { - Tcl_AppendResult(interp, "can't modify ", argv[i], + && (strncmp(arg, "-visual", length) == 0))) { + Tcl_AppendResult(interp, "can't modify ", arg, " option after widget is created", (char *) NULL); result = TCL_ERROR; goto done; } } - result = ConfigureFrame(interp, framePtr, argc-2, argv+2, + result = ConfigureFrame(interp, framePtr, objc-2, objv+2, TK_CONFIG_ARGV_ONLY); } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget or configure", (char *) NULL); - result = TCL_ERROR; + break; + } } done: @@ -591,13 +627,13 @@ DestroyFrame(memPtr) * * ConfigureFrame -- * - * This procedure is called to process an argv/argc list, plus + * This procedure is called to process an objv/objc list, plus * the Tk option database, in order to configure (or * reconfigure) a frame widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, @@ -608,12 +644,12 @@ DestroyFrame(memPtr) */ static int -ConfigureFrame(interp, framePtr, argc, argv, flags) +ConfigureFrame(interp, framePtr, objc, objv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register Frame *framePtr; /* Information about widget; may or may * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ + int objc; /* Number of valid entries in objv. */ + Tcl_Obj *CONST objv[]; /* Arguments. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { char *oldMenuName; @@ -630,7 +666,8 @@ ConfigureFrame(interp, framePtr, argc, argv, flags) } if (Tk_ConfigureWidget(interp, framePtr->tkwin, configSpecs, - argc, argv, (char *) framePtr, flags | framePtr->mask) != TCL_OK) { + objc, (char **) objv, (char *) framePtr, + flags | framePtr->mask | TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -694,7 +731,8 @@ DisplayFrame(clientData) { register Frame *framePtr = (Frame *) clientData; register Tk_Window tkwin = framePtr->tkwin; - GC gc; + void (* drawFunction) _ANSI_ARGS_((Tk_Window, Drawable, Tk_3DBorder, + int, int, int, int, int, int)) = Tk_Fill3DRectangle; framePtr->flags &= ~REDRAW_PENDING; if ((framePtr->tkwin == NULL) || !Tk_IsMapped(tkwin) @@ -703,7 +741,7 @@ DisplayFrame(clientData) } if (framePtr->border != NULL) { - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), + drawFunction(tkwin, Tk_WindowId(tkwin), framePtr->border, framePtr->highlightWidth, framePtr->highlightWidth, Tk_Width(tkwin) - 2*framePtr->highlightWidth, @@ -711,15 +749,19 @@ DisplayFrame(clientData) framePtr->borderWidth, framePtr->relief); } if (framePtr->highlightWidth != 0) { + GC fgGC, bgGC; + + bgGC = Tk_GCForColor(framePtr->highlightBgColorPtr, + Tk_WindowId(tkwin)); if (framePtr->flags & GOT_FOCUS) { - gc = Tk_GCForColor(framePtr->highlightColorPtr, + fgGC = Tk_GCForColor(framePtr->highlightColorPtr, + Tk_WindowId(tkwin)); + TkpDrawHighlightBorder(tkwin, fgGC, bgGC, framePtr->highlightWidth, Tk_WindowId(tkwin)); } else { - gc = Tk_GCForColor(framePtr->highlightBgColorPtr, + TkpDrawHighlightBorder(tkwin, bgGC, bgGC, framePtr->highlightWidth, Tk_WindowId(tkwin)); } - Tk_DrawFocusHighlight(tkwin, gc, framePtr->highlightWidth, - Tk_WindowId(tkwin)); } } @@ -933,7 +975,11 @@ TkInstallFrameMenu(tkwin) if (winPtr->mainPtr != NULL) { Frame *framePtr; framePtr = (Frame*) winPtr->instanceData; + if (framePtr == NULL) { + panic("TkInstallFrameMenu couldn't get frame pointer"); + } TkpMenuNotifyToplevelCreate(winPtr->mainPtr->interp, framePtr->menuName); } } + diff --git a/tk/generic/tkGC.c b/tk/generic/tkGC.c index 9d1c6949009..8ddcd391e4c 100644 --- a/tk/generic/tkGC.c +++ b/tk/generic/tkGC.c @@ -14,9 +14,6 @@ */ #include "tkPort.h" -#include "tk.h" - -/* CYGNUS LOCAL, for TkRegisterColorGC. */ #include "tkInt.h" /* @@ -32,46 +29,20 @@ typedef struct { int refCount; /* Number of active uses of gc. */ Tcl_HashEntry *valueHashPtr;/* Entry in valueTable (needed when deleting * this structure). */ - /* CYGNUS LOCAL. */ - XColor *foreground; /* Foreground color. */ - XColor *background; /* Background color. */ } TkGC; -/* - * Hash table to map from a GC's values to a TkGC structure describing - * a GC with those values (used by Tk_GetGC). - */ - -static Tcl_HashTable valueTable; typedef struct { XGCValues values; /* Desired values for GC. */ Display *display; /* Display for which GC is valid. */ int screenNum; /* screen number of display */ int depth; /* and depth for which GC is valid. */ - /* CYGNUS LOCAL. */ - XColor *foreground; /* Foreground color. */ - XColor *background; /* Background color. */ } ValueKey; /* - * Hash table for <display + GC> -> TkGC mapping. This table is used by - * Tk_FreeGC. - */ - -static Tcl_HashTable idTable; -typedef struct { - Display *display; /* Display for which GC was allocated. */ - GC gc; /* X's identifier for GC. */ -} IdKey; - -static int initialized = 0; /* 0 means static structures haven't been - * initialized yet. */ - -/* * Forward declarations for procedures defined in this file: */ -static void GCInit _ANSI_ARGS_((void)); +static void GCInit _ANSI_ARGS_((TkDisplay *dispPtr)); /* *---------------------------------------------------------------------- @@ -95,11 +66,8 @@ static void GCInit _ANSI_ARGS_((void)); *---------------------------------------------------------------------- */ -/* CYGNUS LOCAL: Rename this to Tk_GetGCColor. The new Tk_GetGC is - below. */ - GC -Tk_GetGCColor(tkwin, valueMask, valuePtr, foreground, background) +Tk_GetGC(tkwin, valueMask, valuePtr) Tk_Window tkwin; /* Window in which GC will be used. */ register unsigned long valueMask; /* 1 bits correspond to values specified @@ -108,31 +76,18 @@ Tk_GetGCColor(tkwin, valueMask, valuePtr, foreground, background) register XGCValues *valuePtr; /* Values are specified here for bits set * in valueMask. */ - /* CYGNUS LOCAL. */ - XColor *foreground; /* Foreground color. */ - XColor *background; /* Background color. */ { ValueKey valueKey; - IdKey idKey; Tcl_HashEntry *valueHashPtr, *idHashPtr; register TkGC *gcPtr; int new; Drawable d, freeDrawable; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - if (!initialized) { - GCInit(); + if (!dispPtr->gcInit) { + GCInit(dispPtr); } -#if !defined(__WIN32__) && !defined(_WIN32) - /* CYGNUS LOCAL. We only care about special foreground and - background colors on Windows. If we are on some other - platform, just ignore them. If we don't do this, we may - allocate an unnecessary GC if we have two colors with different - names but the same pixel value. */ - foreground = NULL; - background = NULL; -#endif - /* * Must zero valueKey at start to clear out pad bytes that may be * part of structure on some systems. @@ -263,12 +218,8 @@ Tk_GetGCColor(tkwin, valueMask, valuePtr, foreground, background) valueKey.display = Tk_Display(tkwin); valueKey.screenNum = Tk_ScreenNumber(tkwin); valueKey.depth = Tk_Depth(tkwin); - - /* CYGNUS LOCAL. Set colors. */ - valueKey.foreground = foreground; - valueKey.background = background; - - valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &valueKey, &new); + valueHashPtr = Tcl_CreateHashEntry(&dispPtr->gcValueTable, + (char *) &valueKey, &new); if (!new) { gcPtr = (TkGC *) Tcl_GetHashValue(valueHashPtr); gcPtr->refCount++; @@ -305,9 +256,8 @@ Tk_GetGCColor(tkwin, valueMask, valuePtr, foreground, background) gcPtr->display = valueKey.display; gcPtr->refCount = 1; gcPtr->valueHashPtr = valueHashPtr; - idKey.display = valueKey.display; - idKey.gc = gcPtr->gc; - idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new); + idHashPtr = Tcl_CreateHashEntry(&dispPtr->gcIdTable, + (char *) gcPtr->gc, &new); if (!new) { panic("GC already registered in Tk_GetGC"); } @@ -317,36 +267,8 @@ Tk_GetGCColor(tkwin, valueMask, valuePtr, foreground, background) Tk_FreePixmap(valueKey.display, freeDrawable); } - /* CYGNUS LOCAL. Record and register the colors. */ - gcPtr->foreground = foreground; - gcPtr->background = background; - if (foreground != NULL) { - TkRegisterColorGC(foreground, valueKey.display, gcPtr->gc, - GCForeground); - } - if (background != NULL) { - TkRegisterColorGC(background, valueKey.display, gcPtr->gc, - GCBackground); - } - return gcPtr->gc; } - -/* CYGNUS LOCAL. Tk_GetGC now just calls Tk_GetGCColor. */ - -GC -Tk_GetGC(tkwin, valueMask, valuePtr) - Tk_Window tkwin; /* Window in which GC will be used. */ - register unsigned long valueMask; - /* 1 bits correspond to values specified - * in *valuesPtr; other values are set - * from defaults. */ - register XGCValues *valuePtr; - /* Values are specified here for bits set - * in valueMask. */ -{ - return Tk_GetGCColor(tkwin, valueMask, valuePtr, NULL, NULL); -} /* *---------------------------------------------------------------------- @@ -371,33 +293,21 @@ Tk_FreeGC(display, gc) Display *display; /* Display for which gc was allocated. */ GC gc; /* Graphics context to be released. */ { - IdKey idKey; Tcl_HashEntry *idHashPtr; register TkGC *gcPtr; + TkDisplay *dispPtr = TkGetDisplay(display); - if (!initialized) { + if (!dispPtr->gcInit) { panic("Tk_FreeGC called before Tk_GetGC"); } - idKey.display = display; - idKey.gc = gc; - idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); + idHashPtr = Tcl_FindHashEntry(&dispPtr->gcIdTable, (char *) gc); if (idHashPtr == NULL) { panic("Tk_FreeGC received unknown gc argument"); } gcPtr = (TkGC *) Tcl_GetHashValue(idHashPtr); gcPtr->refCount--; if (gcPtr->refCount == 0) { - /* CYGNUS LOCAL: Deregister the colors. */ - if (gcPtr->foreground != NULL) { - TkDeregisterColorGC(gcPtr->foreground, gcPtr->gc, - GCForeground); - } - if (gcPtr->background != NULL) { - TkDeregisterColorGC(gcPtr->background, gcPtr->gc, - GCBackground); - } - Tk_FreeXId(gcPtr->display, (XID) XGContextFromGC(gcPtr->gc)); XFreeGC(gcPtr->display, gcPtr->gc); Tcl_DeleteHashEntry(gcPtr->valueHashPtr); @@ -423,9 +333,10 @@ Tk_FreeGC(display, gc) */ static void -GCInit() +GCInit(dispPtr) + TkDisplay *dispPtr; { - initialized = 1; - Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int)); - Tcl_InitHashTable(&idTable, sizeof(IdKey)/sizeof(int)); + dispPtr->gcInit = 1; + Tcl_InitHashTable(&dispPtr->gcValueTable, sizeof(ValueKey)/sizeof(int)); + Tcl_InitHashTable(&dispPtr->gcIdTable, TCL_ONE_WORD_KEYS); } diff --git a/tk/generic/tkGeometry.c b/tk/generic/tkGeometry.c index 3545c4b7c4e..fcc33e33d55 100644 --- a/tk/generic/tkGeometry.c +++ b/tk/generic/tkGeometry.c @@ -53,19 +53,6 @@ typedef struct MaintainMaster { } MaintainMaster; /* - * Hash table that maps from a master's Tk_Window token to a list of - * Maintains for that master: - */ - -static Tcl_HashTable maintainHashTable; - -/* - * Has maintainHashTable been initialized yet? - */ - -static int initialized = 0; - -/* * Prototypes for static procedures in this file: */ @@ -261,10 +248,11 @@ Tk_MaintainGeometry(slave, master, x, y, width, height) register MaintainSlave *slavePtr; int new, map; Tk_Window ancestor, parent; + TkDisplay *dispPtr = ((TkWindow *) master)->dispPtr; - if (!initialized) { - initialized = 1; - Tcl_InitHashTable(&maintainHashTable, TCL_ONE_WORD_KEYS); + if (!dispPtr->geomInit) { + dispPtr->geomInit = 1; + Tcl_InitHashTable(&dispPtr->maintainHashTable, TCL_ONE_WORD_KEYS); } /* @@ -273,7 +261,8 @@ Tk_MaintainGeometry(slave, master, x, y, width, height) */ parent = Tk_Parent(slave); - hPtr = Tcl_CreateHashEntry(&maintainHashTable, (char *) master, &new); + hPtr = Tcl_CreateHashEntry(&dispPtr->maintainHashTable, + (char *) master, &new); if (!new) { masterPtr = (MaintainMaster *) Tcl_GetHashValue(hPtr); } else { @@ -383,16 +372,17 @@ Tk_UnmaintainGeometry(slave, master) MaintainMaster *masterPtr; register MaintainSlave *slavePtr, *prevPtr; Tk_Window ancestor; + TkDisplay *dispPtr = ((TkWindow *) slave)->dispPtr; - if (!initialized) { - initialized = 1; - Tcl_InitHashTable(&maintainHashTable, TCL_ONE_WORD_KEYS); + if (!dispPtr->geomInit) { + dispPtr->geomInit = 1; + Tcl_InitHashTable(&dispPtr->maintainHashTable, TCL_ONE_WORD_KEYS); } if (!(((TkWindow *) slave)->flags & TK_ALREADY_DEAD)) { Tk_UnmapWindow(slave); } - hPtr = Tcl_FindHashEntry(&maintainHashTable, (char *) master); + hPtr = Tcl_FindHashEntry(&dispPtr->maintainHashTable, (char *) master); if (hPtr == NULL) { return; } @@ -580,3 +570,4 @@ MaintainCheckProc(clientData) } } } + diff --git a/tk/generic/tkGet.c b/tk/generic/tkGet.c index 020a39005ae..f9df1acb1a2 100644 --- a/tk/generic/tkGet.c +++ b/tk/generic/tkGet.c @@ -8,7 +8,7 @@ * files. * * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -20,12 +20,64 @@ #include "tkPort.h" /* - * The hash table below is used to keep track of all the Tk_Uids created - * so far. + * One of these structures is created per thread to store + * thread-specific data. In this case, it is used to house the + * Tk_Uid structs used by each thread. The "dataKey" below is + * used to locate the ThreadSpecificData for the current thread. */ -static Tcl_HashTable uidTable; -static int initialized = 0; +typedef struct ThreadSpecificData { + int initialized; + Tcl_HashTable uidTable; +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; + +/* + * The following tables defines the string values for reliefs, which are + * used by Tk_GetAnchorFromObj and Tk_GetJustifyFromObj. + */ + +static char *anchorStrings[] = {"n", "ne", "e", "se", "s", "sw", "w", "nw", + "center", (char *) NULL}; +static char *justifyStrings[] = {"left", "right", "center", (char *) NULL}; + + +/* + *---------------------------------------------------------------------- + * + * Tk_GetAnchorFromObj -- + * + * Return a Tk_Anchor value based on the value of the objPtr. + * + * Results: + * The return value is a standard Tcl result. If an error occurs during + * conversion, an error message is left in the interpreter's result + * unless "interp" is NULL. + * + * Side effects: + * The object gets converted by Tcl_GetIndexFromObj. + * + *---------------------------------------------------------------------- + */ + +int +Tk_GetAnchorFromObj(interp, objPtr, anchorPtr) + Tcl_Interp *interp; /* Used for error reporting. */ + Tcl_Obj *objPtr; /* The object we are trying to get the + * value from. */ + Tk_Anchor *anchorPtr; /* Where to place the Tk_Anchor that + * corresponds to the string value of + * objPtr. */ +{ + int index, code; + + code = Tcl_GetIndexFromObj(interp, objPtr, anchorStrings, "anchor", 0, + &index); + if (code == TCL_OK) { + *anchorPtr = (Tk_Anchor) index; + } + return code; +} /* *-------------------------------------------------------------- @@ -39,7 +91,7 @@ static int initialized = 0; * TCL_OK is returned, then everything went well and the * position is stored at *anchorPtr; otherwise TCL_ERROR * is returned and an error message is left in - * interp->result. + * the interp's result. * * Side effects: * None. @@ -148,14 +200,14 @@ Tk_NameOfAnchor(anchor) * * Tk_GetJoinStyle -- * - * Given a string, return the corresponding Tk_JoinStyle. + * Given a string, return the corresponding Tk JoinStyle. * * Results: * The return value is a standard Tcl return result. If * TCL_OK is returned, then everything went well and the * justification is stored at *joinPtr; otherwise * TCL_ERROR is returned and an error message is left in - * interp->result. + * the interp's result. * * Side effects: * None. @@ -200,7 +252,7 @@ Tk_GetJoinStyle(interp, string, joinPtr) * * Tk_NameOfJoinStyle -- * - * Given a Tk_JoinStyle, return the string that corresponds + * Given a Tk JoinStyle, return the string that corresponds * to it. * * Results: @@ -230,14 +282,14 @@ Tk_NameOfJoinStyle(join) * * Tk_GetCapStyle -- * - * Given a string, return the corresponding Tk_CapStyle. + * Given a string, return the corresponding Tk CapStyle. * * Results: * The return value is a standard Tcl return result. If * TCL_OK is returned, then everything went well and the * justification is stored at *capPtr; otherwise * TCL_ERROR is returned and an error message is left in - * interp->result. + * the interp's result. * * Side effects: * None. @@ -282,7 +334,7 @@ Tk_GetCapStyle(interp, string, capPtr) * * Tk_NameOfCapStyle -- * - * Given a Tk_CapStyle, return the string that corresponds + * Given a Tk CapStyle, return the string that corresponds * to it. * * Results: @@ -308,6 +360,43 @@ Tk_NameOfCapStyle(cap) } /* + *---------------------------------------------------------------------- + * + * Tk_GetJustifyFromObj -- + * + * Return a Tk_Justify value based on the value of the objPtr. + * + * Results: + * The return value is a standard Tcl result. If an error occurs during + * conversion, an error message is left in the interpreter's result + * unless "interp" is NULL. + * + * Side effects: + * The object gets converted by Tcl_GetIndexFromObj. + * + *---------------------------------------------------------------------- + */ + +int +Tk_GetJustifyFromObj(interp, objPtr, justifyPtr) + Tcl_Interp *interp; /* Used for error reporting. */ + Tcl_Obj *objPtr; /* The object we are trying to get the + * value from. */ + Tk_Justify *justifyPtr; /* Where to place the Tk_Justify that + * corresponds to the string value of + * objPtr. */ +{ + int index, code; + + code = Tcl_GetIndexFromObj(interp, objPtr, justifyStrings, + "justification", 0, &index); + if (code == TCL_OK) { + *justifyPtr = (Tk_Justify) index; + } + return code; +} + +/* *-------------------------------------------------------------- * * Tk_GetJustify -- @@ -319,7 +408,7 @@ Tk_NameOfCapStyle(cap) * TCL_OK is returned, then everything went well and the * justification is stored at *justifyPtr; otherwise * TCL_ERROR is returned and an error message is left in - * interp->result. + * the interp's result. * * Side effects: * None. @@ -417,13 +506,16 @@ Tk_GetUid(string) CONST char *string; /* String to convert. */ { int dummy; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + Tcl_HashTable *tablePtr = &tsdPtr->uidTable; - if (!initialized) { - Tcl_InitHashTable(&uidTable, TCL_STRING_KEYS); - initialized = 1; + if (!tsdPtr->initialized) { + Tcl_InitHashTable(tablePtr, TCL_STRING_KEYS); + tsdPtr->initialized = 1; } - return (Tk_Uid) Tcl_GetHashKey(&uidTable, - Tcl_CreateHashEntry(&uidTable, string, &dummy)); + return (Tk_Uid) Tcl_GetHashKey(tablePtr, + Tcl_CreateHashEntry(tablePtr, string, &dummy)); } /* @@ -439,7 +531,7 @@ Tk_GetUid(string) * TCL_OK is returned, then everything went well and the * screen distance is stored at *doublePtr; otherwise * TCL_ERROR is returned and an error message is left in - * interp->result. + * the interp's result. * * Side effects: * None. @@ -515,7 +607,7 @@ Tk_GetScreenMM(interp, tkwin, string, doublePtr) * TCL_OK is returned, then everything went well and the * rounded pixel distance is stored at *intPtr; otherwise * TCL_ERROR is returned and an error message is left in - * interp->result. + * the interp's result. * * Side effects: * None. @@ -529,13 +621,56 @@ Tk_GetPixels(interp, tkwin, string, intPtr) Tk_Window tkwin; /* Window whose screen determines conversion * from centimeters and other absolute * units. */ - char *string; /* String describing a justification style. */ + char *string; /* String describing a number of pixels. */ int *intPtr; /* Place to store converted result. */ { + double d; + + if (TkGetDoublePixels(interp, tkwin, string, &d) != TCL_OK) { + return TCL_ERROR; + } + + if (d < 0) { + *intPtr = (int) (d - 0.5); + } else { + *intPtr = (int) (d + 0.5); + } + return TCL_OK; +} +/* + *-------------------------------------------------------------- + * + * TkGetDoublePixels -- + * + * Given a string, returns the number of pixels corresponding + * to that string. + * + * Results: + * The return value is a standard Tcl return result. If + * TCL_OK is returned, then everything went well and the + * pixel distance is stored at *doublePtr; otherwise + * TCL_ERROR is returned and an error message is left in + * interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkGetDoublePixels(interp, tkwin, string, doublePtr) + Tcl_Interp *interp; /* Use this for error reporting. */ + Tk_Window tkwin; /* Window whose screen determines conversion + * from centimeters and other absolute + * units. */ + CONST char *string; /* String describing a number of pixels. */ + double *doublePtr; /* Place to store converted result. */ +{ char *end; double d; - d = strtod(string, &end); + d = strtod((char *) string, &end); if (end == string) { error: Tcl_AppendResult(interp, "bad screen distance \"", string, @@ -577,10 +712,9 @@ Tk_GetPixels(interp, tkwin, string, intPtr) if (*end != 0) { goto error; } - if (d < 0) { - *intPtr = (int) (d - 0.5); - } else { - *intPtr = (int) (d + 0.5); - } + *doublePtr = d; return TCL_OK; } + + + diff --git a/tk/generic/tkGrab.c b/tk/generic/tkGrab.c index 8be4b9f24f8..1ff6b8e1bcf 100644 --- a/tk/generic/tkGrab.c +++ b/tk/generic/tkGrab.c @@ -4,7 +4,7 @@ * This file provides procedures that implement grabs for Tk. * * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -15,6 +15,10 @@ #include "tkPort.h" #include "tkInt.h" +#if !defined(__WIN32__) && !defined(MAC_TCL) +#include "tkUnixInt.h" +#endif + /* * The grab state machine has four states: ungrabbed, button pressed, * grabbed, and button pressed while grabbed. In addition, there are @@ -238,10 +242,11 @@ Tk_GrabCmd(clientData, interp, argc, argv) } dispPtr = ((TkWindow *) tkwin)->dispPtr; if (dispPtr->eventualGrabWinPtr != NULL) { - interp->result = dispPtr->eventualGrabWinPtr->pathName; + Tcl_SetResult(interp, dispPtr->eventualGrabWinPtr->pathName, + TCL_STATIC); } } else { - for (dispPtr = tkDisplayList; dispPtr != NULL; + for (dispPtr = TkGetDisplayList(); dispPtr != NULL; dispPtr = dispPtr->nextPtr) { if (dispPtr->eventualGrabWinPtr != NULL) { Tcl_AppendElement(interp, @@ -303,11 +308,11 @@ Tk_GrabCmd(clientData, interp, argc, argv) } dispPtr = winPtr->dispPtr; if (dispPtr->eventualGrabWinPtr != winPtr) { - interp->result = "none"; + Tcl_SetResult(interp, "none", TCL_STATIC); } else if (dispPtr->grabFlags & GRAB_GLOBAL) { - interp->result = "global"; + Tcl_SetResult(interp, "global", TCL_STATIC); } else { - interp->result = "local"; + Tcl_SetResult(interp, "local", TCL_STATIC); } } else { Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1], @@ -329,7 +334,7 @@ Tk_GrabCmd(clientData, interp, argc, argv) * Results: * A standard Tcl result is returned. TCL_OK is the normal return * value; if the grab could not be set then TCL_ERROR is returned - * and interp->result will hold an error message. + * and the interp's result will hold an error message. * * Side effects: * Once this call completes successfully, no window outside the @@ -366,7 +371,8 @@ Tk_Grab(interp, tkwin, grabGlobal) } if (dispPtr->eventualGrabWinPtr->mainPtr != winPtr->mainPtr) { alreadyGrabbed: - interp->result = "grab failed: another application has grab"; + Tcl_SetResult(interp, "grab failed: another application has grab", + TCL_STATIC); return TCL_ERROR; } Tk_Ungrab((Tk_Window) dispPtr->eventualGrabWinPtr); @@ -432,15 +438,18 @@ Tk_Grab(interp, tkwin, grabGlobal) if (grabResult != 0) { grabError: if (grabResult == GrabNotViewable) { - interp->result = "grab failed: window not viewable"; + Tcl_SetResult(interp, "grab failed: window not viewable", + TCL_STATIC); } else if (grabResult == AlreadyGrabbed) { goto alreadyGrabbed; } else if (grabResult == GrabFrozen) { - interp->result = "grab failed: keyboard or pointer frozen"; + Tcl_SetResult(interp, + "grab failed: keyboard or pointer frozen", TCL_STATIC); } else if (grabResult == GrabInvalidTime) { - interp->result = "grab failed: invalid time"; + Tcl_SetResult(interp, "grab failed: invalid time", + TCL_STATIC); } else { - char msg[100]; + char msg[64 + TCL_INTEGER_SPACE]; sprintf(msg, "grab failed for unknown reason (code %d)", grabResult); @@ -1533,3 +1542,4 @@ TkGrabState(winPtr) return TkPositionInTree(winPtr, grabWinPtr); } + diff --git a/tk/generic/tkGrid.c b/tk/generic/tkGrid.c index e78eb7e3b78..def4a434d49 100644 --- a/tk/generic/tkGrid.c +++ b/tk/generic/tkGrid.c @@ -222,14 +222,6 @@ typedef struct Gridder { #define DONT_PROPAGATE 2 /* - * Hash table used to map from Tk_Window tokens to corresponding - * Grid structures: - */ - -static Tcl_HashTable gridHashTable; -static int initialized = 0; - -/* * Prototypes for procedures used only in this file: */ @@ -314,6 +306,7 @@ Tk_GridCmd(clientData, interp, argc, argv) int endX, endY; /* last column/row in the layout */ int x=0, y=0; /* starting pixels for this bounding box */ int width, height; /* size of the bounding box */ + char buf[TCL_INTEGER_SPACE * 4]; if (argc!=3 && argc != 5 && argc != 7) { Tcl_AppendResult(interp, "wrong number of arguments: ", @@ -351,7 +344,7 @@ Tk_GridCmd(clientData, interp, argc, argv) gridPtr = masterPtr->masterDataPtr; if (gridPtr == NULL) { - sprintf(interp->result, "%d %d %d %d",0,0,0,0); + Tcl_SetResult(interp, "0 0 0 0", TCL_STATIC); return(TCL_OK); } @@ -360,7 +353,7 @@ Tk_GridCmd(clientData, interp, argc, argv) endY = MAX(gridPtr->rowEnd, gridPtr->rowMax); if ((endX == 0) || (endY == 0)) { - sprintf(interp->result, "%d %d %d %d",0,0,0,0); + Tcl_SetResult(interp, "0 0 0 0", TCL_STATIC); return(TCL_OK); } if (argc == 3) { @@ -406,8 +399,9 @@ Tk_GridCmd(clientData, interp, argc, argv) height = gridPtr->rowPtr[row2].offset - y; } - sprintf(interp->result, "%d %d %d %d", - x + gridPtr->startX, y + gridPtr->startY, width, height); + sprintf(buf, "%d %d %d %d", x + gridPtr->startX, y + gridPtr->startY, + width, height); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) { if (argv[2][0] != '.') { Tcl_AppendResult(interp, "bad argument \"", argv[2], @@ -440,6 +434,9 @@ Tk_GridCmd(clientData, interp, argc, argv) slavePtr->padX = slavePtr->padY = 0; slavePtr->iPadX = slavePtr->iPadY = 0; slavePtr->doubleBw = 2*Tk_Changes(tkwin)->border_width; + if (slavePtr->flags & REQUESTED_RELAYOUT) { + Tcl_CancelIdleCall(ArrangeGrid, (ClientData) slavePtr); + } slavePtr->flags = 0; slavePtr->sticky = 0; } @@ -456,7 +453,7 @@ Tk_GridCmd(clientData, interp, argc, argv) } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) { register Gridder *slavePtr; Tk_Window slave; - char buffer[70]; + char buffer[64 + TCL_INTEGER_SPACE * 4]; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", @@ -469,7 +466,7 @@ Tk_GridCmd(clientData, interp, argc, argv) } slavePtr = GetGrid(slave); if (slavePtr->masterPtr == NULL) { - interp->result[0] = '\0'; + Tcl_ResetResult(interp); return TCL_OK; } @@ -491,6 +488,7 @@ Tk_GridCmd(clientData, interp, argc, argv) int x, y; /* Offset in pixels, from edge of parent. */ int i, j; /* Corresponding column and row indeces. */ int endX, endY; /* end of grid */ + char buf[TCL_INTEGER_SPACE * 2]; if (argc != 5) { Tcl_AppendResult(interp, "wrong # args: should be \"", @@ -512,7 +510,7 @@ Tk_GridCmd(clientData, interp, argc, argv) masterPtr = GetGrid(master); if (masterPtr->masterDataPtr == NULL) { - sprintf(interp->result, "%d %d", -1, -1); + Tcl_SetResult(interp, "-1 -1", TCL_STATIC); return TCL_OK; } gridPtr = masterPtr->masterDataPtr; @@ -524,7 +522,7 @@ Tk_GridCmd(clientData, interp, argc, argv) */ while (masterPtr->flags & REQUESTED_RELAYOUT) { - Tk_CancelIdleCall(ArrangeGrid, (ClientData) masterPtr); + Tcl_CancelIdleCall(ArrangeGrid, (ClientData) masterPtr); ArrangeGrid ((ClientData) masterPtr); } SetGridSize(masterPtr); @@ -551,7 +549,8 @@ Tk_GridCmd(clientData, interp, argc, argv) } } - sprintf(interp->result, "%d %d", i, j); + sprintf(buf, "%d %d", i, j); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) { Tk_Window master; int propagate; @@ -568,14 +567,23 @@ Tk_GridCmd(clientData, interp, argc, argv) } masterPtr = GetGrid(master); if (argc == 3) { - interp->result = (masterPtr->flags & DONT_PROPAGATE) ? "0" : "1"; + Tcl_SetResult(interp, + ((masterPtr->flags & DONT_PROPAGATE) ? "0" : "1"), + TCL_STATIC); return TCL_OK; } if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) { return TCL_ERROR; } + + /* Only request a relayout if the propagation bit changes */ + if ((!propagate) ^ (masterPtr->flags&DONT_PROPAGATE)) { - masterPtr->flags ^= DONT_PROPAGATE; + if (propagate) { + masterPtr->flags &= ~DONT_PROPAGATE; + } else { + masterPtr->flags |= DONT_PROPAGATE; + } /* * Re-arrange the master to allow new geometry information to @@ -606,13 +614,16 @@ Tk_GridCmd(clientData, interp, argc, argv) masterPtr = GetGrid(master); if (masterPtr->masterDataPtr != NULL) { + char buf[TCL_INTEGER_SPACE * 2]; + SetGridSize(masterPtr); gridPtr = masterPtr->masterDataPtr; - sprintf(interp->result, "%d %d", - MAX(gridPtr->columnEnd, gridPtr->columnMax), - MAX(gridPtr->rowEnd, gridPtr->rowMax)); + sprintf(buf, "%d %d", + MAX(gridPtr->columnEnd, gridPtr->columnMax), + MAX(gridPtr->rowEnd, gridPtr->rowMax)); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else { - sprintf(interp->result, "%d %d",0, 0); + Tcl_SetResult(interp, "0 0", TCL_STATIC); } } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0) && (length > 1)) { @@ -754,12 +765,16 @@ Tk_GridCmd(clientData, interp, argc, argv) Tcl_Free((char *)argvPtr); } if ((argc == 4) && (ok == TCL_OK)) { - sprintf(interp->result,"-minsize %d -pad %d -weight %d", + char buf[64 + TCL_INTEGER_SPACE * 3]; + + sprintf(buf, "-minsize %d -pad %d -weight %d", slotPtr[slot].minSize,slotPtr[slot].pad, slotPtr[slot].weight); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return (TCL_OK); } else if (argc == 4) { - sprintf(interp->result,"-minsize %d -pad %d -weight %d", 0,0,0); + Tcl_SetResult(interp, "-minsize 0 -pad 0 -weight 0", + TCL_STATIC); return (TCL_OK); } @@ -780,8 +795,12 @@ Tk_GridCmd(clientData, interp, argc, argv) } if (strncmp(argv[i], "-minsize", length) == 0) { if (argc == 5) { - int value = ok == TCL_OK ? slotPtr[slot].minSize : 0; - sprintf(interp->result,"%d",value); + char buf[TCL_INTEGER_SPACE]; + int value; + + value = (ok == TCL_OK) ? slotPtr[slot].minSize : 0; + sprintf(buf, "%d", value); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (Tk_GetPixels(interp, master, argv[i+1], &size) != TCL_OK) { Tcl_Free((char *)argvPtr); @@ -793,8 +812,12 @@ Tk_GridCmd(clientData, interp, argc, argv) else if (strncmp(argv[i], "-weight", length) == 0) { int wt; if (argc == 5) { - int value = ok == TCL_OK ? slotPtr[slot].weight : 0; - sprintf(interp->result,"%d",value); + char buf[TCL_INTEGER_SPACE]; + int value; + + value = (ok == TCL_OK) ? slotPtr[slot].weight : 0; + sprintf(buf, "%d", value); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (Tcl_GetInt(interp, argv[i+1], &wt) != TCL_OK) { Tcl_Free((char *)argvPtr); return TCL_ERROR; @@ -809,8 +832,12 @@ Tk_GridCmd(clientData, interp, argc, argv) } else if (strncmp(argv[i], "-pad", length) == 0) { if (argc == 5) { - int value = ok == TCL_OK ? slotPtr[slot].pad : 0; - sprintf(interp->result,"%d",value); + char buf[TCL_INTEGER_SPACE]; + int value; + + value = (ok == TCL_OK) ? slotPtr[slot].pad : 0; + sprintf(buf, "%d", value); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (Tk_GetPixels(interp, master, argv[i+1], &size) != TCL_OK) { Tcl_Free((char *)argvPtr); @@ -1411,7 +1438,7 @@ ResolveConstraints(masterPtr, slotType, maxOffset) gridCount = MAX(constraintCount,slotCount); if (gridCount >= TYPICAL_SIZE) { - layoutPtr = (GridLayout *) Tcl_Alloc(sizeof(GridLayout) * (1+gridCount)); + layoutPtr = (GridLayout *) ckalloc(sizeof(GridLayout) * (1+gridCount)); } else { layoutPtr = layoutData; } @@ -1714,10 +1741,11 @@ GetGrid(tkwin) register Gridder *gridPtr; Tcl_HashEntry *hPtr; int new; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - if (!initialized) { - initialized = 1; - Tcl_InitHashTable(&gridHashTable, TCL_ONE_WORD_KEYS); + if (!dispPtr->gridInit) { + Tcl_InitHashTable(&dispPtr->gridHashTable, TCL_ONE_WORD_KEYS); + dispPtr->gridInit = 1; } /* @@ -1725,11 +1753,11 @@ GetGrid(tkwin) * then create a new one. */ - hPtr = Tcl_CreateHashEntry(&gridHashTable, (char *) tkwin, &new); + hPtr = Tcl_CreateHashEntry(&dispPtr->gridHashTable, (char *) tkwin, &new); if (!new) { return (Gridder *) Tcl_GetHashValue(hPtr); } - gridPtr = (Gridder *) Tcl_Alloc(sizeof(Gridder)); + gridPtr = (Gridder *) ckalloc(sizeof(Gridder)); gridPtr->tkwin = tkwin; gridPtr->masterPtr = NULL; gridPtr->masterDataPtr = NULL; @@ -1852,7 +1880,7 @@ CheckSlotData(masterPtr, slot, slotType, checkOnly) int newNumSlot = slot + PREALLOC ; size_t oldSize = numSlot * sizeof(SlotInfo) ; size_t newSize = newNumSlot * sizeof(SlotInfo) ; - SlotInfo *new = (SlotInfo *) Tcl_Alloc(newSize); + SlotInfo *new = (SlotInfo *) ckalloc(newSize); SlotInfo *old = (slotType == ROW) ? masterPtr->masterDataPtr->rowPtr : masterPtr->masterDataPtr->columnPtr; @@ -1904,19 +1932,19 @@ InitMasterData(masterPtr) size_t size; if (masterPtr->masterDataPtr == NULL) { GridMaster *gridPtr = masterPtr->masterDataPtr = - (GridMaster *) Tcl_Alloc(sizeof(GridMaster)); + (GridMaster *) ckalloc(sizeof(GridMaster)); size = sizeof(SlotInfo) * TYPICAL_SIZE; gridPtr->columnEnd = 0; gridPtr->columnMax = 0; - gridPtr->columnPtr = (SlotInfo *) Tcl_Alloc(size); - gridPtr->columnSpace = 0; + gridPtr->columnPtr = (SlotInfo *) ckalloc(size); gridPtr->columnSpace = TYPICAL_SIZE; gridPtr->rowEnd = 0; gridPtr->rowMax = 0; - gridPtr->rowPtr = (SlotInfo *) Tcl_Alloc(size); - gridPtr->rowSpace = 0; + gridPtr->rowPtr = (SlotInfo *) ckalloc(size); gridPtr->rowSpace = TYPICAL_SIZE; + gridPtr->startX = 0; + gridPtr->startY = 0; memset((VOID *) gridPtr->columnPtr, 0, size); memset((VOID *) gridPtr->rowPtr, 0, size); @@ -1986,7 +2014,7 @@ Unlink(slavePtr) * * DestroyGrid -- * - * This procedure is invoked by Tk_EventuallyFree or Tcl_Release + * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a grid at a safe time * (when no-one is using it anymore). Cleaning up the grid involves * freeing the main structure for all windows. and the master structure @@ -2045,6 +2073,7 @@ GridStructureProc(clientData, eventPtr) XEvent *eventPtr; /* Describes what just happened. */ { register Gridder *gridPtr = (Gridder *) clientData; + TkDisplay *dispPtr = ((TkWindow *) gridPtr->tkwin)->dispPtr; if (eventPtr->type == ConfigureNotify) { if (!(gridPtr->flags & REQUESTED_RELAYOUT)) { @@ -2072,13 +2101,13 @@ GridStructureProc(clientData, eventPtr) nextPtr = gridPtr2->nextPtr; gridPtr2->nextPtr = NULL; } - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&gridHashTable, + Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->gridHashTable, (char *) gridPtr->tkwin)); if (gridPtr->flags & REQUESTED_RELAYOUT) { - Tk_CancelIdleCall(ArrangeGrid, (ClientData) gridPtr); + Tcl_CancelIdleCall(ArrangeGrid, (ClientData) gridPtr); } gridPtr->tkwin = NULL; - Tk_EventuallyFree((ClientData) gridPtr, DestroyGrid); + Tcl_EventuallyFree((ClientData) gridPtr, DestroyGrid); } else if (eventPtr->type == MapNotify) { if (!(gridPtr->flags & REQUESTED_RELAYOUT)) { gridPtr->flags |= REQUESTED_RELAYOUT; @@ -2107,7 +2136,7 @@ GridStructureProc(clientData, eventPtr) * * Results: * TCL_OK is returned if all went well. Otherwise, TCL_ERROR is - * returned and interp->result is set to contain an error message. + * returned and the interp's result is set to contain an error message. * * Side effects: * Slave windows get taken over by the grid. @@ -2281,7 +2310,8 @@ ConfigureSlaves(interp, tkwin, argc, argv) return TCL_ERROR; } if (other == slave) { - sprintf(interp->result,"Window can't be managed in itself"); + Tcl_SetResult(interp, "Window can't be managed in itself", + TCL_STATIC); return TCL_ERROR; } masterPtr = GetGrid(other); @@ -2482,6 +2512,7 @@ ConfigureSlaves(interp, tkwin, argc, argv) return TCL_ERROR; } + /* Count the number of consecutive ^'s starting from this position */ for (width=1; width+j < numWindows && *argv[j+width] == REL_VERT; width++) { /* Null Body */ @@ -2494,7 +2525,7 @@ ConfigureSlaves(interp, tkwin, argc, argv) if (lastWindow == NULL) { if (masterPtr->masterDataPtr != NULL) { SetGridSize(masterPtr); - lastRow = masterPtr->masterDataPtr->rowEnd - 1; + lastRow = masterPtr->masterDataPtr->rowEnd - 2; } else { lastRow = 0; } @@ -2502,27 +2533,30 @@ ConfigureSlaves(interp, tkwin, argc, argv) } else { other = Tk_NameToWindow(interp, lastWindow, tkwin); otherPtr = GetGrid(other); - lastRow = otherPtr->row; + lastRow = otherPtr->row + otherPtr->numRows - 2; lastColumn = otherPtr->column + otherPtr->numCols; } for (match=0, slavePtr = masterPtr->slavePtr; slavePtr != NULL; slavePtr = slavePtr->nextPtr) { - if (slavePtr->numCols == width - && slavePtr->column == lastColumn - && slavePtr->row + slavePtr->numRows == lastRow) { - slavePtr->numRows++; - match++; + if (slavePtr->column == lastColumn + && slavePtr->row + slavePtr->numRows - 1 == lastRow) { + if (slavePtr->numCols <= width) { + slavePtr->numRows++; + match++; + j += slavePtr->numCols - 1; + lastWindow = Tk_PathName(slavePtr->tkwin); + break; + } } - lastWindow = Tk_PathName(slavePtr->tkwin); } if (!match) { Tcl_AppendResult(interp, "can't find slave to extend with \"^\".", (char *) NULL); return TCL_ERROR; } - j += width - 1; +/* j += width - 1; */ } if (masterPtr == NULL) { @@ -2613,3 +2647,5 @@ StringToSticky(string) } return sticky; } + + diff --git a/tk/generic/tkImage.c b/tk/generic/tkImage.c index 74ed3bc91b2..778081002a9 100644 --- a/tk/generic/tkImage.c +++ b/tk/generic/tkImage.c @@ -6,7 +6,7 @@ * widgets. * * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -71,12 +71,13 @@ typedef struct ImageMaster { * derived from this name. */ } ImageMaster; -/* - * The following variable points to the first in a list of all known - * image types. - */ - -static Tk_ImageType *imageTypeList = NULL; +typedef struct ThreadSpecificData { + Tk_ImageType *imageTypeList;/* First in a list of all known image + * types. */ + Tk_ImageType *oldImageTypeList;/* First in a list of all known old-style image + * types. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; /* * Prototypes for local procedures: @@ -87,7 +88,7 @@ static void DeleteImage _ANSI_ARGS_((ImageMaster *masterPtr)); /* *---------------------------------------------------------------------- * - * Tk_CreateImageType -- + * Tk_CreateOldImageType, Tk_CreateImageType -- * * This procedure is invoked by an image manager to tell Tk about * a new kind of image and the procedures that manage the new type. @@ -104,20 +105,37 @@ static void DeleteImage _ANSI_ARGS_((ImageMaster *masterPtr)); */ void +Tk_CreateOldImageType(typePtr) + Tk_ImageType *typePtr; /* Structure describing the type. All of + * the fields except "nextPtr" must be filled + * in by caller. Must not have been passed + * to Tk_CreateImageType previously. */ +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + typePtr->nextPtr = tsdPtr->oldImageTypeList; + tsdPtr->oldImageTypeList = typePtr; +} + +void Tk_CreateImageType(typePtr) Tk_ImageType *typePtr; /* Structure describing the type. All of * the fields except "nextPtr" must be filled * in by caller. Must not have been passed * to Tk_CreateImageType previously. */ { - typePtr->nextPtr = imageTypeList; - imageTypeList = typePtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + typePtr->nextPtr = tsdPtr->imageTypeList; + tsdPtr->imageTypeList = typePtr; } /* *---------------------------------------------------------------------- * - * Tk_ImageCmd -- + * Tk_ImageObjCmd -- * * This procedure is invoked to process the "image" Tcl command. * See the user documentation for details on what it does. @@ -132,210 +150,263 @@ Tk_CreateImageType(typePtr) */ int -Tk_ImageCmd(clientData, interp, argc, objv) +Tk_ImageObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ + int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { + static char *imageOptions[] = { + "create", "delete", "height", "names", "type", "types", "width", + (char *) NULL + }; + enum options { + IMAGE_CREATE, IMAGE_DELETE, IMAGE_HEIGHT, IMAGE_NAMES, + IMAGE_TYPE, IMAGE_TYPES, IMAGE_WIDTH + }; TkWindow *winPtr = (TkWindow *) clientData; - int c, i, new, firstOption; - size_t length; + int i, new, firstOption, index; Tk_ImageType *typePtr; ImageMaster *masterPtr; Image *imagePtr; Tcl_HashEntry *hPtr; Tcl_HashSearch search; - char idString[30], *name; - static int id = 0; - - static char **argv = NULL; - if (argv) ckfree((char *) argv); - argv = (char **) ckalloc(argc * sizeof(char *)); - for (i = 0; i < argc; i++) { - argv[i]=Tcl_GetStringFromObj(objv[i], (int *) NULL); + char idString[16 + TCL_INTEGER_SPACE], *name; + TkDisplay *dispPtr = winPtr->dispPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?args?"); + return TCL_ERROR; } - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option ?args?\"", (char *) NULL); + + if (Tcl_GetIndexFromObj(interp, objv[1], imageOptions, "option", 0, + &index) != TCL_OK) { return TCL_ERROR; } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "create", length) == 0)) { - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " create type ?name? ?options?\"", (char *) NULL); - return TCL_ERROR; - } - c = argv[2][0]; + switch ((enum options) index) { + case IMAGE_CREATE: { + char *arg; + Tcl_Obj **args; + int oldimage = 0; + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "type ?name? ?options?"); + return TCL_ERROR; + } - /* - * Look up the image type. - */ + /* + * Look up the image type. + */ - for (typePtr = imageTypeList; typePtr != NULL; - typePtr = typePtr->nextPtr) { - if ((c == typePtr->name[0]) - && (strcmp(argv[2], typePtr->name) == 0)) { - break; + arg = Tcl_GetString(objv[2]); + for (typePtr = tsdPtr->imageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + if ((*arg == typePtr->name[0]) + && (strcmp(arg, typePtr->name) == 0)) { + break; + } + } + if (typePtr == NULL) { + oldimage = 1; + for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + if ((*arg == typePtr->name[0]) + && (strcmp(arg, typePtr->name) == 0)) { + break; + } + } + } + if (typePtr == NULL) { + Tcl_AppendResult(interp, "image type \"", arg, + "\" doesn't exist", (char *) NULL); + return TCL_ERROR; } - } - if (typePtr == NULL) { - Tcl_AppendResult(interp, "image type \"", argv[2], - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - - /* - * Figure out a name to use for the new image. - */ - if ((argc == 3) || (argv[3][0] == '-')) { - id++; - sprintf(idString, "image%d", id); - name = idString; - firstOption = 3; - } else { - name = argv[3]; - firstOption = 4; - } + /* + * Figure out a name to use for the new image. + */ - /* - * Create the data structure for the new image. - */ + if ((objc == 3) || (*(arg = Tcl_GetString(objv[3])) == '-')) { + dispPtr->imageId++; + sprintf(idString, "image%d", dispPtr->imageId); + name = idString; + firstOption = 3; + } else { + name = arg; + firstOption = 4; + } - hPtr = Tcl_CreateHashEntry(&winPtr->mainPtr->imageTable, name, &new); - if (new) { - masterPtr = (ImageMaster *) ckalloc(sizeof(ImageMaster)); - masterPtr->typePtr = NULL; - masterPtr->masterData = NULL; - masterPtr->width = masterPtr->height = 1; - masterPtr->tablePtr = &winPtr->mainPtr->imageTable; - masterPtr->hPtr = hPtr; - masterPtr->instancePtr = NULL; - Tcl_SetHashValue(hPtr, masterPtr); - } else { /* - * An image already exists by this name. Disconnect the - * instances from the master. + * Create the data structure for the new image. */ - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - if (masterPtr->typePtr != NULL) { - for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; - imagePtr = imagePtr->nextPtr) { - (*masterPtr->typePtr->freeProc)( - imagePtr->instanceData, imagePtr->display); - (*imagePtr->changeProc)(imagePtr->widgetClientData, 0, 0, - masterPtr->width, masterPtr->height, masterPtr->width, - masterPtr->height); - } - (*masterPtr->typePtr->deleteProc)(masterPtr->masterData); + hPtr = Tcl_CreateHashEntry(&winPtr->mainPtr->imageTable, + name, &new); + if (new) { + masterPtr = (ImageMaster *) ckalloc(sizeof(ImageMaster)); masterPtr->typePtr = NULL; + masterPtr->masterData = NULL; + masterPtr->width = masterPtr->height = 1; + masterPtr->tablePtr = &winPtr->mainPtr->imageTable; + masterPtr->hPtr = hPtr; + masterPtr->instancePtr = NULL; + Tcl_SetHashValue(hPtr, masterPtr); + } else { + /* + * An image already exists by this name. Disconnect the + * instances from the master. + */ + + masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); + if (masterPtr->typePtr != NULL) { + for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; + imagePtr = imagePtr->nextPtr) { + (*masterPtr->typePtr->freeProc)( + imagePtr->instanceData, imagePtr->display); + (*imagePtr->changeProc)(imagePtr->widgetClientData, + 0, 0, masterPtr->width, masterPtr->height, + masterPtr->width, masterPtr->height); + } + (*masterPtr->typePtr->deleteProc)(masterPtr->masterData); + masterPtr->typePtr = NULL; + } } - } - /* - * Call the image type manager so that it can perform its own - * initialization, then re-"get" for any existing instances of - * the image. - */ + /* + * Call the image type manager so that it can perform its own + * initialization, then re-"get" for any existing instances of + * the image. + */ - if ((*typePtr->createProc)(interp, name, argc-firstOption, - objv+firstOption, typePtr, (Tk_ImageMaster) masterPtr, - &masterPtr->masterData) != TCL_OK) { - DeleteImage(masterPtr); - return TCL_ERROR; + objv += firstOption; + objc -= firstOption; + args = (Tcl_Obj **) objv; + if (oldimage) { + int i; + args = (Tcl_Obj **) ckalloc((objc+1) * sizeof(char *)); + for (i = 0; i < objc; i++) { + args[i] = (Tcl_Obj *) Tcl_GetString(objv[i]); + } + args[objc] = NULL; + } + if ((*typePtr->createProc)(interp, name, objc, + args, typePtr, (Tk_ImageMaster) masterPtr, + &masterPtr->masterData) != TCL_OK) { + DeleteImage(masterPtr); + if (oldimage) { + ckfree((char *) args); + } + return TCL_ERROR; + } + if (oldimage) { + ckfree((char *) args); + } + masterPtr->typePtr = typePtr; + for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; + imagePtr = imagePtr->nextPtr) { + imagePtr->instanceData = (*typePtr->getProc)( + imagePtr->tkwin, masterPtr->masterData); + } + Tcl_SetResult(interp, + Tcl_GetHashKey(&winPtr->mainPtr->imageTable, hPtr), + TCL_STATIC); + break; } - masterPtr->typePtr = typePtr; - for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; - imagePtr = imagePtr->nextPtr) { - imagePtr->instanceData = (*typePtr->getProc)( - imagePtr->tkwin, masterPtr->masterData); + case IMAGE_DELETE: { + for (i = 2; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); + if (hPtr == NULL) { + Tcl_AppendResult(interp, "image \"", arg, + "\" doesn't exist", (char *) NULL); + return TCL_ERROR; + } + masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); + DeleteImage(masterPtr); + } + break; } - Tcl_AppendResult(interp, Tcl_GetHashKey(&winPtr->mainPtr->imageTable, hPtr), (char *) NULL); - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) { - for (i = 2; i < argc; i++) { - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, argv[i]); + case IMAGE_HEIGHT: { + char *arg; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + arg = Tcl_GetString(objv[2]); + hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", argv[i], - "\" doesn't exist", (char *) NULL); + Tcl_AppendResult(interp, "image \"", arg, + "\" doesn't exist", (char *) NULL); return TCL_ERROR; } masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - DeleteImage(masterPtr); + Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->height); + break; } - } else if ((c == 'h') && (strncmp(argv[1], "height", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " height name\"", (char *) NULL); - return TCL_ERROR; - } - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, argv[2]); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", argv[2], - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->height); - } else if ((c == 'n') && (strncmp(argv[1], "names", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " names\"", (char *) NULL); - return TCL_ERROR; - } - for (hPtr = Tcl_FirstHashEntry(&winPtr->mainPtr->imageTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_AppendElement(interp, Tcl_GetHashKey( + case IMAGE_NAMES: { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } + for (hPtr = Tcl_FirstHashEntry(&winPtr->mainPtr->imageTable, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + Tcl_AppendElement(interp, Tcl_GetHashKey( &winPtr->mainPtr->imageTable, hPtr)); + } + break; } - } else if ((c == 't') && (strcmp(argv[1], "type") == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " type name\"", (char *) NULL); - return TCL_ERROR; - } - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, argv[2]); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", argv[2], - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; - } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - if (masterPtr->typePtr != NULL) { - Tcl_AppendResult(interp, masterPtr->typePtr->name, (char *) NULL); - } - } else if ((c == 't') && (strcmp(argv[1], "types") == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " types\"", (char *) NULL); - return TCL_ERROR; - } - for (typePtr = imageTypeList; typePtr != NULL; - typePtr = typePtr->nextPtr) { - Tcl_AppendElement(interp, typePtr->name); + case IMAGE_TYPE: { + char *arg; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + arg = Tcl_GetString(objv[2]); + hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); + if (hPtr == NULL) { + Tcl_AppendResult(interp, "image \"", arg, + "\" doesn't exist", (char *) NULL); + return TCL_ERROR; + } + masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); + if (masterPtr->typePtr != NULL) { + Tcl_SetResult(interp, masterPtr->typePtr->name, TCL_STATIC); + } + break; } - } else if ((c == 'w') && (strncmp(argv[1], "width", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " width name\"", (char *) NULL); - return TCL_ERROR; + case IMAGE_TYPES: { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } + for (typePtr = tsdPtr->imageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + Tcl_AppendElement(interp, typePtr->name); + } + for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + Tcl_AppendElement(interp, typePtr->name); + } + break; } - hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, argv[2]); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "image \"", argv[2], - "\" doesn't exist", (char *) NULL); - return TCL_ERROR; + case IMAGE_WIDTH: { + char *arg; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + arg = Tcl_GetString(objv[2]); + hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); + if (hPtr == NULL) { + Tcl_AppendResult(interp, "image \"", arg, + "\" doesn't exist", (char *) NULL); + return TCL_ERROR; + } + masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); + Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->width); + break; } - masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); - Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->width); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be create, delete, height, names, type, types,", - " or width", (char *) NULL); - return TCL_ERROR; } return TCL_OK; } @@ -379,9 +450,9 @@ Tk_ImageChanged(imageMaster, x, y, width, height, imageWidth, masterPtr->width = imageWidth; masterPtr->height = imageHeight; for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; - imagePtr = imagePtr->nextPtr) { + imagePtr = imagePtr->nextPtr) { (*imagePtr->changeProc)(imagePtr->widgetClientData, x, y, - width, height, imageWidth, imageHeight); + width, height, imageWidth, imageHeight); } } @@ -422,7 +493,7 @@ Tk_NameOfImage(imageMaster) * Results: * The return value is a token for the image. If there is no image * by the given name, then NULL is returned and an error message is - * left in interp->result. + * left in the interp's result. * * Side effects: * Tk records the fact that the widget is using the image, and @@ -537,6 +608,101 @@ Tk_FreeImage(image) /* *---------------------------------------------------------------------- * + * Tk_PostscriptImage -- + * + * This procedure is called by widgets that contain images in order + * to redisplay an image on the screen or an off-screen pixmap. + * + * Results: + * None. + * + * Side effects: + * The image's manager is notified, and it redraws the desired + * portion of the image before returning. + * + *---------------------------------------------------------------------- + */ + +int +Tk_PostscriptImage(image, interp, tkwin, psinfo, x, y, width, height, prepass) + Tk_Image image; /* Token for image to redisplay. */ + Tcl_Interp *interp; + Tk_Window tkwin; + Tk_PostscriptInfo psinfo; /* postscript info */ + int x, y; /* Upper-left pixel of region in image that + * needs to be redisplayed. */ + int width, height; /* Dimensions of region to redraw. */ + int prepass; +{ + Image *imagePtr = (Image *) image; + int result; + XImage *ximage; + Pixmap pmap; + GC newGC; + XGCValues gcValues; + + if (imagePtr->masterPtr->typePtr == NULL) { + /* + * No master for image, so nothing to display on postscript. + */ + return TCL_OK; + } + + /* + * Check if an image specific postscript-generation function + * exists; otherwise go on with generic code. + */ + + if (imagePtr->masterPtr->typePtr->postscriptProc != NULL) { + return (*imagePtr->masterPtr->typePtr->postscriptProc)( + imagePtr->masterPtr->masterData, interp, tkwin, psinfo, + x, y, width, height, prepass); + } + + if (prepass) { + return TCL_OK; + } + + /* + * Create a Pixmap, tell the image to redraw itself there, and then + * generate an XImage from the Pixmap. We can then read pixel + * values out of the XImage. + */ + + pmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), + width, height, Tk_Depth(tkwin)); + + gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin)); + newGC = Tk_GetGC(tkwin, GCForeground, &gcValues); + if (newGC != None) { + XFillRectangle(Tk_Display(tkwin), pmap, newGC, + 0, 0, (unsigned int)width, (unsigned int)height); + Tk_FreeGC(Tk_Display(tkwin), newGC); + } + + Tk_RedrawImage(image, x, y, width, height, pmap, 0, 0); + + ximage = XGetImage(Tk_Display(tkwin), pmap, 0, 0, + (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); + + Tk_FreePixmap(Tk_Display(tkwin), pmap); + + if (ximage == NULL) { + /* The XGetImage() function is apparently not + * implemented on this system. Just ignore it. + */ + return TCL_OK; + } + result = TkPostscriptImage(interp, tkwin, psinfo, ximage, x, y, + width, height); + + XDestroyImage(ximage); + return result; +} + +/* + *---------------------------------------------------------------------- + * * Tk_RedrawImage -- * * This procedure is called by widgets that contain images in order @@ -793,3 +959,41 @@ Tk_GetImageMasterData(interp, name, typePtrPtr) *typePtrPtr = masterPtr->typePtr; return masterPtr->masterData; } + +/* + *---------------------------------------------------------------------- + * + * Tk_SetTSOrigin -- + * + * Set the pattern origin of the tile to a common point (i.e. the + * origin (0,0) of the top level window) so that tiles from two + * different widgets will match up. This done by setting the + * GCTileStipOrigin field is set to the translated origin of the + * toplevel window in the hierarchy. + * + * Results: + * None. + * + * Side Effects: + * The GCTileStipOrigin is reset in the GC. This will cause the + * tile origin to change when the GC is used for drawing. + * + *---------------------------------------------------------------------- + */ +/*ARGSUSED*/ +void +Tk_SetTSOrigin(tkwin, gc, x, y) + Tk_Window tkwin; + GC gc; + int x, y; +{ + while (!Tk_IsTopLevel(tkwin)) { + x -= Tk_X(tkwin) + Tk_Changes(tkwin)->border_width; + y -= Tk_Y(tkwin) + Tk_Changes(tkwin)->border_width; + tkwin = Tk_Parent(tkwin); + } + XSetTSOrigin(Tk_Display(tkwin), gc, x, y); +} + + + diff --git a/tk/generic/tkImgBmap.c b/tk/generic/tkImgBmap.c index fcdc990ed82..47eacf2f560 100644 --- a/tk/generic/tkImgBmap.c +++ b/tk/generic/tkImgBmap.c @@ -5,6 +5,7 @@ * * Copyright (c) 1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -91,6 +92,10 @@ static void ImgBmapDisplay _ANSI_ARGS_((ClientData clientData, static void ImgBmapFree _ANSI_ARGS_((ClientData clientData, Display *display)); static void ImgBmapDelete _ANSI_ARGS_((ClientData clientData)); +static int ImgBmapPostscript _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, + Tk_PostscriptInfo psinfo, int x, int y, + int width, int height, int prepass)); Tk_ImageType tkBitmapImageType = { "bitmap", /* name */ @@ -99,6 +104,7 @@ Tk_ImageType tkBitmapImageType = { ImgBmapDisplay, /* displayProc */ ImgBmapFree, /* freeProc */ ImgBmapDelete, /* deleteProc */ + ImgBmapPostscript, /* postscriptProc */ (Tk_ImageType *) NULL /* nextPtr */ }; @@ -149,13 +155,13 @@ typedef struct ParseInfo { */ static int ImgBmapCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); + Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[])); static void ImgBmapCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static void ImgBmapConfigureInstance _ANSI_ARGS_(( BitmapInstance *instancePtr)); static int ImgBmapConfigureMaster _ANSI_ARGS_(( - BitmapMaster *masterPtr, int argc, char **argv, + BitmapMaster *masterPtr, int argc, Tcl_Obj *CONST objv[], int flags)); static int NextBitmapWord _ANSI_ARGS_((ParseInfo *parseInfoPtr)); @@ -178,12 +184,12 @@ static int NextBitmapWord _ANSI_ARGS_((ParseInfo *parseInfoPtr)); /* ARGSUSED */ static int -ImgBmapCreate(interp, name, argc, objv, typePtr, master, clientDataPtr) +ImgBmapCreate(interp, name, argc, argv, typePtr, master, clientDataPtr) Tcl_Interp *interp; /* Interpreter for application containing * image. */ char *name; /* Name to use for image. */ int argc; /* Number of arguments. */ - Tcl_Obj *CONST objv[]; /* Argument objects for options (doesn't + Tcl_Obj *CONST argv[]; /* Argument objects for options (doesn't * include image name or type). */ Tk_ImageType *typePtr; /* Pointer to our type record (not used). */ Tk_ImageMaster master; /* Token for image, to be used by us in @@ -192,13 +198,11 @@ ImgBmapCreate(interp, name, argc, objv, typePtr, master, clientDataPtr) * it will be returned in later callbacks. */ { BitmapMaster *masterPtr; - char **argv; - int i; masterPtr = (BitmapMaster *) ckalloc(sizeof(BitmapMaster)); masterPtr->tkMaster = master; masterPtr->interp = interp; - masterPtr->imageCmd = Tcl_CreateCommand(interp, name, ImgBmapCmd, + masterPtr->imageCmd = Tcl_CreateObjCommand(interp, name, ImgBmapCmd, (ClientData) masterPtr, ImgBmapCmdDeletedProc); masterPtr->width = masterPtr->height = 0; masterPtr->data = NULL; @@ -211,20 +215,10 @@ ImgBmapCreate(interp, name, argc, objv, typePtr, master, clientDataPtr) masterPtr->maskDataString = NULL; masterPtr->instancePtr = NULL; - /* - * Convert the objv arguments into string equivalent. - * A proper conversion to object format will need to be done in the future - */ - argv = (char **) ckalloc(argc * sizeof(char *)); - for (i = 0; i < argc; i++) { - argv[i] = Tcl_GetStringFromObj(objv[i], NULL); - } if (ImgBmapConfigureMaster(masterPtr, argc, argv, 0) != TCL_OK) { ImgBmapDelete((ClientData) masterPtr); - ckfree((char *) argv); return TCL_ERROR; } - ckfree((char *) argv); *clientDataPtr = (ClientData) masterPtr; return TCL_OK; } @@ -240,7 +234,7 @@ ImgBmapCreate(interp, name, argc, objv, typePtr, master, clientDataPtr) * * Results: * A standard Tcl return value. If TCL_ERROR is returned then - * an error message is left in masterPtr->interp->result. + * an error message is left in the masterPtr->interp's result. * * Side effects: * Existing instances of the image will be redisplayed to match @@ -250,22 +244,30 @@ ImgBmapCreate(interp, name, argc, objv, typePtr, master, clientDataPtr) */ static int -ImgBmapConfigureMaster(masterPtr, argc, argv, flags) +ImgBmapConfigureMaster(masterPtr, objc, objv, flags) BitmapMaster *masterPtr; /* Pointer to data structure describing * overall bitmap image to (reconfigure). */ - int argc; /* Number of entries in argv. */ - char **argv; /* Pairs of configuration options for image. */ + int objc; /* Number of entries in objv. */ + Tcl_Obj *CONST objv[]; /* Pairs of configuration options for image. */ int flags; /* Flags to pass to Tk_ConfigureWidget, * such as TK_CONFIG_ARGV_ONLY. */ { BitmapInstance *instancePtr; int maskWidth, maskHeight, dummy1, dummy2; + char **argv = (char **) ckalloc((objc+1) * sizeof(char *)); + for (dummy1 = 0; dummy1 < objc; dummy1++) { + argv[dummy1]=Tcl_GetString(objv[dummy1]); + } + argv[objc] = NULL; + if (Tk_ConfigureWidget(masterPtr->interp, Tk_MainWindow(masterPtr->interp), - configSpecs, argc, argv, (char *) masterPtr, flags) + configSpecs, objc, argv, (char *) masterPtr, flags) != TCL_OK) { + ckfree((char *) argv); return TCL_ERROR; } + ckfree((char *) argv); /* * Parse the bitmap and/or mask to create binary data. Make sure that @@ -291,7 +293,8 @@ ImgBmapConfigureMaster(masterPtr, argc, argv, flags) if ((masterPtr->maskFileString != NULL) || (masterPtr->maskDataString != NULL)) { if (masterPtr->data == NULL) { - masterPtr->interp->result = "can't have mask without bitmap"; + Tcl_SetResult(masterPtr->interp, "can't have mask without bitmap", + TCL_STATIC); return TCL_ERROR; } masterPtr->maskData = TkGetBitmapData(masterPtr->interp, @@ -304,7 +307,8 @@ ImgBmapConfigureMaster(masterPtr, argc, argv, flags) || (maskHeight != masterPtr->height)) { ckfree(masterPtr->maskData); masterPtr->maskData = NULL; - masterPtr->interp->result = "bitmap and mask have different sizes"; + Tcl_SetResult(masterPtr->interp, + "bitmap and mask have different sizes", TCL_STATIC); return TCL_ERROR; } } @@ -353,6 +357,7 @@ ImgBmapConfigureInstance(instancePtr) XGCValues gcValues; GC gc; unsigned int mask; + Pixmap oldMask; /* * For each of the options in masterPtr, translate the string @@ -395,10 +400,14 @@ ImgBmapConfigureInstance(instancePtr) (unsigned) masterPtr->height); } - if (instancePtr->mask != None) { - Tk_FreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->mask); - instancePtr->mask = None; - } + /* + * Careful: We have to allocate a new mask Pixmap before deleting + * the old one. Otherwise, The XID allocator will always return + * the same XID for the new Pixmap as was used for the old Pixmap. + * And that will prevent the mask from changing in the GC below. + */ + oldMask = instancePtr->mask; + instancePtr->mask = None; if (masterPtr->maskData != NULL) { instancePtr->mask = XCreateBitmapFromData( Tk_Display(instancePtr->tkwin), @@ -406,6 +415,9 @@ ImgBmapConfigureInstance(instancePtr) masterPtr->maskData, (unsigned) masterPtr->width, (unsigned) masterPtr->height); } + if (oldMask != None) { + Tk_FreePixmap(Tk_Display(instancePtr->tkwin), oldMask); + } if (masterPtr->data != NULL) { gcValues.foreground = instancePtr->fg->pixel; @@ -422,8 +434,7 @@ ImgBmapConfigureInstance(instancePtr) gcValues.clip_mask = instancePtr->bitmap; mask |= GCClipMask; } - gc = Tk_GetGCColor(instancePtr->tkwin, mask, &gcValues, - instancePtr->fg, instancePtr->bg); + gc = Tk_GetGC(instancePtr->tkwin, mask, &gcValues); } else { gc = None; } @@ -465,7 +476,7 @@ ImgBmapConfigureInstance(instancePtr) * *heightPtr. *hotXPtr and *hotYPtr are set to the bitmap * hotspot if one is defined, otherwise they are set to -1, -1. * If an error occurred, NULL is returned and an error message is - * left in interp->result. + * left in the interp's result. * * Side effects: * A bitmap is created. @@ -515,6 +526,15 @@ TkGetBitmapData(interp, string, fileName, widthPtr, heightPtr, } return NULL; } + + if (Tcl_SetChannelOption(interp, pi.chan, "-translation", "binary") + != TCL_OK) { + return NULL; + } + if (Tcl_SetChannelOption(interp, pi.chan, "-encoding", "binary") + != TCL_OK) { + return NULL; + } } else { pi.chan = NULL; } @@ -635,8 +655,9 @@ TkGetBitmapData(interp, string, fileName, widthPtr, heightPtr, error: if (interp != NULL) { - interp->result = "format error in bitmap data"; + Tcl_SetResult(interp, "format error in bitmap data", TCL_STATIC); } + errorCleanup: if (data != NULL) { ckfree(data); @@ -735,52 +756,52 @@ NextBitmapWord(parseInfoPtr) */ static int -ImgBmapCmd(clientData, interp, argc, argv) +ImgBmapCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about the image master. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { + static char *bmapOptions[] = {"cget", "configure", (char *) NULL}; BitmapMaster *masterPtr = (BitmapMaster *) clientData; - int c, code; - size_t length; + int code, index; - if (argc < 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s option ?arg arg ...?\"", - argv[0]); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); + if (Tcl_GetIndexFromObj(interp, objv[1], bmapOptions, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + switch (index) { + case 0: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); return TCL_ERROR; } return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs, - (char *) masterPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { + (char *) masterPtr, Tcl_GetString(objv[2]), 0); + } + case 1: { + if (objc == 2) { code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp), configSpecs, (char *) masterPtr, (char *) NULL, 0); - } else if (argc == 3) { + } else if (objc == 3) { code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp), - configSpecs, (char *) masterPtr, argv[2], 0); + configSpecs, (char *) masterPtr, + Tcl_GetString(objv[2]), 0); } else { - code = ImgBmapConfigureMaster(masterPtr, argc-2, argv+2, + code = ImgBmapConfigureMaster(masterPtr, objc-2, objv+2, TK_CONFIG_ARGV_ONLY); } return code; - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget or configure", (char *) NULL); - return TCL_ERROR; + } + default: { + panic("bad const entries to bmapOptions in ImgBmapCmd"); + } } + return TCL_OK; } /* @@ -1080,3 +1101,104 @@ GetByte(chan) return buffer; } } + + +/* + *---------------------------------------------------------------------- + * + * ImgBmapPostscript -- + * + * This procedure is called by the image code to create + * postscript output for an image. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +ImgBmapPostscript(clientData, interp, tkwin, psinfo, x, y, width, height, + prepass) + ClientData clientData; + Tcl_Interp *interp; + Tk_Window tkwin; + Tk_PostscriptInfo psinfo; + int x, y, width, height, prepass; +{ + BitmapMaster *masterPtr = (BitmapMaster *) clientData; + int rowsAtOnce, rowsThisTime; + int curRow, yy; + char buffer[200]; + + if (prepass) { + return TCL_OK; + } + /* + * Color the background, if there is one. + */ + + if (masterPtr->bgUid != NULL) { + XColor color; + XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->bgUid, + &color); + sprintf(buffer, + "%d %d moveto %d 0 rlineto 0 %d rlineto %d %s\n", + x, y, width, height, -width,"0 rlineto closepath"); + Tcl_AppendResult(interp, buffer, (char *) NULL); + if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(interp, "fill\n", (char *) NULL); + } + + /* + * Draw the bitmap, if there is a foreground color. If the bitmap + * is very large, then chop it up into multiple bitmaps, each + * consisting of one or more rows. This is needed because Postscript + * can't handle single strings longer than 64 KBytes long. + */ + + if (masterPtr->fgUid != NULL) { + XColor color; + XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->fgUid, + &color); + if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) { + return TCL_ERROR; + } + if (width > 60000) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "can't generate Postscript", + " for bitmaps more than 60000 pixels wide", + (char *) NULL); + return TCL_ERROR; + } + rowsAtOnce = 60000/width; + if (rowsAtOnce < 1) { + rowsAtOnce = 1; + } + sprintf(buffer, "%d %d translate\n", x, y); + Tcl_AppendResult(interp, buffer, (char *) NULL); + for (curRow = y+height-1; curRow >= y; curRow -= rowsAtOnce) { + rowsThisTime = rowsAtOnce; + if (rowsThisTime > (curRow + 1 - y)) { + rowsThisTime = curRow + 1 - y; + } + sprintf(buffer, "%d %d", width, rowsThisTime); + Tcl_AppendResult(interp, buffer, " true matrix {\n<", + (char *) NULL); + for (yy = curRow; yy >= (curRow - rowsThisTime + 1); yy--) { + sprintf(buffer, "row %d\n", yy); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + sprintf(buffer, "0 %.15g", (double) rowsThisTime); + Tcl_AppendResult(interp, ">\n} imagemask\n", buffer, + " translate\n", (char *) NULL); + } + } + return TCL_OK; +} + diff --git a/tk/generic/tkImgGIF.c b/tk/generic/tkImgGIF.c index 98bb23af4e4..f9588892b4a 100644 --- a/tk/generic/tkImgGIF.c +++ b/tk/generic/tkImgGIF.c @@ -2,8 +2,8 @@ * tkImgGIF.c -- * * A photo image file handler for GIF files. Reads 87a and 89a GIF - * files. At present there is no write function. GIF images may be - * read using the -data option of the photo image. The data may be + * files. At present, there only is a file write function. GIF images + * may be read using the -data option of the photo image. The data may be * given as a binary string in a Tcl_Obj or by representing * the data as BASE64 encoded ascii. Derived from the giftoppm code * found in the pbmplus package and tkImgFmtPPM.c in the tk4.0b2 @@ -63,29 +63,67 @@ typedef struct mFile { #include "tkPort.h" /* + * Non-ASCII encoding support: + * Most data in a GIF image is binary and is treated as such. However, + * a few key bits are stashed in ASCII. If we try to compare those pieces + * to the char they represent, it will fail on any non-ASCII (eg, EBCDIC) + * system. To accomodate these systems, we test against the numeric value + * of the ASCII characters instead of the characters themselves. This is + * encoding independant. + */ + +static CONST char GIF87a[] = + { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x00 }; /* ASCII GIF87a */ +static CONST char GIF89a[] = + { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x00 }; /* ASCII GIF89a */ +# define GIF_TERMINATOR 0x3b /* ASCII ; */ +# define GIF_EXTENSION 0x21 /* ASCII ! */ +# define GIF_START 0x2c /* ASCII , */ + +/* + * HACK ALERT!! HACK ALERT!! HACK ALERT!! + * This code is hard-wired for reading from files. In order to read + * from a data stream, we'll trick fread so we can reuse the same code. + * 0==from file; 1==from base64 encoded data; 2==from binary data + */ + +typedef struct ThreadSpecificData { + int fromData; +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; + +/* * The format record for the GIF file format: */ -static int FileMatchGIF _ANSI_ARGS_((Tcl_Channel chan, char *fileName, - char *formatString, int *widthPtr, int *heightPtr)); +static int FileMatchGIF _ANSI_ARGS_((Tcl_Channel chan, CONST char *fileName, + Tcl_Obj *format, int *widthPtr, int *heightPtr, + Tcl_Interp *interp)); static int FileReadGIF _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_Channel chan, char *fileName, char *formatString, + Tcl_Channel chan, CONST char *fileName, Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY)); static int StringMatchGIF _ANSI_ARGS_(( Tcl_Obj *dataObj, - char *formatString, int *widthPtr, int *heightPtr)); + Tcl_Obj *format, int *widthPtr, int *heightPtr, + Tcl_Interp *interp)); static int StringReadGIF _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *dataObj, - char *formatString, Tk_PhotoHandle imageHandle, + Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY)); +static int FileWriteGIF _ANSI_ARGS_((Tcl_Interp *interp, + CONST char *filename, Tcl_Obj *format, + Tk_PhotoImageBlock *blockPtr)); +static int CommonWriteGIF _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Channel handle, Tcl_Obj *format, + Tk_PhotoImageBlock *blockPtr)); Tk_PhotoImageFormat tkImgFmtGIF = { - "GIF", /* name */ + "gif", /* name */ FileMatchGIF, /* fileMatchProc */ StringMatchGIF, /* stringMatchProc */ FileReadGIF, /* fileReadProc */ StringReadGIF, /* stringReadProc */ - NULL, /* fileWriteProc */ + FileWriteGIF, /* fileWriteProc */ NULL, /* stringWriteProc */ }; @@ -102,15 +140,6 @@ Tk_PhotoImageFormat tkImgFmtGIF = { #define ReadOK(file,buffer,len) (Fread(buffer, len, 1, file) != 0) /* - * HACK ALERT!! HACK ALERT!! HACK ALERT!! - * This code is hard-wired for reading from files. In order to read - * from a data stream, we'll trick fread so we can reuse the same code. - * 0==from file; 1==from base64 encoded data; 2==from binary data - */ - -static int fromData=0; - -/* * Prototypes for local procedures defined in this file: */ @@ -120,8 +149,6 @@ static int GetCode _ANSI_ARGS_((Tcl_Channel chan, int code_size, int flag)); static int GetDataBlock _ANSI_ARGS_((Tcl_Channel chan, unsigned char *buf)); -static int LWZReadByte _ANSI_ARGS_((Tcl_Channel chan, int flag, - int input_code_size)); static int ReadColorMap _ANSI_ARGS_((Tcl_Channel chan, int number, unsigned char buffer[MAXCOLORMAPSIZE][4])); static int ReadGIFHeader _ANSI_ARGS_((Tcl_Channel chan, @@ -145,6 +172,7 @@ static int Mgetc _ANSI_ARGS_((MFile *handle)); static int char64 _ANSI_ARGS_((int c)); static void mInit _ANSI_ARGS_((unsigned char *string, MFile *handle)); + /* *---------------------------------------------------------------------- @@ -165,13 +193,14 @@ static void mInit _ANSI_ARGS_((unsigned char *string, */ static int -FileMatchGIF(chan, fileName, formatString, widthPtr, heightPtr) +FileMatchGIF(chan, fileName, format, widthPtr, heightPtr, interp) Tcl_Channel chan; /* The image file, open for reading. */ - char *fileName; /* The name of the image file. */ - char *formatString; /* User-specified format string, or NULL. */ + CONST char *fileName; /* The name of the image file. */ + Tcl_Obj *format; /* User-specified format object, or NULL. */ int *widthPtr, *heightPtr; /* The dimensions of the image are * returned here if the file is a valid * raw GIF file. */ + Tcl_Interp *interp; /* not used */ { return ReadGIFHeader(chan, widthPtr, heightPtr); } @@ -197,12 +226,12 @@ FileMatchGIF(chan, fileName, formatString, widthPtr, heightPtr) */ static int -FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY, +FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY, width, height, srcX, srcY) Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ Tcl_Channel chan; /* The image file, open for reading. */ - char *fileName; /* The name of the image file. */ - char *formatString; /* User-specified format string, or NULL. */ + CONST char *fileName; /* The name of the image file. */ + Tcl_Obj *format; /* User-specified format object, or NULL. */ Tk_PhotoHandle imageHandle; /* The photo image to write into. */ int destX, destY; /* Coordinates of top-left pixel in * photo image to be written to. */ @@ -212,15 +241,39 @@ FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY, * in image being read. */ { int fileWidth, fileHeight; - int nBytes; + int nBytes, index = 0, argc = 0, i; + Tcl_Obj **objv; Tk_PhotoImageBlock block; unsigned char buf[100]; + unsigned char *trashBuffer = NULL; int bitPixel; unsigned char colorMap[MAXCOLORMAPSIZE][4]; int transparent = -1; + static char *optionStrings[] = { + "-index", NULL + }; + if (format && Tcl_ListObjGetElements(interp, format, + &argc, &objv) != TCL_OK) { + return TCL_ERROR; + } + for (i = 1; i < argc; i++) { + if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, "option name", 0, + &nBytes) != TCL_OK) { + return TCL_ERROR; + } + if (i == (argc-1)) { + Tcl_AppendResult(interp, "no value given for \"", + Tcl_GetStringFromObj(objv[i], NULL), + "\" option", (char *) NULL); + return TCL_ERROR; + } + if (Tcl_GetIntFromObj(interp, objv[++i], &index) != TCL_OK) { + return TCL_ERROR; + } + } if (!ReadGIFHeader(chan, &fileWidth, &fileHeight)) { - Tcl_AppendResult(interp, "couldn't read GIF header from file \"", + Tcl_AppendResult(interp, "couldn't read GIF header from file \"", fileName, "\"", NULL); return TCL_ERROR; } @@ -263,8 +316,8 @@ FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY, block.offset[0] = 0; block.offset[1] = 1; block.offset[2] = 2; - nBytes = height * block.pitch; - block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes); + block.offset[3] = 3; + block.pixelPtr = NULL; while (1) { if (Fread(buf, 1, 1, chan) != 1) { @@ -276,15 +329,17 @@ FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY, break; } - if (buf[0] == ';') { + if (buf[0] == GIF_TERMINATOR) { /* * GIF terminator. */ - break; + Tcl_AppendResult(interp,"no image data for this index", + (char *) NULL); + goto error; } - if (buf[0] == '!') { + if (buf[0] == GIF_EXTENSION) { /* * This is a GIF extension. */ @@ -301,7 +356,7 @@ FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY, continue; } - if (buf[0] != ',') { + if (buf[0] != GIF_START) { /* * Not a valid start character; ignore it. */ @@ -313,8 +368,55 @@ FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY, goto error; } + fileWidth = LM_to_uint(buf[4],buf[5]); + fileHeight = LM_to_uint(buf[6],buf[7]); + bitPixel = 1<<((buf[8]&0x07)+1); + if (index--) { + /* this is not the image we want to read: skip it. */ + if (BitSet(buf[8], LOCALCOLORMAP)) { + if (!ReadColorMap(chan, bitPixel, colorMap)) { + Tcl_AppendResult(interp, + "error reading color map", (char *) NULL); + goto error; + } + } + + /* If we've not yet allocated a trash buffer, do so now */ + if (trashBuffer == NULL) { + nBytes = fileWidth * fileHeight * 3; + trashBuffer = + (unsigned char *) ckalloc((unsigned int) nBytes); + } + + /* + * Slurp! Process the data for this image and stuff it in a + * trash buffer. + * + * Yes, it might be more efficient here to *not* store the data + * (we're just going to throw it away later). However, I elected + * to implement it this way for good reasons. First, I wanted to + * avoid duplicating the (fairly complex) LWZ decoder in ReadImage. + * Fine, you say, why didn't you just modify it to allow the use of + * a NULL specifier for the output buffer? I tried that, but it + * negatively impacted the performance of what I think will be the + * common case: reading the first image in the file. Rather than + * marginally improve the speed of the less frequent case, I chose + * to maintain high performance for the common case. + */ + if (ReadImage(interp, (char *) trashBuffer, chan, fileWidth, + fileHeight, colorMap, 0, 0, 0, 0, 0, -1) != TCL_OK) { + goto error; + } + continue; + } + + /* If a trash buffer has been allocated, free it now */ + if (trashBuffer != NULL) { + ckfree((char *)trashBuffer); + trashBuffer = NULL; + } if (BitSet(buf[8], LOCALCOLORMAP)) { if (!ReadColorMap(chan, bitPixel, colorMap)) { Tcl_AppendResult(interp, "error reading color map", @@ -322,50 +424,62 @@ FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY, goto error; } } + + index = LM_to_uint(buf[0],buf[1]); + srcX -= index; + if (srcX<0) { + destX -= srcX; width += srcX; + srcX = 0; + } + + if (width > fileWidth) { + width = fileWidth; + } + + index = LM_to_uint(buf[2],buf[3]); + srcY -= index; + if (index > srcY) { + destY -= srcY; height += srcY; + srcY = 0; + } + if (height > fileHeight) { + height = fileHeight; + } + + if ((width <= 0) || (height <= 0)) { + block.pixelPtr = 0; + goto noerror; + } + + block.width = width; + block.height = height; + block.pixelSize = (transparent>=0) ? 4 : 3; + block.offset[3] = (transparent>=0) ? 3 : 0; + block.pitch = block.pixelSize * width; + nBytes = block.pitch * height; + block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes); + if (ReadImage(interp, (char *) block.pixelPtr, chan, width, height, colorMap, fileWidth, fileHeight, srcX, srcY, BitSet(buf[8], INTERLACE), transparent) != TCL_OK) { goto error; } break; - } + } - if (transparent == -1) { - Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height); - } else { - int x, y, end; - unsigned char *imagePtr, *rowPtr, *pixelPtr; - - imagePtr = rowPtr = block.pixelPtr; - for (y = 0; y < height; y++) { - x = 0; - pixelPtr = rowPtr; - while(x < width) { - /* search for first non-transparent pixel */ - while ((x < width) && !(pixelPtr[CM_ALPHA])) { - x++; pixelPtr += 4; - } - end = x; - /* search for first transparent pixel */ - while ((end < width) && pixelPtr[CM_ALPHA]) { - end++; pixelPtr += 4; - } - if (end > x) { - block.pixelPtr = rowPtr + 4 * x; - Tk_PhotoPutBlock(imageHandle, &block, destX+x, - destY+y, end-x, 1); - } - x = end; - } - rowPtr += block.pitch; - } - block.pixelPtr = imagePtr; + Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height); + + noerror: + if (block.pixelPtr) { + ckfree((char *) block.pixelPtr); } - ckfree((char *) block.pixelPtr); + Tcl_AppendResult(interp, tkImgFmtGIF.name, (char *) NULL); return TCL_OK; error: - ckfree((char *) block.pixelPtr); + if (block.pixelPtr) { + ckfree((char *) block.pixelPtr); + } return TCL_ERROR; } @@ -389,17 +503,18 @@ FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY, */ static int -StringMatchGIF(dataObj, formatString, widthPtr, heightPtr) +StringMatchGIF(dataObj, format, widthPtr, heightPtr, interp) Tcl_Obj *dataObj; /* the object containing the image data */ - char *formatString; /* the image format string */ + Tcl_Obj *format; /* the image format object, or NULL */ int *widthPtr; /* where to put the string width */ int *heightPtr; /* where to put the string height */ + Tcl_Interp *interp; /* not used */ { unsigned char *data, header[10]; int got, length; MFile handle; - data = Tcl_GetStringFromObj(dataObj, &length); + data = Tcl_GetByteArrayFromObj(dataObj, &length); /* Header is a minimum of 10 bytes */ if (length < 10) { @@ -408,14 +523,14 @@ StringMatchGIF(dataObj, formatString, widthPtr, heightPtr) /* Check whether the data is Base64 encoded */ - if ((strncmp("GIF87a", data, 6) != 0) && - (strncmp("GIF89a", data, 6) != 0)) { + if ((strncmp(GIF87a, (char *) data, 6) != 0) && + (strncmp(GIF89a, (char *) data, 6) != 0)) { /* Try interpreting the data as Base64 encoded */ mInit((unsigned char *) data, &handle); got = Mread(header, 10, 1, &handle); if (got != 10 - || ((strncmp("GIF87a", (char *) header, 6) != 0) - && (strncmp("GIF89a", (char *) header, 6) != 0))) { + || ((strncmp(GIF87a, (char *) header, 6) != 0) + && (strncmp(GIF89a, (char *) header, 6) != 0))) { return 0; } } else { @@ -448,37 +563,41 @@ StringMatchGIF(dataObj, formatString, widthPtr, heightPtr) */ static int -StringReadGIF(interp,dataObj,formatString,imageHandle, +StringReadGIF(interp, dataObj, format, imageHandle, destX, destY, width, height, srcX, srcY) Tcl_Interp *interp; /* interpreter for reporting errors in */ Tcl_Obj *dataObj; /* object containing the image */ - char *formatString; /* format string if any */ + Tcl_Obj *format; /* format object, or NULL */ Tk_PhotoHandle imageHandle; /* the image to write this data into */ int destX, destY; /* The rectangular region of the */ int width, height; /* image to copy */ int srcX, srcY; { - int result; - MFile handle; - Tcl_Channel dataSrc; - char *data; - /* Check whether the data is Base64 encoded */ - data = Tcl_GetStringFromObj(dataObj, NULL); - if ((strncmp("GIF87a", data, 6) != 0) && - (strncmp("GIF89a", data, 6) != 0)) { - mInit((unsigned char *)data,&handle); - fromData = 1; - dataSrc = (Tcl_Channel) &handle; - } else { - fromData = 2; - mInit((unsigned char *)data,&handle); - dataSrc = (Tcl_Channel) &handle; - } - result = FileReadGIF(interp, dataSrc, "inline data", - formatString, imageHandle, destX, destY, width, height, - srcX, srcY); - fromData = 0; - return(result); + int result; + MFile handle; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + Tcl_Channel dataSrc; + char *data; + + /* + * Check whether the data is Base64 encoded + */ + data = (char *) Tcl_GetByteArrayFromObj(dataObj, NULL); + if ((strncmp(GIF87a, data, 6) != 0) && + (strncmp(GIF89a, data, 6) != 0)) { + mInit((unsigned char *)data, &handle); + tsdPtr->fromData = 1; + dataSrc = (Tcl_Channel) &handle; + } else { + tsdPtr->fromData = 2; + mInit((unsigned char *)data, &handle); + dataSrc = (Tcl_Channel) &handle; + } + result = FileReadGIF(interp, dataSrc, "inline data", + format, imageHandle, destX, destY, width, height, srcX, srcY); + tsdPtr->fromData = 0; + return(result); } /* @@ -510,8 +629,8 @@ ReadGIFHeader(chan, widthPtr, heightPtr) unsigned char buf[7]; if ((Fread(buf, 1, 6, chan) != 6) - || ((strncmp("GIF87a", (char *) buf, 6) != 0) - && (strncmp("GIF89a", (char *) buf, 6) != 0))) { + || ((strncmp(GIF87a, (char *) buf, 6) != 0) + && (strncmp(GIF89a, (char *) buf, 6) != 0))) { return 0; } @@ -545,10 +664,12 @@ ReadColorMap(chan, number, buffer) return 0; } - buffer[i][CM_RED] = rgb[0] ; - buffer[i][CM_GREEN] = rgb[1] ; - buffer[i][CM_BLUE] = rgb[2] ; - buffer[i][CM_ALPHA] = 255 ; + if (buffer) { + buffer[i][CM_RED] = rgb[0] ; + buffer[i][CM_GREEN] = rgb[1] ; + buffer[i][CM_BLUE] = rgb[2] ; + buffer[i][CM_ALPHA] = 255 ; + } } return 1; } @@ -621,6 +742,34 @@ GetDataBlock(chan, buf) } + +/* + *---------------------------------------------------------------------- + * + * ReadImage -- + * + * Process a GIF image from a given source, with a given height, + * width, transparency, etc. + * + * This code is based on the code found in the ImageMagick GIF decoder, + * which is (c) 2000 ImageMagick Studio. + * + * Some thoughts on our implementation: + * It sure would be nice if ReadImage didn't take 11 parameters! I think + * that if we were smarter, we could avoid doing that. + * + * Possible further optimizations: we could pull the GetCode function + * directly into ReadImage, which would improve our speed. + * + * Results: + * Processes a GIF image and loads the pixel data into a memory array. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + static int ReadImage(interp, imagePtr, chan, len, rows, cmap, width, height, srcX, srcY, interlace, transparent) @@ -634,26 +783,27 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap, int interlace; int transparent; { - unsigned char c; + unsigned char initialCodeSize; int v; - int xpos = 0, ypos = 0, pass = 0; - char *pixelPtr; - - + int xpos = 0, ypos = 0, pass = 0, i; + register char *pixelPtr; + CONST static int interlaceStep[] = { 8, 8, 4, 2 }; + CONST static int interlaceStart[] = { 0, 4, 2, 1 }; + unsigned short prefix[(1 << MAX_LWZ_BITS)]; + unsigned char append[(1 << MAX_LWZ_BITS)]; + unsigned char stack[(1 << MAX_LWZ_BITS)*2]; + register unsigned char *top; + int codeSize, clearCode, inCode, endCode, oldCode, maxCode, + code, firstCode; + /* - * Initialize the Compression routines + * Initialize the decoder */ - if (! ReadOK(chan, &c, 1)) { + if (! ReadOK(chan, &initialCodeSize, 1)) { Tcl_AppendResult(interp, "error reading GIF image: ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } - - if (LWZReadByte(chan, 1, c) < 0) { - interp->result = "format error in GIF image"; - return TCL_ERROR; - } - if (transparent!=-1) { cmap[transparent][CM_RED] = 0; cmap[transparent][CM_GREEN] = 0; @@ -662,180 +812,194 @@ ReadImage(interp, imagePtr, chan, len, rows, cmap, } pixelPtr = imagePtr; - while ((v = LWZReadByte(chan, 0, c)) >= 0 ) { - if ((xpos>=srcX) && (xpos<srcX+len) && - (ypos>=srcY) && (ypos<srcY+rows)) { - *pixelPtr++ = cmap[v][CM_RED]; - *pixelPtr++ = cmap[v][CM_GREEN]; - *pixelPtr++ = cmap[v][CM_BLUE]; - *pixelPtr++ = cmap[v][CM_ALPHA]; - } - - ++xpos; - if (xpos == width) { - xpos = 0; - if (interlace) { - switch (pass) { - case 0: - case 1: - ypos += 8; break; - case 2: - ypos += 4; break; - case 3: - ypos += 2; break; - } - - while (ypos >= height) { - ++pass; - switch (pass) { - case 1: - ypos = 4; break; - case 2: - ypos = 2; break; - case 3: - ypos = 1; break; - default: - return TCL_OK; - } - } - } else { - ++ypos; - } - pixelPtr = imagePtr + (ypos-srcY) * len * 4; - } - if (ypos >= height) - break; + /* Initialize the decoder */ + /* Set values for "special" numbers: + * clear code reset the decoder + * end code stop decoding + * code size size of the next code to retrieve + * max code next available table position + */ + clearCode = 1 << (int) initialCodeSize; + endCode = clearCode + 1; + codeSize = (int) initialCodeSize + 1; + maxCode = clearCode + 2; + oldCode = -1; + firstCode = -1; + + memset((void *)prefix, 0, (1 << MAX_LWZ_BITS) * sizeof(short)); + memset((void *)append, 0, (1 << MAX_LWZ_BITS) * sizeof(char)); + for (i = 0; i < clearCode; i++) { + append[i] = i; } - return TCL_OK; -} - -static int -LWZReadByte(chan, flag, input_code_size) - Tcl_Channel chan; - int flag; - int input_code_size; -{ - static int fresh = 0; - int code, incode; - static int code_size, set_code_size; - static int max_code, max_code_size; - static int firstcode, oldcode; - static int clear_code, end_code; - static int table[2][(1<< MAX_LWZ_BITS)]; - static int stack[(1<<(MAX_LWZ_BITS))*2], *sp; - register int i; - - if (flag) { - set_code_size = input_code_size; - code_size = set_code_size+1; - clear_code = 1 << set_code_size ; - end_code = clear_code + 1; - max_code_size = 2*clear_code; - max_code = clear_code+2; + top = stack; - GetCode(chan, 0, 1); + GetCode(chan, 0, 1); - fresh = 1; + /* Read until we finish the image */ + for (i = 0, ypos = 0; i < rows; i++) { + for (xpos = 0; xpos < len; ) { - for (i = 0; i < clear_code; ++i) { - table[0][i] = 0; - table[1][i] = i; - } - for (; i < (1<<MAX_LWZ_BITS); ++i) { - table[0][i] = table[1][0] = 0; - } + if (top == stack) { + /* Bummer -- our stack is empty. Now we have to work! */ + code = GetCode(chan, codeSize, 0); + if (code < 0) { + return TCL_OK; + } - sp = stack; + if (code > maxCode || code == endCode) { + /* + * If we're doing things right, we should never + * receive a code that is greater than our current + * maximum code. If we do, bail, because our decoder + * does not yet have that code set up. + * + * If the code is the magic endCode value, quit. + */ + return TCL_OK; + } - return 0; - } else if (fresh) { - fresh = 0; - do { - firstcode = oldcode = GetCode(chan, code_size, 0); - } while (firstcode == clear_code); - return firstcode; - } + if (code == clearCode) { + /* Reset the decoder */ + codeSize = initialCodeSize + 1; + maxCode = clearCode + 2; + oldCode = -1; + continue; + } + + if (oldCode == -1) { + /* + * Last pass reset the decoder, so the first code we + * see must be a singleton. Seed the stack with it, + * and set up the old/first code pointers for + * insertion into the string table. We can't just + * roll this into the clearCode test above, because + * at that point we have not yet read the next code. + */ + *top++=append[code]; + oldCode = code; + firstCode = code; + continue; + } + + inCode = code; + + if (code == maxCode) { + /* + * maxCode is always one bigger than our highest assigned + * code. If the code we see is equal to maxCode, then + * we are about to add a new string to the table. ??? + */ + *top++ = firstCode; + code = oldCode; + } - if (sp > stack) { - return *--sp; - } + while (code > clearCode) { + /* + * Populate the stack by tracing the string in the + * string table from its tail to its head + */ + *top++ = append[code]; + code = prefix[code]; + } + firstCode = append[code]; - while ((code = GetCode(chan, code_size, 0)) >= 0) { - if (code == clear_code) { - for (i = 0; i < clear_code; ++i) { - table[0][i] = 0; - table[1][i] = i; - } - - for (; i < (1<<MAX_LWZ_BITS); ++i) { - table[0][i] = table[1][i] = 0; - } + /* + * If there's no more room in our string table, quit. + * Otherwise, add a new string to the table + */ + if (maxCode >= (1 << MAX_LWZ_BITS)) { + return TCL_OK; + } - code_size = set_code_size+1; - max_code_size = 2*clear_code; - max_code = clear_code+2; - sp = stack; - firstcode = oldcode = GetCode(chan, code_size, 0); - return firstcode; + /* Push the head of the string onto the stack */ + *top++ = firstCode; - } else if (code == end_code) { - int count; - unsigned char buf[260]; + /* Add a new string to the string table */ + prefix[maxCode] = oldCode; + append[maxCode] = firstCode; + maxCode++; - if (ZeroDataBlock) { - return -2; + /* maxCode tells us the maximum code value we can accept. + * If we see that we need more bits to represent it than + * we are requesting from the unpacker, we need to increase + * the number we ask for. + */ + if ((maxCode >= (1 << codeSize)) + && (maxCode < (1<<MAX_LWZ_BITS))) { + codeSize++; + } + oldCode = inCode; } - - while ((count = GetDataBlock(chan, buf)) > 0) - /* Empty body */; - if (count != 0) { - return -2; + /* Pop the next color index off the stack */ + v = *(--top); + if (v < 0) { + return TCL_OK; } - } - - incode = code; - - if (code >= max_code) { - *sp++ = firstcode; - code = oldcode; - } - while (code >= clear_code) { - *sp++ = table[1][code]; - if (code == table[0][code]) { - return -2; - - /* - * Used to be this instead, Steve Ball suggested - * the change to just return. - printf("circular table entry BIG ERROR\n"); - */ + /* + * If pixelPtr is null, we're skipping this image (presumably + * there are more in the file and we will be called to read + * one of them later) + */ + *pixelPtr++ = cmap[v][CM_RED]; + *pixelPtr++ = cmap[v][CM_GREEN]; + *pixelPtr++ = cmap[v][CM_BLUE]; + if (transparent >= 0) { + *pixelPtr++ = cmap[v][CM_ALPHA]; } - code = table[0][code]; - } - - *sp++ = firstcode = table[1][code]; + xpos++; - if ((code = max_code) <(1<<MAX_LWZ_BITS)) { - table[0][code] = oldcode; - table[1][code] = firstcode; - ++max_code; - if ((max_code>=max_code_size) && (max_code_size < (1<<MAX_LWZ_BITS))) { - max_code_size *= 2; - ++code_size; - } } - oldcode = incode; - - if (sp > stack) - return *--sp; + /* If interlacing, the next ypos is not just +1 */ + if (interlace) { + ypos += interlaceStep[pass]; + while (ypos >= height) { + pass++; + if (pass > 3) { + return TCL_OK; + } + ypos = interlaceStart[pass]; + } + } else { + ypos++; } - return code; + pixelPtr = imagePtr + (ypos) * len * ((transparent>=0)?4:3); + } + return TCL_OK; } + +/* + *---------------------------------------------------------------------- + * + * GetCode -- + * + * Extract the next compression code from the file. In GIF's, the + * compression codes are between 3 and 12 bits long and are then + * packed into 8 bit bytes, left to right, for example: + * bbbaaaaa + * dcccccbb + * eeeedddd + * ... + * We use a byte buffer read from the file and a sliding window + * to unpack the bytes. Thanks to ImageMagick for the sliding window + * idea. + * args: chan the channel to read from + * code_size size of the code to extract + * flag boolean indicating whether the extractor + * should be reset or not + * + * Results: + * code the next compression code + * + * Side effects: + * May consume more input from chan. + * + *---------------------------------------------------------------------- + */ static int GetCode(chan, code_size, flag) @@ -844,46 +1008,50 @@ GetCode(chan, code_size, flag) int flag; { static unsigned char buf[280]; - static int curbit, lastbit, done, last_byte; - int i, j, ret; - unsigned char count; + static int bytes = 0, done; + static unsigned char *c; + static unsigned int window; + static int bitsInWindow = 0; + int ret; + if (flag) { - curbit = 0; - lastbit = 0; + /* Initialize the decoder */ + bitsInWindow = 0; + bytes = 0; + window = 0; done = 0; + c = NULL; return 0; } - - if ( (curbit+code_size) >= lastbit) { + while (bitsInWindow < code_size) { + /* Not enough bits in our window to cover the request */ if (done) { - /* ran off the end of my bits */ return -1; } - if (last_byte >= 2) { - buf[0] = buf[last_byte-2]; - } - if (last_byte >= 1) { - buf[1] = buf[last_byte-1]; - } - - if ((count = GetDataBlock(chan, &buf[2])) == 0) { - done = 1; + if (bytes == 0) { + /* Not enough bytes in our buffer to add to the window */ + bytes = GetDataBlock(chan, buf); + c = buf; + if (bytes <= 0) { + done = 1; + break; + } } - - last_byte = 2 + count; - curbit = (curbit - lastbit) + 16; - lastbit = (2+count)*8 ; + /* Tack another byte onto the window, see if that's enough */ + window += (*c) << bitsInWindow; + c++; + bitsInWindow += 8; + bytes--; } - ret = 0; - for (i = curbit, j = 0; j < code_size; ++i, ++j) { - ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j; - } - - curbit += code_size; - + /* The next code will always be the last code_size bits of the window */ + ret = window & ((1 << code_size) - 1); + + /* Shift data in the window to put the next code at the end */ + window >>= code_size; + bitsInWindow -= code_size; return ret; } @@ -1083,16 +1251,761 @@ Fread(dst, hunk, count, chan) size_t hunk,count; /* how many */ Tcl_Channel chan; { - MFile *handle; - switch (fromData) { - case 0: - return Tcl_Read(chan, (char *) dst, (int) (hunk * count)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + MFile *handle; + + switch (tsdPtr->fromData) { case 1: return(Mread(dst, hunk, count, (MFile *) chan)); case 2: handle = (MFile *) chan; - memcpy((VOID *)dst, (VOID *) handle->data, (int) (hunk * count)); + memcpy((VOID *)dst, (VOID *) handle->data, (size_t) (hunk * count)); handle->data += hunk * count; return((int) (hunk * count)); + default: + return Tcl_Read(chan, (char *) dst, (int) (hunk * count)); } } + + +/* + * ChanWriteGIF - writes a image in GIF format. + *------------------------------------------------------------------------- + * Author: Lolo + * Engeneering Projects Area + * Department of Mining + * University of Oviedo + * e-mail zz11425958@zeus.etsimo.uniovi.es + * lolo@pcsig22.etsimo.uniovi.es + * Date: Fri September 20 1996 + * + * Modified for transparency handling (gif89a) and miGIF compression + * by Jan Nijtmans <j.nijtmans@chello.nl> + * + *---------------------------------------------------------------------- + * FileWriteGIF- + * + * This procedure is called by the photo image type to write + * GIF format data from a photo image into a given file + * + * Results: + * A standard TCL completion code. If TCL_ERROR is returned + * then an error message is left in interp->result. + * + *---------------------------------------------------------------------- + */ + + /* + * Types, defines and variables needed to write and compress a GIF. + */ + +typedef int (* ifunptr) _ANSI_ARGS_((void)); + +#define LSB(a) ((unsigned char) (((short)(a)) & 0x00FF)) +#define MSB(a) ((unsigned char) (((short)(a)) >> 8)) + +#define GIFBITS 12 +#define HSIZE 5003 /* 80% occupancy */ + +static int ssize; +static int csize; +static int rsize; +static unsigned char *pixelo; +static int pixelSize; +static int pixelPitch; +static int greenOffset; +static int blueOffset; +static int alphaOffset; +static int num; +static unsigned char mapa[MAXCOLORMAPSIZE][3]; + +/* + * Definition of new functions to write GIFs + */ + +static int color _ANSI_ARGS_((int red,int green, int blue, + unsigned char mapa[MAXCOLORMAPSIZE][3])); +static void compress _ANSI_ARGS_((int init_bits, Tcl_Channel handle, + ifunptr readValue)); +static int nuevo _ANSI_ARGS_((int red, int green ,int blue, + unsigned char mapa[MAXCOLORMAPSIZE][3])); +static void savemap _ANSI_ARGS_((Tk_PhotoImageBlock *blockPtr, + unsigned char mapa[MAXCOLORMAPSIZE][3])); +static int ReadValue _ANSI_ARGS_((void)); + +static int +FileWriteGIF (interp, filename, format, blockPtr) + Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ + CONST char *filename; + Tcl_Obj *format; + Tk_PhotoImageBlock *blockPtr; +{ + Tcl_Channel chan = NULL; + int result; + + chan = Tcl_OpenFileChannel(interp, (char *) filename, "w", 0644); + if (!chan) { + return TCL_ERROR; + } + if (Tcl_SetChannelOption(interp, chan, "-translation", "binary") != TCL_OK) { + return TCL_ERROR; + } + + result = CommonWriteGIF(interp, chan, format, blockPtr); + if (Tcl_Close(interp, chan) == TCL_ERROR) { + return TCL_ERROR; + } + return result; +} + +#define Mputc(c,handle) Tcl_Write(handle,(char *) &c,1) + +static int +CommonWriteGIF(interp, handle, format, blockPtr) + Tcl_Interp *interp; + Tcl_Channel handle; + Tcl_Obj *format; + Tk_PhotoImageBlock *blockPtr; +{ + int resolution; + + long width,height,x; + unsigned char c; + unsigned int top,left; + + top = 0; + left = 0; + + pixelSize=blockPtr->pixelSize; + greenOffset=blockPtr->offset[1]-blockPtr->offset[0]; + blueOffset=blockPtr->offset[2]-blockPtr->offset[0]; + alphaOffset = blockPtr->offset[0]; + if (alphaOffset < blockPtr->offset[2]) { + alphaOffset = blockPtr->offset[2]; + } + if (++alphaOffset < pixelSize) { + alphaOffset -= blockPtr->offset[0]; + } else { + alphaOffset = 0; + } + + Tcl_Write(handle, (char *) (alphaOffset ? GIF89a : GIF87a), 6); + + for (x=0;x<MAXCOLORMAPSIZE;x++) { + mapa[x][CM_RED] = 255; + mapa[x][CM_GREEN] = 255; + mapa[x][CM_BLUE] = 255; + } + + + width=blockPtr->width; + height=blockPtr->height; + pixelo=blockPtr->pixelPtr + blockPtr->offset[0]; + pixelPitch=blockPtr->pitch; + savemap(blockPtr,mapa); + if (num>=MAXCOLORMAPSIZE) { + Tcl_AppendResult(interp, "too many colors", (char *) NULL); + return TCL_ERROR; + } + if (num<2) num=2; + c=LSB(width); + Mputc(c,handle); + c=MSB(width); + Mputc(c,handle); + c=LSB(height); + Mputc(c,handle); + c=MSB(height); + Mputc(c,handle); + + resolution = 0; + while (num >> resolution) { + resolution++; + } + c = 111 + resolution * 17; + Mputc(c,handle); + + num = 1 << resolution; + + /* background color */ + + c = 0; + Mputc(c,handle); + + /* zero for future expansion */ + + Mputc(c,handle); + + for (x=0; x<num ;x++) { + c = mapa[x][CM_RED]; + Mputc(c,handle); + c = mapa[x][CM_GREEN]; + Mputc(c,handle); + c = mapa[x][CM_BLUE]; + Mputc(c,handle); + } + + /* + * Write out extension for transparent colour index, if necessary. + */ + + if (alphaOffset) { + c = GIF_EXTENSION; + Mputc(c, handle); + Tcl_Write(handle, "\371\4\1\0\0\0", 7); + } + + c = GIF_START; + Mputc(c,handle); + c=LSB(top); + Mputc(c,handle); + c=MSB(top); + Mputc(c,handle); + c=LSB(left); + Mputc(c,handle); + c=MSB(left); + Mputc(c,handle); + + c=LSB(width); + Mputc(c,handle); + c=MSB(width); + Mputc(c,handle); + + c=LSB(height); + Mputc(c,handle); + c=MSB(height); + Mputc(c,handle); + + c=0; + Mputc(c,handle); + c=resolution; + Mputc(c,handle); + + ssize = rsize = blockPtr->width; + csize = blockPtr->height; + compress(resolution+1, handle, ReadValue); + + c = 0; + Mputc(c,handle); + c = GIF_TERMINATOR; + Mputc(c,handle); + + return TCL_OK; +} + +static int +color(red, green, blue, mapa) + int red; + int green; + int blue; + unsigned char mapa[MAXCOLORMAPSIZE][3]; +{ + int x; + for (x=(alphaOffset != 0);x<=MAXCOLORMAPSIZE;x++) { + if ((mapa[x][CM_RED]==red) && (mapa[x][CM_GREEN]==green) && + (mapa[x][CM_BLUE]==blue)) { + return x; + } + } + return -1; +} + + +static int +nuevo(red, green, blue, mapa) + int red,green,blue; + unsigned char mapa[MAXCOLORMAPSIZE][3]; +{ + int x; + for (x=(alphaOffset != 0);x<=num;x++) { + if ((mapa[x][CM_RED]==red) && (mapa[x][CM_GREEN]==green) && + (mapa[x][CM_BLUE]==blue)) { + return 0; + } + } + return 1; +} + +static void +savemap(blockPtr,mapa) + Tk_PhotoImageBlock *blockPtr; + unsigned char mapa[MAXCOLORMAPSIZE][3]; +{ + unsigned char *colores; + int x,y; + unsigned char red,green,blue; + + if (alphaOffset) { + num = 0; + mapa[0][CM_RED] = 0xd9; + mapa[0][CM_GREEN] = 0xd9; + mapa[0][CM_BLUE] = 0xd9; + } else { + num = -1; + } + + for(y=0;y<blockPtr->height;y++) { + colores=blockPtr->pixelPtr + blockPtr->offset[0] + + y * blockPtr->pitch; + for(x=0;x<blockPtr->width;x++) { + if (!alphaOffset || (colores[alphaOffset] != 0)) { + red = colores[0]; + green = colores[greenOffset]; + blue = colores[blueOffset]; + if (nuevo(red,green,blue,mapa)) { + num++; + if (num>=MAXCOLORMAPSIZE) { + return; + } + mapa[num][CM_RED]=red; + mapa[num][CM_GREEN]=green; + mapa[num][CM_BLUE]=blue; + } + } + colores += pixelSize; + } + } + return; +} + +static int +ReadValue() +{ + unsigned int col; + + if (csize == 0) { + return EOF; + } + if (alphaOffset && (pixelo[alphaOffset]==0)) { + col = 0; + } else { + col = color(pixelo[0],pixelo[greenOffset],pixelo[blueOffset], mapa); + } + pixelo += pixelSize; + if (--ssize <= 0) { + ssize = rsize; + csize--; + pixelo += pixelPitch - (rsize * pixelSize); + } + + return col; +} + + + +/*----------------------------------------------------------------------- + * + * miGIF Compression - mouse and ivo's GIF-compatible compression + * + * -run length encoding compression routines- + * + * Copyright (C) 1998 Hutchison Avenue Software Corporation + * http://www.hasc.com + * info@hasc.com + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "AS IS." The Hutchison Avenue + * Software Corporation disclaims all warranties, either express or implied, + * including but not limited to implied warranties of merchantability and + * fitness for a particular purpose, with respect to this code and accompanying + * documentation. + * + * The miGIF compression routines do not, strictly speaking, generate files + * conforming to the GIF spec, since the image data is not LZW-compressed + * (this is the point: in order to avoid transgression of the Unisys patent + * on the LZW algorithm.) However, miGIF generates data streams that any + * reasonably sane LZW decompresser will decompress to what we want. + * + * miGIF compression uses run length encoding. It compresses horizontal runs + * of pixels of the same color. This type of compression gives good results + * on images with many runs, for example images with lines, text and solid + * shapes on a solid-colored background. It gives little or no compression + * on images with few runs, for example digital or scanned photos. + * + * der Mouse + * mouse@rodents.montreal.qc.ca + * 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B + * + * ivo@hasc.com + * + * The Graphics Interchange Format(c) is the Copyright property of + * CompuServe Incorporated. GIF(sm) is a Service Mark property of + * CompuServe Incorporated. + * + */ + +static int rl_pixel; +static int rl_basecode; +static int rl_count; +static int rl_table_pixel; +static int rl_table_max; +static int just_cleared; +static int out_bits; +static int out_bits_init; +static int out_count; +static int out_bump; +static int out_bump_init; +static int out_clear; +static int out_clear_init; +static int max_ocodes; +static int code_clear; +static int code_eof; +static unsigned int obuf; +static int obits; +static Tcl_Channel ofile; +static unsigned char oblock[256]; +static int oblen; + +/* Used only when debugging GIF compression code */ +/* #define DEBUGGING_ENVARS */ + +#ifdef DEBUGGING_ENVARS + +static int verbose_set = 0; +static int verbose; +#define VERBOSE (verbose_set?verbose:set_verbose()) + +static int set_verbose(void) +{ + verbose = !!getenv("GIF_VERBOSE"); + verbose_set = 1; + return(verbose); +} + +#else + +#define VERBOSE 0 + +#endif + + +static CONST char * +binformat(v, nbits) + unsigned int v; + int nbits; +{ + static char bufs[8][64]; + static int bhand = 0; + unsigned int bit; + int bno; + char *bp; + + bhand --; + if (bhand < 0) bhand = (sizeof(bufs)/sizeof(bufs[0]))-1; + bp = &bufs[bhand][0]; + for (bno=nbits-1,bit=((unsigned int)1)<<bno;bno>=0;bno--,bit>>=1) + { *bp++ = (v & bit) ? '1' : '0'; + if (((bno&3) == 0) && (bno != 0)) *bp++ = '.'; + } + *bp = '\0'; + return(&bufs[bhand][0]); +} + +static void write_block() +{ + int i; + unsigned char c; + + if (VERBOSE) + { printf("write_block %d:",oblen); + for (i=0;i<oblen;i++) printf(" %02x",oblock[i]); + printf("\n"); + } + c = oblen; + Tcl_Write(ofile, (char *) &c, 1); + Tcl_Write(ofile, (char *) &oblock[0], oblen); + oblen = 0; +} + +static void +block_out(c) + unsigned char c; +{ + if (VERBOSE) printf("block_out %s\n",binformat(c,8)); + oblock[oblen++] = c; + if (oblen >= 255) write_block(); +} + +static void block_flush() +{ + if (VERBOSE) printf("block_flush\n"); + if (oblen > 0) write_block(); +} + +static void output(val) + int val; +{ + if (VERBOSE) printf("output %s [%s %d %d]\n",binformat(val,out_bits),binformat(obuf,obits),obits,out_bits); + obuf |= val << obits; + obits += out_bits; + while (obits >= 8) + { block_out(obuf&0xff); + obuf >>= 8; + obits -= 8; + } + if (VERBOSE) printf("output leaving [%s %d]\n",binformat(obuf,obits),obits); +} + +static void output_flush() +{ + if (VERBOSE) printf("output_flush\n"); + if (obits > 0) block_out(obuf); + block_flush(); +} + +static void did_clear() +{ + if (VERBOSE) printf("did_clear\n"); + out_bits = out_bits_init; + out_bump = out_bump_init; + out_clear = out_clear_init; + out_count = 0; + rl_table_max = 0; + just_cleared = 1; +} + +static void +output_plain(c) + int c; +{ + if (VERBOSE) printf("output_plain %s\n",binformat(c,out_bits)); + just_cleared = 0; + output(c); + out_count ++; + if (out_count >= out_bump) + { out_bits ++; + out_bump += 1 << (out_bits - 1); + } + if (out_count >= out_clear) + { output(code_clear); + did_clear(); + } +} + +static unsigned int isqrt(x) + unsigned int x; +{ + unsigned int r; + unsigned int v; + + if (x < 2) return(x); + for (v=x,r=1;v;v>>=2,r<<=1) ; + while (1) + { v = ((x / r) + r) / 2; + if ((v == r) || (v == r+1)) return(r); + r = v; + } +} + +static unsigned int +compute_triangle_count(count, nrepcodes) + unsigned int count; + unsigned int nrepcodes; +{ + unsigned int perrep; + unsigned int cost; + + cost = 0; + perrep = (nrepcodes * (nrepcodes+1)) / 2; + while (count >= perrep) + { cost += nrepcodes; + count -= perrep; + } + if (count > 0) + { unsigned int n; + n = isqrt(count); + while ((n*(n+1)) >= 2*count) n --; + while ((n*(n+1)) < 2*count) n ++; + cost += n; + } + return(cost); +} + +static void max_out_clear() +{ + out_clear = max_ocodes; +} + +static void reset_out_clear() +{ + out_clear = out_clear_init; + if (out_count >= out_clear) + { output(code_clear); + did_clear(); + } +} + +static void +rl_flush_fromclear(count) + int count; +{ + int n; + + if (VERBOSE) printf("rl_flush_fromclear %d\n",count); + max_out_clear(); + rl_table_pixel = rl_pixel; + n = 1; + while (count > 0) + { if (n == 1) + { rl_table_max = 1; + output_plain(rl_pixel); + count --; + } + else if (count >= n) + { rl_table_max = n; + output_plain(rl_basecode+n-2); + count -= n; + } + else if (count == 1) + { rl_table_max ++; + output_plain(rl_pixel); + count = 0; + } + else + { rl_table_max ++; + output_plain(rl_basecode+count-2); + count = 0; + } + if (out_count == 0) n = 1; else n ++; + } + reset_out_clear(); + if (VERBOSE) printf("rl_flush_fromclear leaving table_max=%d\n",rl_table_max); +} + +static void rl_flush_clearorrep(count) + int count; +{ + int withclr; + + if (VERBOSE) printf("rl_flush_clearorrep %d\n",count); + withclr = 1 + compute_triangle_count(count,max_ocodes); + if (withclr < count) + { output(code_clear); + did_clear(); + rl_flush_fromclear(count); + } + else + { for (;count>0;count--) output_plain(rl_pixel); + } +} + +static void rl_flush_withtable(count) + int count; +{ + int repmax; + int repleft; + int leftover; + + if (VERBOSE) printf("rl_flush_withtable %d\n",count); + repmax = count / rl_table_max; + leftover = count % rl_table_max; + repleft = (leftover ? 1 : 0); + if (out_count+repmax+repleft > max_ocodes) + { repmax = max_ocodes - out_count; + leftover = count - (repmax * rl_table_max); + repleft = 1 + compute_triangle_count(leftover,max_ocodes); + } + if (VERBOSE) printf("rl_flush_withtable repmax=%d leftover=%d repleft=%d\n",repmax,leftover,repleft); + if (1+(int)compute_triangle_count(count,max_ocodes) < repmax+repleft) + { output(code_clear); + did_clear(); + rl_flush_fromclear(count); + return; + } + max_out_clear(); + for (;repmax>0;repmax--) output_plain(rl_basecode+rl_table_max-2); + if (leftover) + { if (just_cleared) + { rl_flush_fromclear(leftover); + } + else if (leftover == 1) + { output_plain(rl_pixel); + } + else + { output_plain(rl_basecode+leftover-2); + } + } + reset_out_clear(); +} + +static void rl_flush() +{ + if (VERBOSE) printf("rl_flush [ %d %d\n",rl_count,rl_pixel); + if (rl_count == 1) + { output_plain(rl_pixel); + rl_count = 0; + if (VERBOSE) printf("rl_flush ]\n"); + return; + } + if (just_cleared) + { rl_flush_fromclear(rl_count); + } + else if ((rl_table_max < 2) || (rl_table_pixel != rl_pixel)) + { rl_flush_clearorrep(rl_count); + } + else + { rl_flush_withtable(rl_count); + } + if (VERBOSE) printf("rl_flush ]\n"); + rl_count = 0; +} + + +static void compress( init_bits, handle, readValue ) + int init_bits; + Tcl_Channel handle; + ifunptr readValue; +{ + int c; + + ofile = handle; + obuf = 0; + obits = 0; + oblen = 0; + code_clear = 1 << (init_bits - 1); + code_eof = code_clear + 1; + rl_basecode = code_eof + 1; + out_bump_init = (1 << (init_bits - 1)) - 1; + /* for images with a lot of runs, making out_clear_init larger will + give better compression. */ + out_clear_init = (init_bits <= 3) ? 9 : (out_bump_init-1); +#ifdef DEBUGGING_ENVARS + { const char *ocienv; + ocienv = getenv("GIF_OUT_CLEAR_INIT"); + if (ocienv) + { out_clear_init = atoi(ocienv); + if (VERBOSE) printf("[overriding out_clear_init to %d]\n",out_clear_init); + } + } +#endif + out_bits_init = init_bits; + max_ocodes = (1 << GIFBITS) - ((1 << (out_bits_init - 1)) + 3); + did_clear(); + output(code_clear); + rl_count = 0; + while (1) + { c = readValue(); + if ((rl_count > 0) && (c != rl_pixel)) rl_flush(); + if (c == EOF) break; + if (rl_pixel == c) + { rl_count ++; + } + else + { rl_pixel = c; + rl_count = 1; + } + } + output(code_eof); + output_flush(); +} + +/*----------------------------------------------------------------------- + * + * End of miGIF section - See copyright notice at start of section. + * + *-----------------------------------------------------------------------*/ + + diff --git a/tk/generic/tkImgPPM.c b/tk/generic/tkImgPPM.c index 02309eb6588..8e5d17aee2b 100644 --- a/tk/generic/tkImgPPM.c +++ b/tk/generic/tkImgPPM.c @@ -16,6 +16,8 @@ * RCS: @(#) $Id$ */ +#define USE_OLD_IMAGE + #include "tkInt.h" #include "tkPort.h" @@ -110,7 +112,7 @@ FileMatchPPM(chan, fileName, formatString, widthPtr, heightPtr) * * Results: * A standard TCL completion code. If TCL_ERROR is returned - * then an error message is left in interp->result. + * then an error message is left in the interp's result. * * Side effects: * The access position in file f is changed, and new data is @@ -151,7 +153,7 @@ FileReadPPM(interp, chan, fileName, formatString, imageHandle, destX, destY, return TCL_ERROR; } if ((maxIntensity <= 0) || (maxIntensity >= 256)) { - char buffer[30]; + char buffer[TCL_INTEGER_SPACE]; sprintf(buffer, "%d", maxIntensity); Tcl_AppendResult(interp, "PPM image file \"", fileName, @@ -183,6 +185,7 @@ FileReadPPM(interp, chan, fileName, formatString, imageHandle, destX, destY, block.offset[1] = 1; block.offset[2] = 2; } + block.offset[3] = 0; block.width = width; block.pitch = block.pixelSize * fileWidth; @@ -243,7 +246,7 @@ FileReadPPM(interp, chan, fileName, formatString, imageHandle, destX, destY, * * Results: * A standard TCL completion code. If TCL_ERROR is returned - * then an error message is left in interp->result. + * then an error message is left in the interp's result. * * Side effects: * Data is written to the file given by "fileName". @@ -262,13 +265,22 @@ FileWritePPM(interp, fileName, formatString, blockPtr) int w, h; int greenOffset, blueOffset, nBytes; unsigned char *pixelPtr, *pixLinePtr; - char header[30]; + char header[16 + TCL_INTEGER_SPACE * 2]; chan = Tcl_OpenFileChannel(interp, fileName, "w", 0666); if (chan == NULL) { return TCL_ERROR; } + if (Tcl_SetChannelOption(interp, chan, "-translation", "binary") + != TCL_OK) { + return TCL_ERROR; + } + if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary") + != TCL_OK) { + return TCL_ERROR; + } + sprintf(header, "P6\n%d %d\n255\n", blockPtr->width, blockPtr->height); Tcl_Write(chan, header, -1); @@ -343,7 +355,7 @@ ReadPPMFileHeader(chan, widthPtr, heightPtr, maxIntensityPtr) { #define BUFFER_SIZE 1000 char buffer[BUFFER_SIZE]; - int i, numFields, firstInLine; + int i, numFields; int type = 0; char c; @@ -355,7 +367,6 @@ ReadPPMFileHeader(chan, widthPtr, heightPtr, maxIntensityPtr) if (Tcl_Read(chan, &c, 1) != 1) { return 0; } - firstInLine = 1; i = 0; for (numFields = 0; numFields < 4; numFields++) { /* @@ -364,7 +375,6 @@ ReadPPMFileHeader(chan, widthPtr, heightPtr, maxIntensityPtr) while (1) { while (isspace(UCHAR(c))) { - firstInLine = (c == '\n'); if (Tcl_Read(chan, &c, 1) != 1) { return 0; } @@ -377,7 +387,6 @@ ReadPPMFileHeader(chan, widthPtr, heightPtr, maxIntensityPtr) return 0; } } while (c != '\n'); - firstInLine = 1; } /* @@ -397,7 +406,6 @@ ReadPPMFileHeader(chan, widthPtr, heightPtr, maxIntensityPtr) buffer[i] = ' '; i++; } - firstInLine = 0; } done: buffer[i] = 0; @@ -419,3 +427,4 @@ ReadPPMFileHeader(chan, widthPtr, heightPtr, maxIntensityPtr) } return type; } + diff --git a/tk/generic/tkImgPhoto.c b/tk/generic/tkImgPhoto.c index 72fddfe1478..7416771041b 100644 --- a/tk/generic/tkImgPhoto.c +++ b/tk/generic/tkImgPhoto.c @@ -2,7 +2,7 @@ * tkImgPhoto.c -- * * Implements images of type "photo" for Tk. Photo images are - * stored in full color (24 bits per pixel) and displayed using + * stored in full color (32 bits per pixel) and displayed using * dithering if necessary. * * Copyright (c) 1994 The Australian National University. @@ -11,6 +11,10 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * + * Author: Paul Mackerras (paulus@cs.anu.edu.au), + * Department of Computer Science, + * Australian National University. + * * RCS: @(#) $Id$ */ @@ -19,11 +23,15 @@ #include "tclMath.h" #include <ctype.h> +#ifdef __WIN32__ +#include "tkWinInt.h" +#endif + /* * Declaration for internal Xlib function used here: */ -extern _XInitImageFuncPtrs _ANSI_ARGS_((XImage *image)); +extern int _XInitImageFuncPtrs _ANSI_ARGS_((XImage *image)); /* * A signed 8-bit integral type. If chars are unsigned and the compiler @@ -121,6 +129,9 @@ typedef struct ColorTable { * MAP_COLORS: 1 means pixel values should be mapped * through pixelMap. */ +#ifdef COLOR_WINDOW +#undef COLOR_WINDOW +#endif #define BLACK_AND_WHITE 1 #define COLOR_WINDOW 2 @@ -147,8 +158,8 @@ typedef struct PhotoMaster { * instances of this image. */ double gamma; /* Display gamma value to correct for. */ char *fileString; /* Name of file to read into image. */ - Tcl_Obj *dataObj; /* Object to use as contents of image. */ - char *format; /* User-specified format of data in image + Tcl_Obj *dataString; /* Object to use as contents of image. */ + Tcl_Obj *format; /* User-specified format of data in image * file or string value. */ unsigned char *pix24; /* Local storage for 24-bit image. */ int ditherX, ditherY; /* Location of first incorrectly @@ -211,14 +222,14 @@ typedef struct PhotoInstance { struct SubcommandOptions { int options; /* Individual bits indicate which * options were specified - see below. */ - char *name; /* Name specified without an option. */ + Tcl_Obj *name; /* Name specified without an option. */ int fromX, fromY; /* Values specified for -from option. */ int fromX2, fromY2; /* Second coordinate pair for -from option. */ int toX, toY; /* Values specified for -to option. */ int toX2, toY2; /* Second coordinate pair for -to option. */ int zoomX, zoomY; /* Values specified for -zoom option. */ int subsampleX, subsampleY; /* Values specified for -subsample option. */ - char *format; /* Value specified for -format option. */ + Tcl_Obj *format; /* Value specified for -format option. */ XColor *background; /* Value specified for -background option. */ }; @@ -270,7 +281,7 @@ static char *optionNames[] = { */ static int ImgPhotoCreate _ANSI_ARGS_((Tcl_Interp *interp, - char *name, int argc, Tcl_Obj *CONST objv[], + char *name, int objc, Tcl_Obj *CONST objv[], Tk_ImageType *typePtr, Tk_ImageMaster master, ClientData *clientDataPtr)); static ClientData ImgPhotoGet _ANSI_ARGS_((Tk_Window tkwin, @@ -282,6 +293,10 @@ static void ImgPhotoDisplay _ANSI_ARGS_((ClientData clientData, static void ImgPhotoFree _ANSI_ARGS_((ClientData clientData, Display *display)); static void ImgPhotoDelete _ANSI_ARGS_((ClientData clientData)); +static int ImgPhotoPostscript _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, + Tk_PostscriptInfo psInfo, int x, int y, int width, + int height, int prepass)); Tk_ImageType tkPhotoImageType = { "photo", /* name */ @@ -290,9 +305,18 @@ Tk_ImageType tkPhotoImageType = { ImgPhotoDisplay, /* displayProc */ ImgPhotoFree, /* freeProc */ ImgPhotoDelete, /* deleteProc */ + ImgPhotoPostscript, /* postscriptProc */ (Tk_ImageType *) NULL /* nextPtr */ }; +typedef struct ThreadSpecificData { + Tk_PhotoImageFormat *formatList; /* Pointer to the first in the + * list of known photo image formats.*/ + Tk_PhotoImageFormat *oldFormatList; /* Pointer to the first in the + * list of known photo image formats.*/ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; + /* * Default configuration */ @@ -306,8 +330,6 @@ Tk_ImageType tkPhotoImageType = { * Information used for parsing configuration specifications: */ static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_STRING, "-format", (char *) NULL, (char *) NULL, - (char *) NULL, Tk_Offset(PhotoMaster, format), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(PhotoMaster, fileString), TK_CONFIG_NULL_OK}, {TK_CONFIG_DOUBLE, "-gamma", (char *) NULL, (char *) NULL, @@ -332,26 +354,20 @@ static int imgPhotoColorHashInitialized; #define N_COLOR_HASH (sizeof(ColorTableId) / sizeof(int)) /* - * Pointer to the first in the list of known photo image formats. - */ - -static Tk_PhotoImageFormat *formatList = NULL; - -/* * Forward declarations */ static int ImgPhotoCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[])); + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int ParseSubcommandOptions _ANSI_ARGS_(( struct SubcommandOptions *optPtr, Tcl_Interp *interp, int allowedOptions, - int *indexPtr, int argc, char **argv)); + int *indexPtr, int objc, Tcl_Obj *CONST objv[])); static void ImgPhotoCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static int ImgPhotoConfigureMaster _ANSI_ARGS_(( Tcl_Interp *interp, PhotoMaster *masterPtr, - int argc, Tcl_Obj *CONST objv[], int flags)); + int objc, Tcl_Obj *CONST objv[], int flags)); static void ImgPhotoConfigureInstance _ANSI_ARGS_(( PhotoInstance *instancePtr)); static void ImgPhotoSetSize _ANSI_ARGS_((PhotoMaster *masterPtr, @@ -359,7 +375,7 @@ static void ImgPhotoSetSize _ANSI_ARGS_((PhotoMaster *masterPtr, static void ImgPhotoInstanceSetSize _ANSI_ARGS_(( PhotoInstance *instancePtr)); static int ImgStringWrite _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_DString *dataPtr, char *formatString, + Tcl_Obj *formatString, Tk_PhotoImageBlock *blockPtr)); static char * ImgGetPhoto _ANSI_ARGS_((PhotoMaster *masterPtr, Tk_PhotoImageBlock *blockPtr, @@ -376,18 +392,19 @@ static void DisposeInstance _ANSI_ARGS_((ClientData clientData)); static int ReclaimColors _ANSI_ARGS_((ColorTableId *id, int numColors)); static int MatchFileFormat _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_Channel chan, char *fileName, - char *formatString, + Tcl_Channel chan, char *fileName, Tcl_Obj *formatString, Tk_PhotoImageFormat **imageFormatPtr, - int *widthPtr, int *heightPtr)); + int *widthPtr, int *heightPtr, int *oldformat)); static int MatchStringFormat _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_Obj *dataObj, char *formatString, + Tcl_Obj *data, Tcl_Obj *formatString, Tk_PhotoImageFormat **imageFormatPtr, - int *widthPtr, int *heightPtr)); -static void Dither _ANSI_ARGS_((PhotoMaster *masterPtr, - int x, int y, int width, int height)); + int *widthPtr, int *heightPtr, int *oldformat)); +static Tcl_ObjCmdProc * PhotoOptionFind _ANSI_ARGS_((Tcl_Interp * interp, + Tcl_Obj *obj)); static void DitherInstance _ANSI_ARGS_((PhotoInstance *instancePtr, int x, int y, int width, int height)); +static void PhotoOptionCleanupProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp)); #undef MIN #define MIN(a, b) ((a) < (b)? (a): (b)) @@ -397,7 +414,7 @@ static void DitherInstance _ANSI_ARGS_((PhotoInstance *instancePtr, /* *---------------------------------------------------------------------- * - * Tk_CreatePhotoImageFormat -- + * Tk_CreateOldPhotoImageFormat, Tk_CreatePhotoImageFormat -- * * This procedure is invoked by an image file handler to register * a new photo image format and the procedures that handle the @@ -413,6 +430,25 @@ static void DitherInstance _ANSI_ARGS_((PhotoInstance *instancePtr, * *---------------------------------------------------------------------- */ +void +Tk_CreateOldPhotoImageFormat(formatPtr) + Tk_PhotoImageFormat *formatPtr; + /* Structure describing the format. All of + * the fields except "nextPtr" must be filled + * in by caller. Must not have been passed + * to Tk_CreatePhotoImageFormat previously. */ +{ + Tk_PhotoImageFormat *copyPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat)); + *copyPtr = *formatPtr; + copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1)); + strcpy(copyPtr->name, formatPtr->name); + copyPtr->nextPtr = tsdPtr->oldFormatList; + tsdPtr->oldFormatList = copyPtr; +} void Tk_CreatePhotoImageFormat(formatPtr) @@ -423,13 +459,20 @@ Tk_CreatePhotoImageFormat(formatPtr) * to Tk_CreatePhotoImageFormat previously. */ { Tk_PhotoImageFormat *copyPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat)); *copyPtr = *formatPtr; copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1)); strcpy(copyPtr->name, formatPtr->name); - copyPtr->nextPtr = formatList; - formatList = copyPtr; + if (isupper((unsigned char) *formatPtr->name)) { + copyPtr->nextPtr = tsdPtr->oldFormatList; + tsdPtr->oldFormatList = copyPtr; + } else { + copyPtr->nextPtr = tsdPtr->formatList; + tsdPtr->formatList = copyPtr; + } } /* @@ -451,11 +494,11 @@ Tk_CreatePhotoImageFormat(formatPtr) */ static int -ImgPhotoCreate(interp, name, argc, objv, typePtr, master, clientDataPtr) +ImgPhotoCreate(interp, name, objc, objv, typePtr, master, clientDataPtr) Tcl_Interp *interp; /* Interpreter for application containing * image. */ char *name; /* Name to use for image. */ - int argc; /* Number of arguments. */ + int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects for options (doesn't * include image name or type). */ Tk_ImageType *typePtr; /* Pointer to our type record (not used). */ @@ -485,7 +528,7 @@ ImgPhotoCreate(interp, name, argc, objv, typePtr, master, clientDataPtr) * Process configuration options given in the image create command. */ - if (ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, 0) != TCL_OK) { + if (ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, 0) != TCL_OK) { ImgPhotoDelete((ClientData) masterPtr); return TCL_ERROR; } @@ -513,14 +556,24 @@ ImgPhotoCreate(interp, name, argc, objv, typePtr, master, clientDataPtr) */ static int -ImgPhotoCmd(clientData, interp, argc, objv) +ImgPhotoCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about photo master. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ + int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { + int oldformat = 0; + static char *photoOptions[] = { + "blank", "cget", "configure", "copy", "data", "get", "put", + "read", "redither", "write", (char *) NULL + }; + enum options { + PHOTO_BLANK, PHOTO_CGET, PHOTO_CONFIGURE, PHOTO_COPY, PHOTO_DATA, + PHOTO_GET, PHOTO_PUT, PHOTO_READ, PHOTO_REDITHER, PHOTO_WRITE + }; + PhotoMaster *masterPtr = (PhotoMaster *) clientData; - int c, result, index; + int result, index; int x, y, width, height; int dataWidth, dataHeight; struct SubcommandOptions options; @@ -530,7 +583,6 @@ ImgPhotoCmd(clientData, interp, argc, objv) unsigned char *pixelPtr; Tk_PhotoImageBlock block; Tk_Window tkwin; - char string[16]; XColor color; Tk_PhotoImageFormat *imageFormat; int imageWidth, imageHeight; @@ -538,96 +590,126 @@ ImgPhotoCmd(clientData, interp, argc, objv) Tcl_Channel chan; Tk_PhotoHandle srcHandle; size_t length; - static char **argv = NULL; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option ?arg arg ...?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } - if (argv) { - ckfree((char *) argv); - } - argv = (char **) ckalloc((argc+1) * sizeof(char *)); - argv[argc] = NULL; - for (index = 0; index < argc; index++) { - argv[index] = Tcl_GetStringFromObj(objv[index], (int *) NULL); + if (Tcl_GetIndexFromObj(interp, objv[1], photoOptions, "option", 0, + &index) != TCL_OK) { + Tcl_ObjCmdProc *proc; + proc = PhotoOptionFind(interp, objv[1]); + if (proc == (Tcl_ObjCmdProc *) NULL) { + return TCL_ERROR; + } + return proc(clientData, interp, objc, objv); } - c = argv[1][0]; - length = strlen(argv[1]); - - if ((c == 'b') && (strncmp(argv[1], "blank", length) == 0)) { + switch ((enum options) index) { + case PHOTO_BLANK: { /* * photo blank command - just call Tk_PhotoBlank. */ - if (argc == 2) { + if (objc == 2) { Tk_PhotoBlank(masterPtr); } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " blank\"", (char *) NULL); + Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL); return TCL_ERROR; } - } else if ((c == 'c') && (length >= 2) - && (strncmp(argv[1], "cget", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); + break; + } + case PHOTO_CGET: { + char *arg; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); return TCL_ERROR; } - if (strncmp(argv[2],"-data", length) == 0) { - if (masterPtr->dataObj) { - Tcl_SetObjResult(interp, masterPtr->dataObj); + arg = Tcl_GetStringFromObj(objv[2], (int *) &length); + if (strncmp(arg,"-data", length) == 0) { + if (masterPtr->dataString) { + Tcl_SetObjResult(interp, masterPtr->dataString); + } + return TCL_OK; + } + if (strncmp(arg,"-format", length) == 0) { + if (masterPtr->format) { + Tcl_SetObjResult(interp, masterPtr->format); } return TCL_OK; } Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs, - (char *) masterPtr, argv[2], 0); - } else if ((c == 'c') && (length >= 3) - && (strncmp(argv[1], "configure", length) == 0)) { + (char *) masterPtr, Tcl_GetString(objv[2]), 0); + break; + } + case PHOTO_CONFIGURE: { /* * photo configure command - handle this in the standard way. */ char *opt, *arg; - if (argc == 2) { + if (objc == 2) { + Tcl_Obj *obj, *subobj; result = Tk_ConfigureInfo(interp, Tk_MainWindow(interp), configSpecs, (char *) masterPtr, (char *) NULL, 0); if (result != TCL_OK) { return result; } - opt = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &length); - arg = (char *) ckalloc(length + 1); - strcpy(arg, opt); - Tcl_ResetResult(interp); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "{-data {} {} {} {}} ", arg, (char*) NULL); - ckfree(arg); + obj = Tcl_NewObj(); + subobj = Tcl_NewStringObj("-data {} {} {}", 14); + if (masterPtr->dataString) { + Tcl_ListObjAppendElement(interp, subobj, masterPtr->dataString); + } else { + Tcl_AppendStringsToObj(subobj, " {}", (char *) NULL); + } + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewStringObj("-format {} {} {}", 16); + if (masterPtr->format) { + Tcl_ListObjAppendElement(interp, subobj, masterPtr->format); + } else { + Tcl_AppendStringsToObj(subobj, " {}", (char *) NULL); + } + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_ListObjAppendList(interp, obj, Tcl_GetObjResult(interp)); + Tcl_SetObjResult(interp, obj); return TCL_OK; } - if (argc == 3) { - if (strncmp(argv[2], "-data", length)) { - return Tk_ConfigureInfo(interp, Tk_MainWindow(interp), - configSpecs, (char *) masterPtr, argv[2], 0); - } else { + if (objc == 3) { + char *arg = Tcl_GetStringFromObj(objv[2], (int *) &length); + if (!strncmp(arg, "-data", length)) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "-data {} {} {}", (char *) NULL); + if (masterPtr->dataString) { + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + masterPtr->dataString); + } else { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + " {}", (char *) NULL); + } + return TCL_OK; + } else if (!strncmp(arg, "-format", length)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "-data {} {} {} ", (char *) NULL); - if (masterPtr->dataObj) { + "-format {} {} {}", (char *) NULL); + if (masterPtr->format) { Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), - masterPtr->dataObj); + masterPtr->format); } else { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "{}", (char *) NULL); + " {}", (char *) NULL); } return TCL_OK; + } else { + return Tk_ConfigureInfo(interp, Tk_MainWindow(interp), + configSpecs, (char *) masterPtr, arg, 0); } } - return ImgPhotoConfigureMaster(interp, masterPtr, argc-2, objv+2, + return ImgPhotoConfigureMaster(interp, masterPtr, objc-2, objv+2, TK_CONFIG_ARGV_ONLY); - } else if ((c == 'c') && (length >= 3) - && (strncmp(argv[1], "copy", length) == 0)) { + break; + } + case PHOTO_COPY: { /* * photo copy command - first parse options. */ @@ -639,14 +721,12 @@ ImgPhotoCmd(clientData, interp, argc, objv) options.name = NULL; if (ParseSubcommandOptions(&options, interp, OPT_FROM | OPT_TO | OPT_ZOOM | OPT_SUBSAMPLE | OPT_SHRINK, - &index, argc, argv) != TCL_OK) { + &index, objc, objv) != TCL_OK) { return TCL_ERROR; } - if (options.name == NULL || index < argc) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " copy source-image ?-from x1 y1 x2 y2?", - " ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?", - "\"", (char *) NULL); + if (options.name == NULL || index < objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "source-image ?-from x1 y1 x2 y2? ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?"); return TCL_ERROR; } @@ -655,8 +735,9 @@ ImgPhotoCmd(clientData, interp, argc, objv) * Check the values given for the -from option. */ - if ((srcHandle = Tk_FindPhoto(interp, options.name)) == NULL) { - Tcl_AppendResult(interp, "image \"", argv[2], "\" doesn't", + if ((srcHandle = Tk_FindPhoto(interp, Tcl_GetString(options.name))) == NULL) { + Tcl_AppendResult(interp, "image \"", + Tcl_GetString(options.name), "\" doesn't", " exist or is not a photo image", (char *) NULL); return TCL_ERROR; } @@ -722,8 +803,9 @@ ImgPhotoCmd(clientData, interp, argc, objv) options.toY2 - options.toY, options.zoomX, options.zoomY, options.subsampleX, options.subsampleY); - } else if ((c == 'd') && (strncmp(argv[1], "data", length) == 0)) { - Tcl_DString buffer; + break; + } + case PHOTO_DATA: { char *data; /* @@ -739,13 +821,11 @@ ImgPhotoCmd(clientData, interp, argc, objv) options.fromY = 0; if (ParseSubcommandOptions(&options, interp, OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND, - &index, argc, argv) != TCL_OK) { + &index, objc, objv) != TCL_OK) { return TCL_ERROR; } - if ((options.name != NULL) || (index < argc)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " data ?-format format-name?", - "?-from x1 y1 x2 y2?\"", (char *) NULL); + if ((options.name != NULL) || (index < objc)) { + Tcl_WrongNumArgs(interp, 2, objv, "?options?"); return TCL_ERROR; } if ((options.fromX > masterPtr->width) @@ -771,10 +851,10 @@ ImgPhotoCmd(clientData, interp, argc, objv) */ if (options.options & OPT_FORMAT) { - for (imageFormat = formatList; imageFormat != NULL; + for (imageFormat = tsdPtr->formatList; imageFormat != NULL; imageFormat = imageFormat->nextPtr) { - if ((strncasecmp(options.format, imageFormat->name, - strlen(imageFormat->name)) == 0)) { + if ((strncasecmp(Tcl_GetString(options.format), + imageFormat->name, strlen(imageFormat->name)) == 0)) { if (imageFormat->stringWriteProc != NULL) { stringWriteProc = imageFormat->stringWriteProc; break; @@ -782,7 +862,8 @@ ImgPhotoCmd(clientData, interp, argc, objv) } } if (stringWriteProc == NULL) { - Tcl_AppendResult(interp, "image string format \"", options.format, + Tcl_AppendResult(interp, "image string format \"", + Tcl_GetString(options.format), "\" is not supported", (char *) NULL); return TCL_ERROR; } @@ -796,39 +877,37 @@ ImgPhotoCmd(clientData, interp, argc, objv) */ data = ImgGetPhoto(masterPtr, &block, &options); - Tcl_DStringInit(&buffer); - result = stringWriteProc(interp, &buffer, - options.format, &block); + result = ((int (*) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *formatString, + Tk_PhotoImageBlock *blockPtr, VOID *dummy))) stringWriteProc) + (interp, options.format, &block, (VOID *) NULL); if (options.background) { Tk_FreeColor(options.background); } if (data) { ckfree(data); } - if (result == TCL_OK) { - Tcl_DStringResult(interp, &buffer); - } else { - Tcl_DStringFree(&buffer); - } return result; - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { + break; + } + case PHOTO_GET: { /* * photo get command - first parse and check parameters. */ - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " get x y\"", (char *) NULL); + char string[TCL_INTEGER_SPACE * 3]; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "x y"); return TCL_ERROR; } - if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { + if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) + || (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) { return TCL_ERROR; } if ((x < 0) || (x >= masterPtr->width) || (y < 0) || (y >= masterPtr->height)) { - Tcl_AppendResult(interp, argv[0], " get: ", + Tcl_AppendResult(interp, Tcl_GetString(objv[0]), " get: ", "coordinates out of range", (char *) NULL); return TCL_ERROR; } @@ -841,7 +920,9 @@ ImgPhotoCmd(clientData, interp, argc, objv) sprintf(string, "%d %d %d", pixelPtr[0], pixelPtr[1], pixelPtr[2]); Tcl_AppendResult(interp, string, (char *) NULL); - } else if ((c == 'p') && (strncmp(argv[1], "put", length) == 0)) { + break; + } + case PHOTO_PUT: { /* * photo put command - first parse the options and colors specified. */ @@ -850,19 +931,19 @@ ImgPhotoCmd(clientData, interp, argc, objv) memset((VOID *) &options, 0, sizeof(options)); options.name = NULL; if (ParseSubcommandOptions(&options, interp, OPT_TO|OPT_FORMAT, - &index, argc, argv) != TCL_OK) { + &index, objc, objv) != TCL_OK) { return TCL_ERROR; } - if ((options.name == NULL) || (index < argc)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " put data ?-format format? ?-to x1 y1 x2 y2?\"", - (char *) NULL); + if ((options.name == NULL) || (index < objc)) { + Tcl_WrongNumArgs(interp, 2, objv, "data ?options?"); return TCL_ERROR; } if (MatchStringFormat(interp, options.name ? objv[2]:NULL, options.format, &imageFormat, &imageWidth, - &imageHeight) == TCL_OK) { + &imageHeight, &oldformat) == TCL_OK) { + Tcl_Obj *format; + Tcl_Obj *data; if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) { options.toX2 = options.toX + imageWidth; options.toY2 = options.toY + imageHeight; @@ -873,8 +954,16 @@ ImgPhotoCmd(clientData, interp, argc, objv) if (imageHeight > options.toY2 - options.toY) { imageHeight = options.toY2 - options.toY; } - if ((*imageFormat->stringReadProc)(interp, objv[2], - options.format, (Tk_PhotoHandle) masterPtr, + format = options.format; + data = objv[2]; + if (oldformat) { + if (format) { + format = (Tcl_Obj *) Tcl_GetString(format); + } + data = (Tcl_Obj *) Tcl_GetString(data); + } + if ((*imageFormat->stringReadProc)(interp, data, + format, (Tk_PhotoHandle) masterPtr, 0, 0, imageWidth, imageHeight, options.toX, options.toY) != TCL_OK) { return TCL_ERROR; @@ -886,7 +975,8 @@ ImgPhotoCmd(clientData, interp, argc, objv) return TCL_ERROR; } Tcl_ResetResult(interp); - if (Tcl_SplitList(interp, options.name, &dataHeight, &srcArgv) + if (Tcl_SplitList(interp, Tcl_GetString(options.name), + &dataHeight, &srcArgv) != TCL_OK) { return TCL_ERROR; } @@ -955,30 +1045,31 @@ ImgPhotoCmd(clientData, interp, argc, objv) block.offset[0] = 0; block.offset[1] = 1; block.offset[2] = 2; + block.offset[3] = 0; Tk_PhotoPutBlock((ClientData)masterPtr, &block, options.toX, options.toY, options.toX2 - options.toX, options.toY2 - options.toY); ckfree((char *) block.pixelPtr); - } else if ((c == 'r') && (length >= 3) - && (strncmp(argv[1], "read", length) == 0)) { + break; + } + case PHOTO_READ: { /* * photo read command - first parse the options specified. */ + Tcl_Obj *format; index = 2; memset((VOID *) &options, 0, sizeof(options)); options.name = NULL; options.format = NULL; if (ParseSubcommandOptions(&options, interp, OPT_FORMAT | OPT_FROM | OPT_TO | OPT_SHRINK, - &index, argc, argv) != TCL_OK) { + &index, objc, objv) != TCL_OK) { return TCL_ERROR; } - if ((options.name == NULL) || (index < argc)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " read fileName ?-format format-name?", - " ?-from x1 y1 x2 y2? ?-to x y? ?-shrink?\"", - (char *) NULL); + if ((options.name == NULL) || (index < objc)) { + Tcl_WrongNumArgs(interp, 2, objv, + "fileName ?options?"); return TCL_ERROR; } @@ -996,7 +1087,8 @@ ImgPhotoCmd(clientData, interp, argc, objv) * Open the image file and look for a handler for it. */ - chan = Tcl_OpenFileChannel(interp, options.name, "r", 0); + chan = Tcl_OpenFileChannel(interp, + Tcl_GetString(options.name), "r", 0); if (chan == NULL) { return TCL_ERROR; } @@ -1004,8 +1096,14 @@ ImgPhotoCmd(clientData, interp, argc, objv) != TCL_OK) { return TCL_ERROR; } - if (MatchFileFormat(interp, chan, options.name, options.format, - &imageFormat, &imageWidth, &imageHeight) != TCL_OK) { + if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary") + != TCL_OK) { + return TCL_ERROR; + } + + if (MatchFileFormat(interp, chan, + Tcl_GetString(options.name), options.format, + &imageFormat, &imageWidth, &imageHeight, &oldformat) != TCL_OK) { Tcl_Close(NULL, chan); return TCL_ERROR; } @@ -1044,17 +1142,22 @@ ImgPhotoCmd(clientData, interp, argc, objv) * into the image. */ - result = (*imageFormat->fileReadProc)(interp, chan, options.name, - options.format, (Tk_PhotoHandle) masterPtr, options.toX, + format = options.format; + if (oldformat && format) { + format = (Tcl_Obj *) Tcl_GetString(format); + } + result = (*imageFormat->fileReadProc)(interp, chan, + Tcl_GetString(options.name), + format, (Tk_PhotoHandle) masterPtr, options.toX, options.toY, width, height, options.fromX, options.fromY); if (chan != NULL) { Tcl_Close(NULL, chan); } return result; - } else if ((c == 'r') && (length >= 3) - && (strncmp(argv[1], "redither", length) == 0)) { - - if (argc == 2) { + break; + } + case PHOTO_REDITHER: { + if (objc == 2) { /* * Call Dither if any part of the image is not correctly * dithered at present. @@ -1063,11 +1166,11 @@ ImgPhotoCmd(clientData, interp, argc, objv) x = masterPtr->ditherX; y = masterPtr->ditherY; if (masterPtr->ditherX != 0) { - Dither(masterPtr, x, y, masterPtr->width - x, 1); + Tk_DitherPhoto((Tk_PhotoHandle) masterPtr, x, y, masterPtr->width - x, 1); } if (masterPtr->ditherY < masterPtr->height) { x = 0; - Dither(masterPtr, 0, masterPtr->ditherY, masterPtr->width, + Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, 0, masterPtr->ditherY, masterPtr->width, masterPtr->height - masterPtr->ditherY); } @@ -1082,12 +1185,15 @@ ImgPhotoCmd(clientData, interp, argc, objv) } } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " redither\"", (char *) NULL); + Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL); return TCL_ERROR; } - } else if ((c == 'w') && (strncmp(argv[1], "write", length) == 0)) { + break; + } + case PHOTO_WRITE: { char *data; + Tcl_Obj *format; + /* * Prevent file system access in safe interpreters. */ @@ -1108,13 +1214,11 @@ ImgPhotoCmd(clientData, interp, argc, objv) options.format = NULL; if (ParseSubcommandOptions(&options, interp, OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND, - &index, argc, argv) != TCL_OK) { + &index, objc, objv) != TCL_OK) { return TCL_ERROR; } - if ((options.name == NULL) || (index < argc)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " write fileName ?-format format-name?", - "?-from x1 y1 x2 y2?\"", (char *) NULL); + if ((options.name == NULL) || (index < objc)) { + Tcl_WrongNumArgs(interp, 2, objv, "fileName ?options?"); return TCL_ERROR; } if ((options.fromX > masterPtr->width) @@ -1141,16 +1245,30 @@ ImgPhotoCmd(clientData, interp, argc, objv) */ matched = 0; - for (imageFormat = formatList; imageFormat != NULL; + for (imageFormat = tsdPtr->formatList; imageFormat != NULL; + imageFormat = imageFormat->nextPtr) { + if ((options.format == NULL) + || (strncasecmp(Tcl_GetString(options.format), + imageFormat->name, strlen(imageFormat->name)) == 0)) { + matched = 1; + if (imageFormat->fileWriteProc != NULL) { + break; + } + } + } + if (imageFormat == NULL) { + oldformat = 1; + for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL; imageFormat = imageFormat->nextPtr) { if ((options.format == NULL) - || (strncasecmp(options.format, imageFormat->name, - strlen(imageFormat->name)) == 0)) { + || (strncasecmp(Tcl_GetString(options.format), + imageFormat->name, strlen(imageFormat->name)) == 0)) { matched = 1; if (imageFormat->fileWriteProc != NULL) { break; } } + } } if (imageFormat == NULL) { if (options.format == NULL) { @@ -1158,10 +1276,12 @@ ImgPhotoCmd(clientData, interp, argc, objv) "has file writing capability", (char *) NULL); } else if (!matched) { Tcl_AppendResult(interp, "image file format \"", - options.format, "\" is unknown", (char *) NULL); + Tcl_GetString(options.format), + "\" is unknown", (char *) NULL); } else { Tcl_AppendResult(interp, "image file format \"", - options.format, "\" has no file writing capability", + Tcl_GetString(options.format), + "\" has no file writing capability", (char *) NULL); } return TCL_ERROR; @@ -1173,8 +1293,13 @@ ImgPhotoCmd(clientData, interp, argc, objv) */ data = ImgGetPhoto(masterPtr, &block, &options); - result = (*imageFormat->fileWriteProc)(interp, options.name, - options.format, &block); + format = options.format; + if (oldformat && format) { + format = (Tcl_Obj *) Tcl_GetString(options.format); + } + result = (*imageFormat->fileWriteProc)(interp, + Tcl_GetString(options.name), + format, &block); if (options.background) { Tk_FreeColor(options.background); } @@ -1182,11 +1307,8 @@ ImgPhotoCmd(clientData, interp, argc, objv) ckfree(data); } return result; - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be blank, cget, configure, copy, get, put,", - " read, redither, or write", (char *) NULL); - return TCL_ERROR; + break; + } } return TCL_OK; @@ -1211,7 +1333,7 @@ ImgPhotoCmd(clientData, interp, argc, objv) */ static int -ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv) +ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, objc, objv) struct SubcommandOptions *optPtr; /* Information about the options specified * and the values given is returned here. */ @@ -1219,27 +1341,27 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv) int allowedOptions; /* Indicates which options are valid for * the current command. */ int *optIndexPtr; /* Points to a variable containing the - * current index in argv; this variable is + * current index in objv; this variable is * updated by this procedure. */ - int argc; /* Number of arguments in argv[]. */ - char **argv; /* Arguments to be parsed. */ + int objc; /* Number of arguments in objv[]. */ + Tcl_Obj *CONST objv[]; /* Arguments to be parsed. */ { int index, c, bit, currentBit; - size_t length; + int length; char *option, **listPtr; int values[4]; int numValues, maxValues, argIndex; - for (index = *optIndexPtr; index < argc; *optIndexPtr = ++index) { + for (index = *optIndexPtr; index < objc; *optIndexPtr = ++index) { /* * We can have one value specified without an option; * it goes into optPtr->name. */ - option = argv[index]; + option = Tcl_GetStringFromObj(objv[index], &length); if (option[0] != '-') { if (optPtr->name == NULL) { - optPtr->name = option; + optPtr->name = objv[index]; continue; } break; @@ -1249,13 +1371,12 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv) * Work out which option this is. */ - length = strlen(option); c = option[0]; bit = 0; currentBit = 1; for (listPtr = optionNames; *listPtr != NULL; ++listPtr) { if ((c == *listPtr[0]) - && (strncmp(option, *listPtr, length) == 0)) { + && (strncmp(option, *listPtr, (size_t) length) == 0)) { if (bit != 0) { bit = 0; /* An ambiguous option. */ break; @@ -1271,7 +1392,8 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv) */ if ((allowedOptions & bit) == 0) { - Tcl_AppendResult(interp, "unrecognized option \"", argv[index], + Tcl_AppendResult(interp, "unrecognized option \"", + Tcl_GetString(objv[index]), "\": must be ", (char *)NULL); bit = 1; for (listPtr = optionNames; *listPtr != NULL; ++listPtr) { @@ -1300,10 +1422,10 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv) * The -background option takes a single XColor value. */ - if (index + 1 < argc) { + if (index + 1 < objc) { *optIndexPtr = ++index; optPtr->background = Tk_GetColor(interp, Tk_MainWindow(interp), - Tk_GetUid(argv[index])); + Tk_GetUid(Tcl_GetString(objv[index]))); if (!optPtr->background) { return TCL_ERROR; } @@ -1317,22 +1439,26 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv) * The -format option takes a single string value. */ - if (index + 1 < argc) { + if (index + 1 < objc) { *optIndexPtr = ++index; - optPtr->format = argv[index]; + optPtr->format = objv[index]; } else { Tcl_AppendResult(interp, "the \"-format\" option ", "requires a value", (char *) NULL); return TCL_ERROR; } } else if ((bit != OPT_SHRINK) && (bit != OPT_GRAYSCALE)) { + char *val; maxValues = ((bit == OPT_FROM) || (bit == OPT_TO))? 4: 2; argIndex = index + 1; for (numValues = 0; numValues < maxValues; ++numValues) { - if ((argIndex < argc) && (isdigit(UCHAR(argv[argIndex][0])) - || ((argv[argIndex][0] == '-') - && (isdigit(UCHAR(argv[argIndex][1])))))) { - if (Tcl_GetInt(interp, argv[argIndex], &values[numValues]) + if (argIndex >= objc) { + break; + } + val = Tcl_GetString(objv[argIndex]); + if ((argIndex < objc) && (isdigit(UCHAR(val[0])) + || ((val[0] == '-') && isdigit(UCHAR(val[1]))))) { + if (Tcl_GetInt(interp, val, &values[numValues]) != TCL_OK) { return TCL_ERROR; } @@ -1343,7 +1469,7 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv) } if (numValues == 0) { - Tcl_AppendResult(interp, "the \"", argv[index], "\" option ", + Tcl_AppendResult(interp, "the \"", option, "\" option ", "requires one ", maxValues == 2? "or two": "to four", " integer values", (char *) NULL); return TCL_ERROR; @@ -1442,7 +1568,7 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv) * * Results: * A standard Tcl return value. If TCL_ERROR is returned then - * an error message is left in masterPtr->interp->result. + * an error message is left in the masterPtr->interp's result. * * Side effects: * Existing instances of the image will be redisplayed to match @@ -1452,38 +1578,48 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv) */ static int -ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags) +ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags) Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ PhotoMaster *masterPtr; /* Pointer to data structure describing * overall photo image to (re)configure. */ - int argc; /* Number of entries in argv. */ + int objc; /* Number of entries in objv. */ Tcl_Obj *CONST objv[]; /* Pairs of configuration options for image. */ int flags; /* Flags to pass to Tk_ConfigureWidget, * such as TK_CONFIG_ARGV_ONLY. */ { PhotoInstance *instancePtr; - char *oldFileString, *oldPaletteString, *oldFormat; - Tcl_Obj *oldDataObj, *dataObj = NULL; + char *oldFileString, *oldPaletteString; + Tcl_Obj *oldData, *data = NULL, *oldFormat, *format = NULL; int length, i, j; double oldGamma; int result; Tcl_Channel chan; Tk_PhotoImageFormat *imageFormat; int imageWidth, imageHeight; - static char **argv = NULL; - - if (argv) ckfree((char *) argv); - argv = (char **) ckalloc((argc + 1) * sizeof(char *)); - for (i = 0, j = 0; i < argc; i++,j++) { - argv[j] = Tcl_GetStringFromObj(objv[i], &length); - if (argv[j][0] == '-' && argv[j][1] == 'd' && - strncmp(argv[j],"-data", length) == 0) { - if (i < argc) { - dataObj = objv[++i]; - j--; + char **args; + int oldformat; + Tcl_Obj *tempdata, *tempformat; + + args = (char **) ckalloc((objc + 1) * sizeof(char *)); + for (i = 0, j = 0; i < objc; i++,j++) { + args[j] = Tcl_GetStringFromObj(objv[i], &length); + if ((length > 1) && (args[j][0] == '-')) { + if ((args[j][1] == 'd') && + !strncmp(args[j],"-data", (size_t) length)) { + if (i < objc) { + data = objv[++i]; + j--; + } + } else if ((args[j][1] == 'f') && + !strncmp(args[j],"-format", (size_t) length)) { + if (i < objc) { + format = objv[++i]; + j--; + } } } } + /* * Save the current values for fileString and dataString, so we * can tell if the user specifies them anew. @@ -1494,7 +1630,7 @@ ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags) */ oldFileString = masterPtr->fileString; - oldDataObj = (oldFileString == NULL) ? masterPtr->dataObj: NULL; + oldData = (oldFileString == NULL) ? masterPtr->dataString: NULL; oldFormat = masterPtr->format; oldPaletteString = masterPtr->palette; oldGamma = masterPtr->gamma; @@ -1504,9 +1640,11 @@ ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags) */ if (Tk_ConfigureWidget(interp, Tk_MainWindow(interp), configSpecs, - j, argv, (char *) masterPtr, flags) != TCL_OK) { + j, args, (char *) masterPtr, flags) != TCL_OK) { + ckfree((char *) args); return TCL_ERROR; } + ckfree((char *) args); /* * Regard the empty string for -file, -data or -format as the null @@ -1517,22 +1655,30 @@ ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags) ckfree(masterPtr->fileString); masterPtr->fileString = NULL; } - if (dataObj) { - if (dataObj->length) { - Tcl_IncrRefCount(dataObj); + if (data) { + if (data->length + || (data->typePtr == Tcl_GetObjType("bytearray") + && data->internalRep.otherValuePtr != NULL)) { + Tcl_IncrRefCount(data); } else { - dataObj = NULL; + data = NULL; } - if (masterPtr->dataObj) { - Tcl_DecrRefCount(masterPtr->dataObj); + if (masterPtr->dataString) { + Tcl_DecrRefCount(masterPtr->dataString); } - masterPtr->dataObj = dataObj; + masterPtr->dataString = data; } - if ((masterPtr->format != NULL) && (masterPtr->format[0] == 0)) { - ckfree(masterPtr->format); - masterPtr->format = NULL; + if (format) { + if (format->length) { + Tcl_IncrRefCount(format); + } else { + format = NULL; + } + if (masterPtr->format) { + Tcl_DecrRefCount(masterPtr->format); + } + masterPtr->format = format; } - /* * Set the image to the user-requested size, if any, * and make sure storage is correctly allocated for this image. @@ -1567,15 +1713,23 @@ ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags) != TCL_OK) { return TCL_ERROR; } + if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary") + != TCL_OK) { + return TCL_ERROR; + } if (MatchFileFormat(interp, chan, masterPtr->fileString, masterPtr->format, &imageFormat, &imageWidth, - &imageHeight) != TCL_OK) { + &imageHeight, &oldformat) != TCL_OK) { Tcl_Close(NULL, chan); return TCL_ERROR; } ImgPhotoSetSize(masterPtr, imageWidth, imageHeight); + tempformat = masterPtr->format; + if (oldformat && tempformat) { + tempformat = (Tcl_Obj *) Tcl_GetString(tempformat); + } result = (*imageFormat->fileReadProc)(interp, chan, - masterPtr->fileString, masterPtr->format, + masterPtr->fileString, tempformat, (Tk_PhotoHandle) masterPtr, 0, 0, imageWidth, imageHeight, 0, 0); Tcl_Close(NULL, chan); @@ -1583,25 +1737,35 @@ ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags) return TCL_ERROR; } + Tcl_ResetResult(interp); masterPtr->flags |= IMAGE_CHANGED; } - if ((masterPtr->fileString == NULL) && (masterPtr->dataObj != NULL) - && ((masterPtr->dataObj != oldDataObj) + if ((masterPtr->fileString == NULL) && (masterPtr->dataString != NULL) + && ((masterPtr->dataString != oldData) || (masterPtr->format != oldFormat))) { - if (MatchStringFormat(interp, masterPtr->dataObj, + if (MatchStringFormat(interp, masterPtr->dataString, masterPtr->format, &imageFormat, &imageWidth, - &imageHeight) != TCL_OK) { + &imageHeight, &oldformat) != TCL_OK) { return TCL_ERROR; } ImgPhotoSetSize(masterPtr, imageWidth, imageHeight); - if ((*imageFormat->stringReadProc)(interp, masterPtr->dataObj, - masterPtr->format, (Tk_PhotoHandle) masterPtr, + tempformat = masterPtr->format; + tempdata = masterPtr->dataString; + if (oldformat) { + if (tempformat) { + tempformat = (Tcl_Obj *) Tcl_GetString(tempformat); + } + tempdata = (Tcl_Obj *) Tcl_GetString(tempdata); + } + if ((*imageFormat->stringReadProc)(interp, tempdata, + tempformat, (Tk_PhotoHandle) masterPtr, 0, 0, imageWidth, imageHeight, 0, 0) != TCL_OK) { return TCL_ERROR; } + Tcl_ResetResult(interp); masterPtr->flags |= IMAGE_CHANGED; } @@ -1814,7 +1978,7 @@ ImgPhotoGet(tkwin, masterData) int mono, nRed, nGreen, nBlue; XVisualInfo visualInfo, *visInfoPtr; XRectangle validBox; - char buf[16]; + char buf[TCL_INTEGER_SPACE * 3]; int numVisuals; XColor *white, *black; XGCValues gcValues; @@ -1955,9 +2119,8 @@ ImgPhotoGet(tkwin, masterData) gcValues.background = (black != NULL)? black->pixel: BlackPixelOfScreen(Tk_Screen(tkwin)); gcValues.graphics_exposures = False; - instancePtr->gc = Tk_GetGCColor(tkwin, - GCForeground|GCBackground|GCGraphicsExposures, &gcValues, - white, black); + instancePtr->gc = Tk_GetGC(tkwin, + GCForeground|GCBackground|GCGraphicsExposures, &gcValues); /* * Set configuration options and finish the initialization of the instance. */ @@ -2133,8 +2296,11 @@ ImgPhotoDelete(masterData) if (masterPtr->validRegion != NULL) { TkDestroyRegion(masterPtr->validRegion); } - if (masterPtr->dataObj != NULL) { - Tcl_DecrRefCount(masterPtr->dataObj); + if (masterPtr->dataString != NULL) { + Tcl_DecrRefCount(masterPtr->dataString); + } + if (masterPtr->format != NULL) { + Tcl_DecrRefCount(masterPtr->format); } Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0); ckfree((char *) masterPtr); @@ -3225,20 +3391,29 @@ DisposeInstance(clientData) */ static int -MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr, - widthPtr, heightPtr) +MatchFileFormat(interp, chan, fileName, formatObj, imageFormatPtr, + widthPtr, heightPtr, oldformat) Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ Tcl_Channel chan; /* The image file, open for reading. */ char *fileName; /* The name of the image file. */ - char *formatString; /* User-specified format string, or NULL. */ + Tcl_Obj *formatObj; /* User-specified format string, or NULL. */ Tk_PhotoImageFormat **imageFormatPtr; /* A pointer to the photo image format * record is returned here. */ int *widthPtr, *heightPtr; /* The dimensions of the image are * returned here. */ + int *oldformat; { int matched; + int useoldformat = 0; Tk_PhotoImageFormat *formatPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + char *formatString = NULL; + + if (formatObj) { + formatString = Tcl_GetString(formatObj); + } /* * Scan through the table of file format handlers to find @@ -3246,11 +3421,11 @@ MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr, */ matched = 0; - for (formatPtr = formatList; formatPtr != NULL; + for (formatPtr = tsdPtr->formatList; formatPtr != NULL; formatPtr = formatPtr->nextPtr) { - if (formatString != NULL) { - if (strncasecmp(formatString, formatPtr->name, - strlen(formatPtr->name)) != 0) { + if (formatObj != NULL) { + if (strncasecmp(formatString, + formatPtr->name, strlen(formatPtr->name)) != 0) { continue; } matched = 1; @@ -3263,8 +3438,8 @@ MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr, if (formatPtr->fileMatchProc != NULL) { (void) Tcl_Seek(chan, 0L, SEEK_SET); - if ((*formatPtr->fileMatchProc)(chan, fileName, formatString, - widthPtr, heightPtr)) { + if ((*formatPtr->fileMatchProc)(chan, fileName, formatObj, + widthPtr, heightPtr, interp)) { if (*widthPtr < 1) { *widthPtr = 1; } @@ -3275,10 +3450,42 @@ MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr, } } } + if (formatPtr == NULL) { + useoldformat = 1; + for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL; + formatPtr = formatPtr->nextPtr) { + if (formatString != NULL) { + if (strncasecmp(formatString, + formatPtr->name, strlen(formatPtr->name)) != 0) { + continue; + } + matched = 1; + if (formatPtr->fileMatchProc == NULL) { + Tcl_AppendResult(interp, "-file option isn't supported for ", + formatString, " images", (char *) NULL); + return TCL_ERROR; + } + } + if (formatPtr->fileMatchProc != NULL) { + (void) Tcl_Seek(chan, 0L, SEEK_SET); + if ((*formatPtr->fileMatchProc)(chan, fileName, (Tcl_Obj *) formatString, + widthPtr, heightPtr, interp)) { + if (*widthPtr < 1) { + *widthPtr = 1; + } + if (*heightPtr < 1) { + *heightPtr = 1; + } + break; + } + } + } + } if (formatPtr == NULL) { - if ((formatString != NULL) && !matched) { - Tcl_AppendResult(interp, "image file format \"", formatString, + if ((formatObj != NULL) && !matched) { + Tcl_AppendResult(interp, "image file format \"", + formatString, "\" is not supported", (char *) NULL); } else { Tcl_AppendResult(interp, @@ -3289,6 +3496,7 @@ MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr, } *imageFormatPtr = formatPtr; + *oldformat = useoldformat; (void) Tcl_Seek(chan, 0L, SEEK_SET); return TCL_OK; } @@ -3316,19 +3524,28 @@ MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr, */ static int -MatchStringFormat(interp, dataObj, formatString, imageFormatPtr, - widthPtr, heightPtr) +MatchStringFormat(interp, data, formatObj, imageFormatPtr, + widthPtr, heightPtr, oldformat) Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ - Tcl_Obj *dataObj; /* Object containing the image data. */ - char *formatString; /* User-specified format string, or NULL. */ + Tcl_Obj *data; /* Object containing the image data. */ + Tcl_Obj *formatObj; /* User-specified format string, or NULL. */ Tk_PhotoImageFormat **imageFormatPtr; /* A pointer to the photo image format * record is returned here. */ int *widthPtr, *heightPtr; /* The dimensions of the image are * returned here. */ + int *oldformat; /* returns 1 if the old image API is used */ { int matched; + int useoldformat = 0; Tk_PhotoImageFormat *formatPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + char *formatString = NULL; + + if (formatObj) { + formatString = Tcl_GetString(formatObj); + } /* * Scan through the table of file format handlers to find @@ -3336,11 +3553,11 @@ MatchStringFormat(interp, dataObj, formatString, imageFormatPtr, */ matched = 0; - for (formatPtr = formatList; formatPtr != NULL; + for (formatPtr = tsdPtr->formatList; formatPtr != NULL; formatPtr = formatPtr->nextPtr) { - if (formatString != NULL) { - if (strncasecmp(formatString, formatPtr->name, - strlen(formatPtr->name)) != 0) { + if (formatObj != NULL) { + if (strncasecmp(formatString, + formatPtr->name, strlen(formatPtr->name)) != 0) { continue; } matched = 1; @@ -3352,15 +3569,41 @@ MatchStringFormat(interp, dataObj, formatString, imageFormatPtr, } if ((formatPtr->stringMatchProc != NULL) && (formatPtr->stringReadProc != NULL) - && (*formatPtr->stringMatchProc)(dataObj, formatString, - widthPtr, heightPtr)) { + && (*formatPtr->stringMatchProc)(data, formatObj, + widthPtr, heightPtr, interp)) { break; } } if (formatPtr == NULL) { - if ((formatString != NULL) && !matched) { - Tcl_AppendResult(interp, "image format \"", formatString, + useoldformat = 1; + for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL; + formatPtr = formatPtr->nextPtr) { + if (formatObj != NULL) { + if (strncasecmp(formatString, + formatPtr->name, strlen(formatPtr->name)) != 0) { + continue; + } + matched = 1; + if (formatPtr->stringMatchProc == NULL) { + Tcl_AppendResult(interp, "-data option isn't supported for ", + formatString, " images", (char *) NULL); + return TCL_ERROR; + } + } + if ((formatPtr->stringMatchProc != NULL) + && (formatPtr->stringReadProc != NULL) + && (*formatPtr->stringMatchProc)((Tcl_Obj *) Tcl_GetString(data), + (Tcl_Obj *) formatString, + widthPtr, heightPtr, interp)) { + break; + } + } + } + if (formatPtr == NULL) { + if ((formatObj != NULL) && !matched) { + Tcl_AppendResult(interp, "image format \"", + formatString, "\" is not supported", (char *) NULL); } else { Tcl_AppendResult(interp, "couldn't recognize image data", @@ -3370,6 +3613,7 @@ MatchStringFormat(interp, dataObj, formatString, imageFormatPtr, } *imageFormatPtr = formatPtr; + *oldformat = useoldformat; return TCL_OK; } @@ -3482,13 +3726,8 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height) greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; - alphaOffset = 0; - while ((alphaOffset != blockPtr->offset[0]) && - (alphaOffset != blockPtr->offset[1]) && - (alphaOffset != blockPtr->offset[2])) { - alphaOffset++; - } - if (alphaOffset >= blockPtr->pixelSize) { + alphaOffset = blockPtr->offset[3]; + if ((alphaOffset >= blockPtr->pixelSize) || (alphaOffset < 0)) { alphaOffset = 0; } else { alphaOffset -= blockPtr->offset[0]; @@ -3505,7 +3744,13 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height) destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4; pitch = masterPtr->width * 4; - if ((blockPtr->pixelSize == 4) && (greenOffset == 1) && (blueOffset == 2) + /* + * This test is probably too restrictive. We should also be able to + * do a memcpy if pixelSize == 3 and alphaOffset == 0. Maybe other cases + * too. + */ + if ((blockPtr->pixelSize == 4) + && (greenOffset == 1) && (blueOffset == 2) && (alphaOffset == 3) && (width <= blockPtr->width) && (height <= blockPtr->height) && ((height == 1) || ((x == 0) && (width == masterPtr->width) && (blockPtr->pitch == pitch)))) { @@ -3524,11 +3769,24 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height) wLeft -= wCopy; srcPtr = srcLinePtr; for (; wCopy > 0; --wCopy) { + if (!destPtr[3]) { + destPtr[0] = destPtr[1] = destPtr[2] = 0xd9; + } + if (!alphaOffset || (srcPtr[alphaOffset] == 255)) { *destPtr++ = srcPtr[0]; *destPtr++ = srcPtr[greenOffset]; *destPtr++ = srcPtr[blueOffset]; - *destPtr++ = alphaOffset ? srcPtr[alphaOffset] : 255; - srcPtr += blockPtr->pixelSize; + *destPtr++ = 255; + } else { + if (srcPtr[alphaOffset]) { + destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255; + destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * srcPtr[alphaOffset] / 255; + destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * srcPtr[alphaOffset] / 255; + destPtr[3] += (255 - destPtr[3]) * srcPtr[alphaOffset] / 255; + } + destPtr+=4; + } + srcPtr += blockPtr->pixelSize; } } srcLinePtr += blockPtr->pitch; @@ -3541,18 +3799,67 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height) * Add this new block to the region which specifies which data is valid. */ + if (alphaOffset) { + int x1, y1, end; + + /* + * This block is grossly inefficient. For each row in the image, it + * finds each continguous string of transparent pixels, then marks those + * areas as invalid in the validRegion mask. This makes drawing very + * efficient, because of the way we use X: we just say, here's your + * mask, and here's your data. We need not worry about the current + * background color, etc. But this costs us a lot on the image setup. + * Still, image setup only happens once, whereas the drawing happens + * many times, so this might be the best way to go. + * + * An alternative might be to not set up this mask, and instead, at + * drawing time, for each transparent pixel, set its color to the + * color of the background behind that pixel. This is what I suspect + * most of programs do. However, they don't have to deal with the canvas, + * which could have many different background colors. Determining the + * correct bg color for a given pixel might be expensive. + */ + + destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4 + 3; + for (y1 = 0; y1 < height; y1++) { + x1 = 0; + destPtr = destLinePtr; + while (x1 < width) { + /* search for first non-transparent pixel */ + while ((x1 < width) && !*destPtr) { + x1++; destPtr += 4; + } + end = x1; + /* search for first transparent pixel */ + while ((end < width) && *destPtr) { + end++; destPtr += 4; + } + if (end > x1) { + rect.x = x + x1; + rect.y = y + y1; + rect.width = end - x1; + rect.height = 1; + TkUnionRectWithRegion(&rect, masterPtr->validRegion, + masterPtr->validRegion); + } + x1 = end; + } + destLinePtr += masterPtr->width * 4; + } + } else { rect.x = x; rect.y = y; rect.width = width; rect.height = height; TkUnionRectWithRegion(&rect, masterPtr->validRegion, masterPtr->validRegion); + } /* * Update each instance. */ - Dither(masterPtr, x, y, width, height); + Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, x, y, width, height); /* * Tell the core image code that this image has changed. @@ -3656,13 +3963,8 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY, greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; - alphaOffset = 0; - while ((alphaOffset != blockPtr->offset[0]) && - (alphaOffset != blockPtr->offset[1]) && - (alphaOffset != blockPtr->offset[2])) { - alphaOffset++; - } - if (alphaOffset >= blockPtr->pixelSize) { + alphaOffset = blockPtr->offset[3]; + if ((alphaOffset >= blockPtr->pixelSize) || (alphaOffset < 0)) { alphaOffset = 0; } else { alphaOffset -= blockPtr->offset[0]; @@ -3718,10 +4020,23 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY, srcPtr = srcLinePtr; for (; wCopy > 0; wCopy -= zoomX) { for (xRepeat = MIN(wCopy, zoomX); xRepeat > 0; xRepeat--) { + if (!destPtr[3]) { + destPtr[0] = destPtr[1] = destPtr[2] = 0xd9; + } + if (!alphaOffset || (srcPtr[alphaOffset] == 255)) { *destPtr++ = srcPtr[0]; *destPtr++ = srcPtr[greenOffset]; *destPtr++ = srcPtr[blueOffset]; - *destPtr++ = alphaOffset ? srcPtr[alphaOffset] : 255; + *destPtr++ = 255; + } else { + if (srcPtr[alphaOffset]) { + destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255; + destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * srcPtr[alphaOffset] / 255; + destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * srcPtr[alphaOffset] / 255; + destPtr[3] += (255 - destPtr[3]) * srcPtr[alphaOffset] / 255; + } + destPtr+=4; + } } srcPtr += blockXSkip; } @@ -3739,18 +4054,49 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY, * Add this new block to the region that specifies which data is valid. */ + if (alphaOffset) { + int x1, y1, end; + + destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4 + 3; + for (y1 = 0; y1 < height; y1++) { + x1 = 0; + destPtr = destLinePtr; + while (x1 < width) { + /* search for first non-transparent pixel */ + while ((x1 < width) && !*destPtr) { + x1++; destPtr += 4; + } + end = x1; + /* search for first transparent pixel */ + while ((end < width) && *destPtr) { + end++; destPtr += 4; + } + if (end > x1) { + rect.x = x + x1; + rect.y = y + y1; + rect.width = end - x1; + rect.height = 1; + TkUnionRectWithRegion(&rect, masterPtr->validRegion, + masterPtr->validRegion); + } + x1 = end; + } + destLinePtr += masterPtr->width * 4; + } + } else { rect.x = x; rect.y = y; rect.width = width; rect.height = height; TkUnionRectWithRegion(&rect, masterPtr->validRegion, masterPtr->validRegion); + } /* * Update each instance. */ - Dither(masterPtr, x, y, width, height); + Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, x, y, width, height); /* * Tell the core image code that this image has changed. @@ -3763,7 +4109,7 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY, /* *---------------------------------------------------------------------- * - * Dither -- + * Tk_DitherPhoto -- * * This procedure is called to update an area of each instance's * pixmap by dithering the corresponding area of the image master. @@ -3779,14 +4125,15 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY, *---------------------------------------------------------------------- */ -static void -Dither(masterPtr, x, y, width, height) - PhotoMaster *masterPtr; /* Image master whose instances are +void +Tk_DitherPhoto(photo, x, y, width, height) + Tk_PhotoHandle photo; /* Image master whose instances are * to be updated. */ int x, y; /* Coordinates of the top-left pixel * in the area to be dithered. */ int width, height; /* Dimensions of the area to be dithered. */ { + PhotoMaster *masterPtr = (PhotoMaster *) photo; PhotoInstance *instancePtr; if ((width <= 0) || (height <= 0)) { @@ -4431,7 +4778,8 @@ ImgGetPhoto(masterPtr, blockPtr, optPtr) if ((greenOffset || blueOffset) && !(optPtr->options & OPT_GRAYSCALE)) { newPixelSize += 2; } - data = ckalloc(newPixelSize * blockPtr->width * blockPtr->height); + data = ckalloc((unsigned int) (newPixelSize * + blockPtr->width * blockPtr->height)); srcPtr = blockPtr->pixelPtr + blockPtr->offset[0]; destPtr = (unsigned char *) data; if (!greenOffset && !blueOffset) { @@ -4546,22 +4894,23 @@ ImgGetPhoto(masterPtr, blockPtr, optPtr) */ static int -ImgStringWrite (interp, dataPtr, formatString, blockPtr) +ImgStringWrite(interp, formatString, blockPtr) Tcl_Interp *interp; - Tcl_DString *dataPtr; - char *formatString; + Tcl_Obj *formatString; Tk_PhotoImageBlock *blockPtr; { int row,col; char *line, *linePtr; unsigned char *pixelPtr; int greenOffset, blueOffset; + Tcl_DString data; greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; + Tcl_DStringInit(&data); if ((blockPtr->width > 0) && (blockPtr->height > 0)) { - line = (char *) ckalloc(8 * blockPtr->width + 2); + line = (char *) ckalloc((unsigned int) ((8 * blockPtr->width) + 2)); for (row=0; row<blockPtr->height; row++) { pixelPtr = blockPtr->pixelPtr + blockPtr->offset[0] + row * blockPtr->pitch; @@ -4572,10 +4921,11 @@ ImgStringWrite (interp, dataPtr, formatString, blockPtr) pixelPtr += blockPtr->pixelSize; linePtr += 8; } - Tcl_DStringAppendElement(dataPtr, line+1); + Tcl_DStringAppendElement(&data, line+1); } ckfree (line); } + Tcl_DStringResult(interp, &data); return TCL_OK; } @@ -4618,5 +4968,189 @@ Tk_PhotoGetImage(handle, blockPtr) blockPtr->offset[0] = 0; blockPtr->offset[1] = 1; blockPtr->offset[2] = 2; + blockPtr->offset[3] = 3; return 1; } + +/* + *---------------------------------------------------------------------- + * + * PhotoOptionFind -- + * + * Finds a specific Photo option. + * + * Results: + * None. + * + * Side effects: + * After commands are removed. + * + *---------------------------------------------------------------------- + */ + +typedef struct OptionAssocData { + struct OptionAssocData *nextPtr; /* pointer to next OptionAssocData */ + Tcl_ObjCmdProc *command; /* command associated with this + * option */ + char name[1]; /* name of option (remaining chars) */ +} OptionAssocData; + +static Tcl_ObjCmdProc * +PhotoOptionFind(interp, obj) + Tcl_Interp *interp; /* Interpreter that is being deleted. */ + Tcl_Obj *obj; /* Name of option to be found. */ +{ + size_t length; + char *name = Tcl_GetStringFromObj(obj, (int *) &length); + OptionAssocData *list; + char *prevname = NULL; + Tcl_ObjCmdProc *proc = (Tcl_ObjCmdProc *) NULL; + list = (OptionAssocData *) Tcl_GetAssocData(interp, "photoOption", + (Tcl_InterpDeleteProc **) NULL); + while (list != (OptionAssocData *) NULL) { + if (strncmp(name, list->name, length) == 0) { + if (proc != (Tcl_ObjCmdProc *) NULL) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "ambiguous option \"", name, + "\": must be ", prevname, (char *) NULL); + while (list->nextPtr != (OptionAssocData *) NULL) { + Tcl_AppendResult(interp, prevname, ", ",(char *) NULL); + list = list->nextPtr; + prevname = list->name; + } + Tcl_AppendResult(interp, ", or", prevname, (char *) NULL); + return (Tcl_ObjCmdProc *) NULL; + } + proc = list->command; + prevname = list->name; + } + list = list->nextPtr; + } + if (proc != (Tcl_ObjCmdProc *) NULL) { + Tcl_ResetResult(interp); + } + return proc; +} + +/* + *---------------------------------------------------------------------- + * + * PhotoOptionCleanupProc -- + * + * This procedure is invoked whenever an interpreter is deleted + * to cleanup the AssocData for "photoVisitor". + * + * Results: + * None. + * + * Side effects: + * Photo Visitor options are removed. + * + *---------------------------------------------------------------------- + */ + +static void +PhotoOptionCleanupProc(clientData, interp) + ClientData clientData; /* Points to "photoVisitor" AssocData + * for the interpreter. */ + Tcl_Interp *interp; /* Interpreter that is being deleted. */ +{ + OptionAssocData *list = (OptionAssocData *) clientData; + OptionAssocData *ptr; + + while (list != NULL) { + list = (ptr = list)->nextPtr; + ckfree((char *) ptr); + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_CreatePhotoOption -- + * + * This procedure may be invoked to add a new kind of photo + * option to the core photo command supported by Tk. + * + * Results: + * None. + * + * Side effects: + * From now on, the new option will be useable by the + * photo command. + * + *-------------------------------------------------------------- + */ + +void +Tk_CreatePhotoOption(interp, name, proc) + Tcl_Interp *interp; /* interpreter */ + CONST char *name; /* option name */ + Tcl_ObjCmdProc *proc; /* proc to execute command */ +{ + OptionAssocData *typePtr2, *prevPtr, *ptr; + OptionAssocData *list; + + list = (OptionAssocData *) Tcl_GetAssocData(interp, "photoOption", + (Tcl_InterpDeleteProc **) NULL); + + /* + * If there's already a photo option with the given name, remove it. + */ + + for (typePtr2 = list, prevPtr = NULL; typePtr2 != NULL; + prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) { + if (strcmp(typePtr2->name, name) == 0) { + if (prevPtr == NULL) { + list = typePtr2->nextPtr; + } else { + prevPtr->nextPtr = typePtr2->nextPtr; + } + ckfree((char *) typePtr2); + break; + } + } + ptr = (OptionAssocData *) ckalloc(sizeof(OptionAssocData) + strlen(name)); + strcpy(&(ptr->name[0]), name); + ptr->command = proc; + ptr->nextPtr = list; + Tcl_SetAssocData(interp, "photoOption", PhotoOptionCleanupProc, + (ClientData) ptr); +} + +/* + *-------------------------------------------------------------- + * + * TkPostscriptPhoto -- + * + * This procedure is called to output the contents of a + * photo image in Postscript by calling the Tk_PostscriptPhoto + * function. + * + * Results: + * Returns a standard Tcl return value. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +static int +ImgPhotoPostscript(clientData, interp, tkwin, psInfo, + x, y, width, height, prepass) + ClientData clientData; + Tcl_Interp *interp; + Tk_Window tkwin; + Tk_PostscriptInfo psInfo; /* postscript info */ + int x, y; /* First pixel to output */ + int width, height; /* Width and height of area */ + int prepass; +{ + Tk_PhotoImageBlock block; + + Tk_PhotoGetImage((Tk_PhotoHandle) clientData, &block); + block.pixelPtr += y * block.pitch + x * block.pixelSize; + + return Tk_PostscriptPhoto(interp, &block, psInfo, width, height); +} + diff --git a/tk/generic/tkImgUtil.c b/tk/generic/tkImgUtil.c index b865c9ca18f..810611ddded 100644 --- a/tk/generic/tkImgUtil.c +++ b/tk/generic/tkImgUtil.c @@ -76,3 +76,4 @@ TkAlignImageData(image, alignment, bitOrder) } return data; } + diff --git a/tk/generic/tkInitScript.h b/tk/generic/tkInitScript.h index 959ebea448d..0ff30077918 100644 --- a/tk/generic/tkInitScript.h +++ b/tk/generic/tkInitScript.h @@ -12,6 +12,8 @@ * RCS: @(#) $Id$ */ + + /* * In order to find tk.tcl during initialization, the following script * is invoked by Tk_Init(). It looks in several different directories: @@ -46,11 +48,12 @@ */ static char initScript[] = "if {[info proc tkInit]==\"\"} {\n\ - proc tkInit {} {\n\ - global tk_library tk_version tk_patchLevel\n\ - rename tkInit {}\n\ - tcl_findLibrary tk $tk_version $tk_patchLevel tk.tcl TK_LIBRARY tk_library\n\ - }\n\ + proc tkInit {} {\n\ + global tk_library tk_version tk_patchLevel\n\ + rename tkInit {}\n\ + tcl_findLibrary tk $tk_version $tk_patchLevel tk.tcl TK_LIBRARY tk_library\n\ +}\n\ }\n\ tkInit"; + diff --git a/tk/generic/tkInt.decls b/tk/generic/tkInt.decls new file mode 100644 index 00000000000..b4d3d470477 --- /dev/null +++ b/tk/generic/tkInt.decls @@ -0,0 +1,1932 @@ + # tkInt.decls -- +# +# This file contains the declarations for all unsupported +# functions that are exported by the Tk library. This file +# is used to generate the tkIntDecls.h, tkIntPlatDecls.h, +# tkIntStub.c, and tkPlatStub.c files. +# +# Copyright (c) 1998-1999 by Scriptics Corporation. +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id$ + +library tk + +# Define the unsupported generic interfaces. + +interface tkInt + +# Declare each of the functions in the unsupported internal Tcl +# interface. These interfaces are allowed to changed between versions. +# Use at your own risk. Note that the position of functions should not +# be changed between versions to avoid gratuitous incompatibilities. + +declare 0 generic { + TkWindow * TkAllocWindow (TkDisplay *dispPtr, int screenNum, \ + TkWindow *parentPtr) +} + +declare 1 generic { + void TkBezierPoints (double control[], int numSteps, double *coordPtr) +} + +declare 2 generic { + void TkBezierScreenPoints (Tk_Canvas canvas, double control[], \ + int numSteps, XPoint *xPointPtr) +} + +declare 3 generic { + void TkBindDeadWindow (TkWindow *winPtr) +} + +declare 4 generic { + void TkBindEventProc (TkWindow *winPtr, XEvent *eventPtr) +} + +declare 5 generic { + void TkBindFree (TkMainInfo *mainPtr) +} + +declare 6 generic { + void TkBindInit (TkMainInfo *mainPtr) +} + +declare 7 generic { + void TkChangeEventWindow (XEvent *eventPtr, TkWindow *winPtr) +} + +declare 8 generic { + int TkClipInit (Tcl_Interp *interp, TkDisplay *dispPtr) +} + +declare 9 generic { + void TkComputeAnchor (Tk_Anchor anchor, Tk_Window tkwin, \ + int padX, int padY, int innerWidth, int innerHeight, \ + int *xPtr, int *yPtr) +} + +declare 10 generic { + int TkCopyAndGlobalEval (Tcl_Interp *interp, char *script) +} + +declare 11 generic { + unsigned long TkCreateBindingProcedure (Tcl_Interp *interp, \ + Tk_BindingTable bindingTable, \ + ClientData object, char *eventString, \ + TkBindEvalProc *evalProc, TkBindFreeProc *freeProc, \ + ClientData clientData) +} + +declare 12 generic { + TkCursor * TkCreateCursorFromData (Tk_Window tkwin, \ + char *source, char *mask, int width, int height, \ + int xHot, int yHot, XColor fg, XColor bg) +} + +declare 13 generic { + int TkCreateFrame (ClientData clientData, \ + Tcl_Interp *interp, int argc, char **argv, \ + int toplevel, char *appName) +} + +declare 14 generic { + Tk_Window TkCreateMainWindow (Tcl_Interp *interp, \ + char *screenName, char *baseName) +} + +declare 15 generic { + Time TkCurrentTime (TkDisplay *dispPtr) +} + +declare 16 generic { + void TkDeleteAllImages (TkMainInfo *mainPtr) +} + +declare 17 generic { + void TkDoConfigureNotify (TkWindow *winPtr) +} + +declare 18 generic { + void TkDrawInsetFocusHighlight (Tk_Window tkwin, GC gc, int width, \ + Drawable drawable, int padding) +} + +declare 19 generic { + void TkEventDeadWindow (TkWindow *winPtr) +} + +declare 20 generic { + void TkFillPolygon (Tk_Canvas canvas, \ + double *coordPtr, int numPoints, Display *display, \ + Drawable drawable, GC gc, GC outlineGC) +} + +declare 21 generic { + int TkFindStateNum (Tcl_Interp *interp, \ + CONST char *option, CONST TkStateMap *mapPtr, \ + CONST char *strKey) +} + +declare 22 generic { + char * TkFindStateString (CONST TkStateMap *mapPtr, int numKey) +} + +declare 23 generic { + void TkFocusDeadWindow (TkWindow *winPtr) +} + +declare 24 generic { + int TkFocusFilterEvent (TkWindow *winPtr, XEvent *eventPtr) +} + +declare 25 generic { + TkWindow * TkFocusKeyEvent (TkWindow *winPtr, XEvent *eventPtr) +} + +declare 26 generic { + void TkFontPkgInit (TkMainInfo *mainPtr) +} + +declare 27 generic { + void TkFontPkgFree (TkMainInfo *mainPtr) +} + +declare 28 generic { + void TkFreeBindingTags (TkWindow *winPtr) +} + +# Name change only, TkFreeCursor in Tcl 8.0.x now TkpFreeCursor +declare 29 generic { + void TkpFreeCursor (TkCursor *cursorPtr) +} + +declare 30 generic { + char * TkGetBitmapData (Tcl_Interp *interp, \ + char *string, char *fileName, int *widthPtr, \ + int *heightPtr, int *hotXPtr, int *hotYPtr) +} + +declare 31 generic { + void TkGetButtPoints (double p1[], double p2[], \ + double width, int project, double m1[], double m2[]) +} + +declare 32 generic { + TkCursor * TkGetCursorByName (Tcl_Interp *interp, \ + Tk_Window tkwin, Tk_Uid string) +} + +declare 33 generic { + char * TkGetDefaultScreenName (Tcl_Interp *interp, char *screenName) +} + +declare 34 generic { + TkDisplay * TkGetDisplay (Display *display) +} + +declare 35 generic { + int TkGetDisplayOf (Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], \ + Tk_Window *tkwinPtr) +} + +declare 36 generic { + TkWindow * TkGetFocusWin (TkWindow *winPtr) +} + +declare 37 generic { + int TkGetInterpNames (Tcl_Interp *interp, Tk_Window tkwin) +} + +declare 38 generic { + int TkGetMiterPoints (double p1[], double p2[], double p3[], \ + double width, double m1[],double m2[]) +} + +declare 39 generic { + void TkGetPointerCoords (Tk_Window tkwin, int *xPtr, int *yPtr) +} + +declare 40 generic { + void TkGetServerInfo (Tcl_Interp *interp, Tk_Window tkwin) +} + +declare 41 generic { + void TkGrabDeadWindow (TkWindow *winPtr) +} + +declare 42 generic { + int TkGrabState (TkWindow *winPtr) +} + +declare 43 generic { + void TkIncludePoint (Tk_Item *itemPtr, double *pointPtr) +} + +declare 44 generic { + void TkInOutEvents (XEvent *eventPtr, TkWindow *sourcePtr, \ + TkWindow *destPtr, int leaveType, int enterType, \ + Tcl_QueuePosition position) +} + +declare 45 generic { + void TkInstallFrameMenu (Tk_Window tkwin) +} + +declare 46 generic { + char * TkKeysymToString (KeySym keysym) +} + +declare 47 generic { + int TkLineToArea (double end1Ptr[], double end2Ptr[], double rectPtr[]) +} + +declare 48 generic { + double TkLineToPoint (double end1Ptr[], \ + double end2Ptr[], double pointPtr[]) +} + +declare 49 generic { + int TkMakeBezierCurve (Tk_Canvas canvas, \ + double *pointPtr, int numPoints, int numSteps, \ + XPoint xPoints[], double dblPoints[]) +} + +declare 50 generic { + void TkMakeBezierPostscript (Tcl_Interp *interp, \ + Tk_Canvas canvas, double *pointPtr, int numPoints) +} + +declare 51 generic { + void TkOptionClassChanged (TkWindow *winPtr) +} + +declare 52 generic { + void TkOptionDeadWindow (TkWindow *winPtr) +} + +declare 53 generic { + int TkOvalToArea (double *ovalPtr, double *rectPtr) +} + +declare 54 generic { + double TkOvalToPoint (double ovalPtr[], \ + double width, int filled, double pointPtr[]) +} + +declare 55 generic { + int TkpChangeFocus (TkWindow *winPtr, int force) +} + +declare 56 generic { + void TkpCloseDisplay (TkDisplay *dispPtr) +} + +declare 57 generic { + void TkpClaimFocus (TkWindow *topLevelPtr, int force) +} + +declare 58 generic { + void TkpDisplayWarning (char *msg, char *title) +} + +declare 59 generic { + void TkpGetAppName (Tcl_Interp *interp, Tcl_DString *name) +} + +declare 60 generic { + TkWindow * TkpGetOtherWindow (TkWindow *winPtr) +} + +declare 61 generic { + TkWindow * TkpGetWrapperWindow (TkWindow *winPtr) +} + +declare 62 generic { + int TkpInit (Tcl_Interp *interp) +} + +declare 63 generic { + void TkpInitializeMenuBindings (Tcl_Interp *interp, \ + Tk_BindingTable bindingTable) +} + +declare 64 generic { + void TkpMakeContainer (Tk_Window tkwin) +} + +declare 65 generic { + void TkpMakeMenuWindow (Tk_Window tkwin, int transient) +} + +declare 66 generic { + Window TkpMakeWindow (TkWindow *winPtr, Window parent) +} + +declare 67 generic { + void TkpMenuNotifyToplevelCreate (Tcl_Interp *interp1, char *menuName) +} + +declare 68 generic { + TkDisplay * TkpOpenDisplay (char *display_name) +} + +declare 69 generic { + int TkPointerEvent (XEvent *eventPtr, TkWindow *winPtr) +} + +declare 70 generic { + int TkPolygonToArea (double *polyPtr, int numPoints, double *rectPtr) +} + +declare 71 generic { + double TkPolygonToPoint (double *polyPtr, int numPoints, double *pointPtr) +} + +declare 72 generic { + int TkPositionInTree (TkWindow *winPtr, TkWindow *treePtr) +} + +declare 73 generic { + void TkpRedirectKeyEvent (TkWindow *winPtr, XEvent *eventPtr) +} + +declare 74 generic { + void TkpSetMainMenubar (Tcl_Interp *interp, \ + Tk_Window tkwin, char *menuName) +} + +declare 75 generic { + int TkpUseWindow (Tcl_Interp *interp, Tk_Window tkwin, char *string) +} + +declare 76 generic { + int TkpWindowWasRecentlyDeleted (Window win, TkDisplay *dispPtr) +} + +declare 77 generic { + void TkQueueEventForAllChildren (TkWindow *winPtr, XEvent *eventPtr) +} + +declare 78 generic { + int TkReadBitmapFile (Display* display, Drawable d, CONST char* filename, \ + unsigned int* width_return, unsigned int* height_return, \ + Pixmap* bitmap_return, int* x_hot_return, int* y_hot_return) +} + +declare 79 generic { + int TkScrollWindow (Tk_Window tkwin, GC gc, \ + int x, int y, int width, int height, int dx, \ + int dy, TkRegion damageRgn) +} + +declare 80 generic { + void TkSelDeadWindow (TkWindow *winPtr) +} + +declare 81 generic { + void TkSelEventProc (Tk_Window tkwin, XEvent *eventPtr) +} + +declare 82 generic { + void TkSelInit (Tk_Window tkwin) +} + +declare 83 generic { + void TkSelPropProc (XEvent *eventPtr) +} + +declare 84 generic { + void TkSetClassProcs (Tk_Window tkwin, \ + TkClassProcs *procs, ClientData instanceData) +} + +declare 85 generic { + void TkSetWindowMenuBar (Tcl_Interp *interp, \ + Tk_Window tkwin, char *oldMenuName, char *menuName) +} + +declare 86 generic { + KeySym TkStringToKeysym (char *name) +} + +declare 87 generic { + int TkThickPolyLineToArea (double *coordPtr, \ + int numPoints, double width, int capStyle, \ + int joinStyle, double *rectPtr) +} + +declare 88 generic { + void TkWmAddToColormapWindows (TkWindow *winPtr) +} + +declare 89 generic { + void TkWmDeadWindow (TkWindow *winPtr) +} + +declare 90 generic { + TkWindow * TkWmFocusToplevel (TkWindow *winPtr) +} + +declare 91 generic { + void TkWmMapWindow (TkWindow *winPtr) +} + +declare 92 generic { + void TkWmNewWindow (TkWindow *winPtr) +} + +declare 93 generic { + void TkWmProtocolEventProc (TkWindow *winPtr, XEvent *evenvPtr) +} + +declare 94 generic { + void TkWmRemoveFromColormapWindows (TkWindow *winPtr) +} + +declare 95 generic { + void TkWmRestackToplevel (TkWindow *winPtr, int aboveBelow, \ + TkWindow *otherPtr) +} + +declare 96 generic { + void TkWmSetClass (TkWindow *winPtr) +} + +declare 97 generic { + void TkWmUnmapWindow (TkWindow *winPtr) +} + +# new for 8.1 + +declare 98 generic { + Tcl_Obj * TkDebugBitmap ( Tk_Window tkwin, char *name) +} + +declare 99 generic { + Tcl_Obj * TkDebugBorder ( Tk_Window tkwin, char *name) +} + +declare 100 generic { + Tcl_Obj * TkDebugCursor ( Tk_Window tkwin, char *name) +} + +declare 101 generic { + Tcl_Obj * TkDebugColor ( Tk_Window tkwin, char *name) +} + +declare 102 generic { + Tcl_Obj * TkDebugConfig (Tcl_Interp *interp, Tk_OptionTable table) +} + +declare 103 generic { + Tcl_Obj * TkDebugFont ( Tk_Window tkwin, char *name) +} + +declare 104 generic { + int TkFindStateNumObj (Tcl_Interp *interp, \ + Tcl_Obj *optionPtr, CONST TkStateMap *mapPtr, \ + Tcl_Obj *keyPtr) +} + +declare 105 generic { + Tcl_HashTable * TkGetBitmapPredefTable (void) +} + +declare 106 generic { + TkDisplay * TkGetDisplayList (void) +} + +declare 107 generic { + TkMainInfo * TkGetMainInfoList (void) +} + +declare 108 generic { + int TkGetWindowFromObj (Tcl_Interp *interp, \ + Tk_Window tkwin, Tcl_Obj *objPtr, \ + Tk_Window *windowPtr) +} + +declare 109 generic { + char * TkpGetString (TkWindow *winPtr, \ + XEvent *eventPtr, Tcl_DString *dsPtr) +} + +declare 110 generic { + void TkpGetSubFonts (Tcl_Interp *interp, Tk_Font tkfont) +} + +declare 111 generic { + Tcl_Obj * TkpGetSystemDefault (Tk_Window tkwin, \ + char *dbName, char *className) +} + +declare 112 generic { + void TkpMenuThreadInit (void) +} + +declare 113 win { + void TkClipBox (TkRegion rgn, XRectangle* rect_return) +} + +declare 113 mac { + void TkClipBox (TkRegion rgn, XRectangle* rect_return) +} + +declare 114 win { + TkRegion TkCreateRegion (void) +} + +declare 114 mac { + TkRegion TkCreateRegion (void) +} + +declare 115 win { + void TkDestroyRegion (TkRegion rgn) +} + +declare 115 mac { + void TkDestroyRegion (TkRegion rgn) +} + +declare 116 win { + void TkIntersectRegion (TkRegion sra, TkRegion srcb, TkRegion dr_return) +} + +declare 116 mac { + void TkIntersectRegion (TkRegion sra, TkRegion srcb, TkRegion dr_return) +} + +declare 117 win { + int TkRectInRegion (TkRegion rgn, int x, int y, unsigned int width, \ + unsigned int height) +} + +declare 117 mac { + int TkRectInRegion (TkRegion rgn, int x, int y, unsigned int width, \ + unsigned int height) +} + +declare 118 win { + void TkSetRegion (Display* display, GC gc, TkRegion rgn) +} + +declare 118 mac { + void TkSetRegion (Display* display, GC gc, TkRegion rgn) +} + +declare 119 win { + void TkUnionRectWithRegion (XRectangle* rect, \ + TkRegion src, TkRegion dr_return) +} + +declare 119 mac { + void TkUnionRectWithRegion (XRectangle* rect, \ + TkRegion src, TkRegion dr_return) +} + +declare 130 mac { + Window TkGetTransientMaster (TkWindow *winPtr) +} + +declare 131 mac { + int TkGenerateButtonEvent (int x, int y, \ + Window window, unsigned int state) +} + +declare 133 mac { + void TkGenWMDestroyEvent (Tk_Window tkwin) +} + +declare 134 mac { + void TkGenWMConfigureEvent (Tk_Window tkwin, int x, int y, \ + int width, int height, int flags) +} + +declare 135 generic { + void TkpDrawHighlightBorder (Tk_Window tkwin, GC fgGC, GC bgGC, \ + int highlightWidth, Drawable drawable) +} + +declare 136 generic { + void TkSetFocusWin (TkWindow *winPtr, int force) +} + +declare 137 generic { + void TkpSetKeycodeAndState (Tk_Window tkwin, KeySym keySym, \ + XEvent *eventPtr) +} + +declare 138 generic { + KeySym TkpGetKeySym (TkDisplay *dispPtr, XEvent *eventPtr) +} + +declare 139 generic { + void TkpInitKeymapInfo (TkDisplay *dispPtr) +} + +############################################################################## + +# Define the platform specific internal Tcl interface. These functions are +# only available on the designated platform. + +interface tkIntPlat + +######################### +# Unix specific functions + +declare 0 unix { + void TkCreateXEventSource (void) +} + +declare 1 unix { + void TkFreeWindowId (TkDisplay *dispPtr, Window w) +} + +declare 2 unix { + void TkInitXId (TkDisplay *dispPtr) +} + +declare 3 unix { + int TkpCmapStressed (Tk_Window tkwin, Colormap colormap) +} + +declare 4 unix { + void TkpSync (Display *display) +} + +declare 5 unix { + Window TkUnixContainerId (TkWindow *winPtr) +} + +declare 6 unix { + int TkUnixDoOneXEvent (Tcl_Time *timePtr) +} + +declare 7 unix { + void TkUnixSetMenubar (Tk_Window tkwin, Tk_Window menubar) +} + + + +############################ +# Windows specific functions + +declare 0 win { + char * TkAlignImageData (XImage *image, int alignment, int bitOrder) +} + +declare 2 win { + void TkGenerateActivateEvents (TkWindow *winPtr, int active) +} + +declare 3 win { + unsigned long TkpGetMS (void) +} + +declare 4 win { + void TkPointerDeadWindow (TkWindow *winPtr) +} + +declare 5 win { + void TkpPrintWindowId (char *buf, Window window) +} + +declare 6 win { + int TkpScanWindowId (Tcl_Interp *interp, char *string, int *idPtr) +} + +declare 7 win { + void TkpSetCapture (TkWindow *winPtr) +} + +declare 8 win { + void TkpSetCursor (TkpCursor cursor) +} + +declare 9 win { + void TkpWmSetState (TkWindow *winPtr, int state) +} + +declare 10 win { + void TkSetPixmapColormap (Pixmap pixmap, Colormap colormap) +} + +declare 11 win { + void TkWinCancelMouseTimer (void) +} + +declare 12 win { + void TkWinClipboardRender (TkDisplay *dispPtr, UINT format) +} + +declare 13 win { + LRESULT TkWinEmbeddedEventProc (HWND hwnd, UINT message, \ + WPARAM wParam, LPARAM lParam) +} + +declare 14 win { + void TkWinFillRect (HDC dc, int x, int y, int width, int height, \ + int pixel) +} + +declare 15 win { + COLORREF TkWinGetBorderPixels (Tk_Window tkwin, Tk_3DBorder border, \ + int which) +} + +declare 16 win { + HDC TkWinGetDrawableDC (Display *display, Drawable d, TkWinDCState* state) +} + +declare 17 win { + int TkWinGetModifierState (void) +} + +declare 18 win { + HPALETTE TkWinGetSystemPalette (void) +} + +declare 19 win { + HWND TkWinGetWrapperWindow (Tk_Window tkwin) +} + +declare 20 win { + int TkWinHandleMenuEvent (HWND *phwnd, \ + UINT *pMessage, WPARAM *pwParam, LPARAM *plParam, \ + LRESULT *plResult) +} + +declare 21 win { + int TkWinIndexOfColor (XColor *colorPtr) +} + +declare 22 win { + void TkWinReleaseDrawableDC (Drawable d, HDC hdc, TkWinDCState* state) +} + +declare 23 win { + LRESULT TkWinResendEvent (WNDPROC wndproc, HWND hwnd, XEvent *eventPtr) +} + +declare 24 win { + HPALETTE TkWinSelectPalette (HDC dc, Colormap colormap) +} + +declare 25 win { + void TkWinSetMenu (Tk_Window tkwin, HMENU hMenu) +} + +declare 26 win { + void TkWinSetWindowPos (HWND hwnd, HWND siblingHwnd, int pos) +} + +declare 27 win { + void TkWinWmCleanup (HINSTANCE hInstance) +} + +declare 28 win { + void TkWinXCleanup (HINSTANCE hInstance) +} + +declare 29 win { + void TkWinXInit (HINSTANCE hInstance) +} + +# new for 8.1 + +declare 30 win { + void TkWinSetForegroundWindow (TkWindow *winPtr) +} + +declare 31 win { + void TkWinDialogDebug (int debug) +} + +declare 32 win { + Tcl_Obj * TkWinGetMenuSystemDefault (Tk_Window tkwin, \ + char *dbName, char *className) +} + +declare 33 win { + int TkWinGetPlatformId(void) +} + +######################## +# Mac specific functions + +declare 0 mac { + void TkGenerateActivateEvents (TkWindow *winPtr, int active) +} + +declare 1 mac { + Pixmap TkpCreateNativeBitmap (Display *display, char * source) +} + +declare 2 mac { + void TkpDefineNativeBitmaps (void) +} + +declare 3 mac { + unsigned long TkpGetMS (void) +} + +declare 4 mac { + Pixmap TkpGetNativeAppBitmap (Display *display, \ + char *name, int *width, int *height) +} + +declare 5 mac { + void TkPointerDeadWindow (TkWindow *winPtr) +} + +declare 6 mac { + void TkpSetCapture (TkWindow *winPtr) +} + +declare 7 mac { + void TkpSetCursor (TkpCursor cursor) +} + +declare 8 mac { + void TkpWmSetState (TkWindow *winPtr, int state) +} + +declare 9 mac { + int HandleWMEvent (EventRecord *theEvent) +} + +declare 10 mac { + void TkAboutDlg (void) +} + +declare 11 mac { + void TkCreateMacEventSource (void) +} + +declare 12 mac { + void TkFontList (Tcl_Interp *interp, Display *display) +} + +declare 13 mac { + Window TkGetTransientMaster (TkWindow *winPtr) +} + +declare 14 mac { + int TkGenerateButtonEvent (int x, int y, \ + Window window, unsigned int state) +} + +declare 15 mac { + int TkGetCharPositions (XFontStruct *font_struct, char *string, \ + int count, short *buffer) +} + +declare 16 mac { + void TkGenWMDestroyEvent (Tk_Window tkwin) +} + +declare 17 mac { + void TkGenWMConfigureEvent (Tk_Window tkwin, int x, int y, \ + int width, int height, int flags) +} + +declare 18 mac { + unsigned int TkMacButtonKeyState (void) +} + +declare 19 mac { + void TkMacClearMenubarActive (void) +} + +declare 20 mac { + int TkMacConvertEvent (EventRecord *eventPtr) +} + +declare 21 mac { + int TkMacDispatchMenuEvent (int menuID, int index) +} + +declare 22 mac { + void TkMacInstallCursor (int resizeOverride) +} + +declare 23 mac { + int TkMacConvertTkEvent (EventRecord *eventPtr, Window window) +} + +declare 24 mac { + void TkMacHandleTearoffMenu (void) +} + +declare 25 mac { + void tkMacInstallMWConsole (Tcl_Interp *interp) +} + +declare 26 mac { + void TkMacInvalClipRgns (TkWindow *winPtr) +} + +declare 27 mac { + void TkMacDoHLEvent (EventRecord *theEvent) +} + +declare 28 mac { + void TkMacFontInfo (Font fontId, short *family, \ + short *style, short *size) +} + +declare 29 mac { + Time TkMacGenerateTime (void) +} + +declare 30 mac { + GWorldPtr TkMacGetDrawablePort (Drawable drawable) +} + +declare 31 mac { + TkWindow * TkMacGetScrollbarGrowWindow (TkWindow *winPtr) +} + +declare 32 mac { + Window TkMacGetXWindow (WindowRef macWinPtr) +} + +declare 33 mac { + int TkMacGrowToplevel (WindowRef whichWindow, Point start) +} + +declare 34 mac { + void TkMacHandleMenuSelect (long mResult, int optionKeyPressed) +} + +declare 35 mac { + int TkMacHaveAppearance (void) +} + +declare 36 mac { + void TkMacInitAppleEvents (Tcl_Interp *interp) +} + +declare 37 mac { + void TkMacInitMenus (Tcl_Interp *interp) +} + +declare 38 mac { + void TkMacInvalidateWindow (MacDrawable *macWin, int flag) +} + +declare 39 mac { + int TkMacIsCharacterMissing (Tk_Font tkfont, unsigned int searchChar) +} + +declare 40 mac { + void TkMacMakeRealWindowExist (TkWindow *winPtr) +} + +declare 41 mac { + BitMapPtr TkMacMakeStippleMap(Drawable d1, Drawable d2) +} + +declare 42 mac { + void TkMacMenuClick (void) +} + +declare 43 mac { + void TkMacRegisterOffScreenWindow (Window window, GWorldPtr portPtr) +} + +declare 44 mac { + int TkMacResizable (TkWindow *winPtr) +} + +declare 45 mac { + void TkMacSetEmbedRgn (TkWindow *winPtr, RgnHandle rgn) +} + +declare 46 mac { + void TkMacSetHelpMenuItemCount (void) +} + +declare 47 mac { + void TkMacSetScrollbarGrow (TkWindow *winPtr, int flag) +} + +declare 48 mac { + void TkMacSetUpClippingRgn (Drawable drawable) +} + +declare 49 mac { + void TkMacSetUpGraphicsPort (GC gc) +} + +declare 50 mac { + void TkMacUpdateClipRgn (TkWindow *winPtr) +} + +declare 51 mac { + void TkMacUnregisterMacWindow (GWorldPtr portPtr) +} + +declare 52 mac { + int TkMacUseMenuID (short macID) +} + +declare 53 mac { + RgnHandle TkMacVisableClipRgn (TkWindow *winPtr) +} + +declare 54 mac { + void TkMacWinBounds (TkWindow *winPtr, Rect *geometry) +} + +declare 55 mac { + void TkMacWindowOffset (WindowRef wRef, int *xOffset, int *yOffset) +} + +declare 56 mac { + void TkResumeClipboard (void) +} + +declare 57 mac { + int TkSetMacColor (unsigned long pixel, RGBColor *macColor) +} + +declare 58 mac { + void TkSetWMName (TkWindow *winPtr, Tk_Uid titleUid) +} + +declare 59 mac { + void TkSuspendClipboard (void) +} + +declare 60 mac { + int TkWMGrowToplevel (WindowRef whichWindow, Point start) +} + +declare 61 mac { + int TkMacZoomToplevel (WindowPtr whichWindow, Point where, short zoomPart) +} + +declare 62 mac { + Tk_Window Tk_TopCoordsToWindow (Tk_Window tkwin, \ + int rootX, int rootY, int *newX, int *newY) +} + +declare 63 mac { + MacDrawable * TkMacContainerId (TkWindow *winPtr) +} + +declare 64 mac { + MacDrawable * TkMacGetHostToplevel (TkWindow *winPtr) +} + + +############################################################################## + +# Define the platform specific internal Xlib interfaces. These functions are +# only available on the designated platform. + +interface tkIntXlib + +# X functions for Windows + +# This slot is reserved for use by the dash patch: +# declare 0 win { +# XSetDashes +# } +declare 1 win { + XModifierKeymap* XGetModifierMapping (Display* d) +} + +declare 2 win { + XImage * XCreateImage (Display* d, Visual* v, unsigned int ui1, int i1, \ + int i2, char* cp, unsigned int ui2, unsigned int ui3, int i3, \ + int i4) + +} + +declare 3 win { + XImage *XGetImage (Display* d, Drawable dr, int i1, int i2, \ + unsigned int ui1, unsigned int ui2, unsigned long ul, int i3) +} + +declare 4 win { + char *XGetAtomName (Display* d,Atom a) + +} + +declare 5 win { + char *XKeysymToString (KeySym k) +} + +declare 6 win { + Colormap XCreateColormap (Display* d, Window w, Visual* v, int i) + +} + +declare 7 win { + Cursor XCreatePixmapCursor (Display* d, Pixmap p1, Pixmap p2, \ + XColor* x1, XColor* x2, \ + unsigned int ui1, unsigned int ui2) +} + +declare 8 win { + Cursor XCreateGlyphCursor (Display* d, Font f1, Font f2, \ + unsigned int ui1, unsigned int ui2, XColor* x1, XColor* x2) +} + +declare 9 win { + GContext XGContextFromGC (GC g) +} + +declare 10 win { + XHostAddress *XListHosts (Display* d, int* i, Bool* b) +} + +# second parameter was of type KeyCode +declare 11 win { + KeySym XKeycodeToKeysym (Display* d, unsigned int k, int i) +} + +declare 12 win { + KeySym XStringToKeysym (_Xconst char* c) +} + +declare 13 win { + Window XRootWindow (Display* d, int i) +} + +declare 14 win { + XErrorHandler XSetErrorHandler (XErrorHandler x) +} + +declare 15 win { + Status XIconifyWindow (Display* d, Window w, int i) +} + +declare 16 win { + Status XWithdrawWindow (Display* d, Window w, int i) +} + +declare 17 win { + Status XGetWMColormapWindows (Display* d, Window w, Window** wpp, int* ip) +} + +declare 18 win { + Status XAllocColor (Display* d, Colormap c, XColor* xp) +} + +declare 19 win { + void XBell (Display* d, int i) +} + +declare 20 win { + void XChangeProperty (Display* d, Window w, Atom a1, Atom a2, int i1, \ + int i2, _Xconst unsigned char* c, int i3) +} + +declare 21 win { + void XChangeWindowAttributes (Display* d, Window w, unsigned long ul, \ + XSetWindowAttributes* x) +} + +declare 22 win { + void XClearWindow (Display* d, Window w) +} + +declare 23 win { + void XConfigureWindow (Display* d, Window w, unsigned int i, \ + XWindowChanges* x) +} + +declare 24 win { + void XCopyArea (Display* d, Drawable dr1, Drawable dr2, GC g, int i1, \ + int i2, unsigned int ui1, \ + unsigned int ui2, int i3, int i4) +} + +declare 25 win { + void XCopyPlane (Display* d, Drawable dr1, Drawable dr2, GC g, int i1, \ + int i2, unsigned int ui1, \ + unsigned int ui2, int i3, int i4, unsigned long ul) +} + +declare 26 win { + Pixmap XCreateBitmapFromData(Display* display, Drawable d, \ + _Xconst char* data, unsigned int width,unsigned int height) +} + +declare 27 win { + void XDefineCursor (Display* d, Window w, Cursor c) +} + +declare 28 win { + void XDeleteProperty (Display* d, Window w, Atom a) +} + +declare 29 win { + void XDestroyWindow (Display* d, Window w) +} + +declare 30 win { + void XDrawArc (Display* d, Drawable dr, GC g, int i1, int i2, \ + unsigned int ui1, unsigned int ui2, int i3, int i4) +} + +declare 31 win { + void XDrawLines (Display* d, Drawable dr, GC g, XPoint* x, int i1, int i2) +} + +declare 32 win { + void XDrawRectangle (Display* d, Drawable dr, GC g, int i1, int i2,\ + unsigned int ui1, unsigned int ui2) +} + +declare 33 win { + void XFillArc (Display* d, Drawable dr, GC g, int i1, int i2, \ + unsigned int ui1, unsigned int ui2, int i3, int i4) +} + +declare 34 win { + void XFillPolygon (Display* d, Drawable dr, GC g, XPoint* x, \ + int i1, int i2, int i3) +} + +declare 35 win { + void XFillRectangles (Display* d, Drawable dr, GC g, XRectangle* x, int i) +} + +declare 36 win { + void XForceScreenSaver (Display* d, int i) +} + +declare 37 win { + void XFreeColormap (Display* d, Colormap c) +} + +declare 38 win { + void XFreeColors (Display* d, Colormap c, \ + unsigned long* ulp, int i, unsigned long ul) +} + +declare 39 win { + void XFreeCursor (Display* d, Cursor c) +} + +declare 40 win { + void XFreeModifiermap (XModifierKeymap* x) +} + +declare 41 win { + Status XGetGeometry (Display* d, Drawable dr, Window* w, int* i1, \ + int* i2, unsigned int* ui1, unsigned int* ui2, unsigned int* ui3, \ + unsigned int* ui4) +} + +declare 42 win { + void XGetInputFocus (Display* d, Window* w, int* i) +} + +declare 43 win { + int XGetWindowProperty (Display* d, Window w, Atom a1, long l1, long l2, \ + Bool b, Atom a2, Atom* ap, int* ip, unsigned long* ulp1, \ + unsigned long* ulp2, unsigned char** cpp) +} + +declare 44 win { + Status XGetWindowAttributes (Display* d, Window w, XWindowAttributes* x) +} + +declare 45 win { + int XGrabKeyboard (Display* d, Window w, Bool b, int i1, int i2, Time t) +} + +declare 46 win { + int XGrabPointer (Display* d, Window w1, Bool b, unsigned int ui, \ + int i1, int i2, Window w2, Cursor c, Time t) +} + +declare 47 win { + KeyCode XKeysymToKeycode (Display* d, KeySym k) +} + +declare 48 win { + Status XLookupColor (Display* d, Colormap c1, _Xconst char* c2, \ + XColor* x1, XColor* x2) +} + +declare 49 win { + void XMapWindow (Display* d, Window w) +} + +declare 50 win { + void XMoveResizeWindow (Display* d, Window w, int i1, int i2, \ + unsigned int ui1, unsigned int ui2) +} + +declare 51 win { + void XMoveWindow (Display* d, Window w, int i1, int i2) +} + +declare 52 win { + void XNextEvent (Display* d, XEvent* x) +} + +declare 53 win { + void XPutBackEvent (Display* d, XEvent* x) +} + +declare 54 win { + void XQueryColors (Display* d, Colormap c, XColor* x, int i) +} + +declare 55 win { + Bool XQueryPointer (Display* d, Window w1, Window* w2, Window* w3, \ + int* i1, int* i2, int* i3, int* i4, unsigned int* ui) +} + +declare 56 win { + Status XQueryTree (Display* d, Window w1, Window* w2, Window* w3, \ + Window** w4, unsigned int* ui) +} + +declare 57 win { + void XRaiseWindow (Display* d, Window w) +} + +declare 58 win { + void XRefreshKeyboardMapping (XMappingEvent* x) +} + +declare 59 win { + void XResizeWindow (Display* d, Window w, unsigned int ui1, \ + unsigned int ui2) +} + +declare 60 win { + void XSelectInput (Display* d, Window w, long l) +} + +declare 61 win { + Status XSendEvent (Display* d, Window w, Bool b, long l, XEvent* x) +} + +declare 62 win { + void XSetCommand (Display* d, Window w, char** c, int i) +} + +declare 63 win { + void XSetIconName (Display* d, Window w, _Xconst char* c) +} + +declare 64 win { + void XSetInputFocus (Display* d, Window w, int i, Time t) +} + +declare 65 win { + void XSetSelectionOwner (Display* d, Atom a, Window w, Time t) +} + +declare 66 win { + void XSetWindowBackground (Display* d, Window w, unsigned long ul) +} + +declare 67 win { + void XSetWindowBackgroundPixmap (Display* d, Window w, Pixmap p) +} + +declare 68 win { + void XSetWindowBorder (Display* d, Window w, unsigned long ul) +} + +declare 69 win { + void XSetWindowBorderPixmap (Display* d, Window w, Pixmap p) +} + +declare 70 win { + void XSetWindowBorderWidth (Display* d, Window w, unsigned int ui) +} + +declare 71 win { + void XSetWindowColormap (Display* d, Window w, Colormap c) +} + +declare 72 win { + Bool XTranslateCoordinates (Display* d, Window w1, Window w2, int i1,\ + int i2, int* i3, int* i4, Window* w3) +} + +declare 73 win { + void XUngrabKeyboard (Display* d, Time t) +} + +declare 74 win { + void XUngrabPointer (Display* d, Time t) +} + +declare 75 win { + void XUnmapWindow (Display* d, Window w) +} + +declare 76 win { + void XWindowEvent (Display* d, Window w, long l, XEvent* x) +} + +declare 77 win { + void XDestroyIC (XIC x) +} + +declare 78 win { + Bool XFilterEvent (XEvent* x, Window w) +} + +declare 79 win { + int XmbLookupString (XIC xi, XKeyPressedEvent* xk, \ + char* c, int i, KeySym* k, Status* s) +} + +declare 80 win { + void TkPutImage (unsigned long *colors, \ + int ncolors, Display* display, Drawable d, \ + GC gc, XImage* image, int src_x, int src_y, \ + int dest_x, int dest_y, unsigned int width, \ + unsigned int height) +} +# This slot is reserved for use by the clipping rectangle patch: +# declare 81 win { +# XSetClipRectangles(Display *display, GC gc, int clip_x_origin, \ +# int clip_y_origin, XRectangle rectangles[], int n, int ordering) +# } + +declare 82 win { + Status XParseColor (Display *display, Colormap map, \ + _Xconst char* spec, XColor *colorPtr) +} + +declare 83 win { + GC XCreateGC(Display* display, Drawable d, \ + unsigned long valuemask, XGCValues* values) +} + +declare 84 win { + void XFreeGC(Display* display, GC gc) +} + +declare 85 win { + Atom XInternAtom(Display* display,_Xconst char* atom_name, \ + Bool only_if_exists) +} + +declare 86 win { + void XSetBackground(Display* display, GC gc, \ + unsigned long foreground) +} + +declare 87 win { + void XSetForeground(Display* display, GC gc, \ + unsigned long foreground) +} + +declare 88 win { + void XSetClipMask(Display* display, GC gc, Pixmap pixmap) +} + +declare 89 win { + void XSetClipOrigin(Display* display, GC gc, \ + int clip_x_origin, int clip_y_origin) +} + +declare 90 win { + void XSetTSOrigin(Display* display, GC gc, \ + int ts_x_origin, int ts_y_origin) +} + +declare 91 win { + void XChangeGC(Display * d, GC gc, unsigned long mask, XGCValues *values) +} + +declare 92 win { + void XSetFont(Display *display, GC gc, Font font) +} + +declare 93 win { + void XSetArcMode(Display *display, GC gc, int arc_mode) +} + +declare 94 win { + void XSetStipple(Display *display, GC gc, Pixmap stipple) +} + +declare 95 win { + void XSetFillRule(Display *display, GC gc, int fill_rule) +} + +declare 96 win { + void XSetFillStyle(Display *display, GC gc, int fill_style) +} + +declare 97 win { + void XSetFunction(Display *display, GC gc, int function) +} + +declare 98 win { + void XSetLineAttributes(Display *display, GC gc, \ + unsigned int line_width, int line_style, \ + int cap_style, int join_style) +} + +declare 99 win { + int _XInitImageFuncPtrs(XImage *image) +} + +declare 100 win { + XIC XCreateIC(void) +} + +declare 101 win { + XVisualInfo *XGetVisualInfo(Display* display, long vinfo_mask, \ + XVisualInfo* vinfo_template, int* nitems_return) +} + +declare 102 win { + void XSetWMClientMachine(Display* display, Window w, XTextProperty* text_prop) +} + +declare 103 win { + Status XStringListToTextProperty(char** list, int count, \ + XTextProperty* text_prop_return) +} + +# X functions for Mac + +# This slot is reserved for use by the dash patch: +# declare 0 win { +# XSetDashes +# } + +declare 1 mac { + XModifierKeymap* XGetModifierMapping (Display* d) +} + +declare 2 mac { + XImage * XCreateImage (Display* d, Visual* v, unsigned int ui1, int i1, \ + int i2, char* cp, unsigned int ui2, unsigned int ui3, int i3, \ + int i4) + +} + +declare 3 mac { + XImage *XGetImage (Display* d, Drawable dr, int i1, int i2, \ + unsigned int ui1, unsigned int ui2, unsigned long ul, int i3) +} + +declare 4 mac { + char *XGetAtomName (Display* d,Atom a) + +} + +declare 5 mac { + char *XKeysymToString (KeySym k) +} + +declare 6 mac { + Colormap XCreateColormap (Display* d, Window w, Visual* v, int i) + +} + +declare 7 mac { + GContext XGContextFromGC (GC g) +} + +declare 8 mac { + KeySym XKeycodeToKeysym (Display* d, KeyCode k, int i) +} + +declare 9 mac { + KeySym XStringToKeysym (_Xconst char* c) +} + +declare 10 mac { + Window XRootWindow (Display* d, int i) +} + +declare 11 mac { + XErrorHandler XSetErrorHandler (XErrorHandler x) +} + +declare 12 mac { + Status XAllocColor (Display* d, Colormap c, XColor* xp) +} + +declare 13 mac { + void XBell (Display* d, int i) +} + +declare 14 mac { + void XChangeProperty (Display* d, Window w, Atom a, Atom a, int i1, \ + int i2, _Xconst unsigned char* c, int i3) +} + +declare 15 mac { + void XChangeWindowAttributes (Display* d, Window w, unsigned long ul, \ + XSetWindowAttributes* x) +} + +declare 16 mac { + void XConfigureWindow (Display* d, Window w, unsigned int i, \ + XWindowChanges* x) +} + +declare 17 mac { + void XCopyArea (Display* d, Drawable dr1, Drawable dr2, GC g, int i1, \ + int i2, unsigned int ui1, \ + unsigned int ui2, int i3, int i4) +} + +declare 18 mac { + void XCopyPlane (Display* d, Drawable dr1, Drawable dr2, GC g, int i1, \ + int i2, unsigned int ui1, \ + unsigned int ui2, int i3, int i4, unsigned long ul) +} + +declare 19 mac { + Pixmap XCreateBitmapFromData(Display* display, Drawable d, \ + _Xconst char* data, unsigned int width,unsigned int height) +} + +declare 20 mac { + void XDefineCursor (Display* d, Window w, Cursor c) +} + +declare 21 mac { + void XDestroyWindow (Display* d, Window w) +} + +declare 22 mac { + void XDrawArc (Display* d, Drawable dr, GC g, int i1, int i2, \ + unsigned int ui1, unsigned int ui2, int i3, int i4) +} + +declare 23 mac { + void XDrawLines (Display* d, Drawable dr, GC g, XPoint* x, int i1, int i2) +} + +declare 24 mac { + void XDrawRectangle (Display* d, Drawable dr, GC g, int i1, int i2,\ + unsigned int ui1, unsigned int ui2) +} + +declare 25 mac { + void XFillArc (Display* d, Drawable dr, GC g, int i1, int i2, \ + unsigned int ui1, unsigned int ui2, int i3, int i4) +} + +declare 26 mac { + void XFillPolygon (Display* d, Drawable dr, GC g, XPoint* x, \ + int i1, int i2, int i3) +} + +declare 27 mac { + void XFillRectangles (Display* d, Drawable dr, GC g, XRectangle* x, int i) +} + +declare 28 mac { + void XFreeColormap (Display* d, Colormap c) +} + +declare 29 mac { + void XFreeColors (Display* d, Colormap c, \ + unsigned long* ulp, int i, unsigned long ul) +} + +declare 30 mac { + void XFreeModifiermap (XModifierKeymap* x) +} + +declare 31 mac { + Status XGetGeometry (Display* d, Drawable dr, Window* w, int* i1, \ + int* i2, unsigned int* ui1, unsigned int* ui2, unsigned int* ui3, \ + unsigned int* ui4) +} + +declare 32 mac { + int XGetWindowProperty (Display* d, Window w, Atom a1, long l1, long l2, \ + Bool b, Atom a2, Atom* ap, int* ip, unsigned long* ulp1, \ + unsigned long* ulp2, unsigned char** cpp) +} + +declare 33 mac { + int XGrabKeyboard (Display* d, Window w, Bool b, int i1, int i2, Time t) +} + +declare 34 mac { + int XGrabPointer (Display* d, Window w1, Bool b, unsigned int ui, \ + int i1, int i2, Window w2, Cursor c, Time t) +} + +declare 35 mac { + KeyCode XKeysymToKeycode (Display* d, KeySym k) +} + +declare 36 mac { + void XMapWindow (Display* d, Window w) +} + +declare 37 mac { + void XMoveResizeWindow (Display* d, Window w, int i1, int i2, \ + unsigned int ui1, unsigned int ui2) +} + +declare 38 mac { + void XMoveWindow (Display* d, Window w, int i1, int i2) +} + +declare 39 mac { + Bool XQueryPointer (Display* d, Window w1, Window* w2, Window* w3, \ + int* i1, int* i2, int* i3, int* i4, unsigned int* ui) +} + +declare 40 mac { + void XRaiseWindow (Display* d, Window w) +} + +declare 41 mac { + void XRefreshKeyboardMapping (XMappingEvent* x) +} + +declare 42 mac { + void XResizeWindow (Display* d, Window w, unsigned int ui1, \ + unsigned int ui2) +} + +declare 43 mac { + void XSelectInput (Display* d, Window w, long l) +} + +declare 44 mac { + Status XSendEvent (Display* d, Window w, Bool b, long l, XEvent* x) +} + +declare 45 mac { + void XSetIconName (Display* d, Window w, _Xconst char* c) +} + +declare 46 mac { + void XSetInputFocus (Display* d, Window w, int i, Time t) +} + +declare 47 mac { + void XSetSelectionOwner (Display* d, Atom a, Window w, Time t) +} + +declare 48 mac { + void XSetWindowBackground (Display* d, Window w, unsigned long ul) +} + +declare 49 mac { + void XSetWindowBackgroundPixmap (Display* d, Window w, Pixmap p) +} + +declare 50 mac { + void XSetWindowBorder (Display* d, Window w, unsigned long ul) +} + +declare 51 mac { + void XSetWindowBorderPixmap (Display* d, Window w, Pixmap p) +} + +declare 52 mac { + void XSetWindowBorderWidth (Display* d, Window w, unsigned int ui) +} + +declare 53 mac { + void XSetWindowColormap (Display* d, Window w, Colormap c) +} + +declare 54 mac { + void XUngrabKeyboard (Display* d, Time t) +} + +declare 55 mac { + void XUngrabPointer (Display* d, Time t) +} + +declare 56 mac { + void XUnmapWindow (Display* d, Window w) +} + +declare 57 mac { + void TkPutImage (unsigned long *colors, \ + int ncolors, Display* display, Drawable d, \ + GC gc, XImage* image, int src_x, int src_y, \ + int dest_x, int dest_y, unsigned int width, \ + unsigned int height) +} +declare 58 mac { + Status XParseColor (Display *display, Colormap map, \ + _Xconst char* spec, XColor *colorPtr) +} + +declare 59 mac { + GC XCreateGC(Display* display, Drawable d, \ + unsigned long valuemask, XGCValues* values) +} + +declare 60 mac { + void XFreeGC(Display* display, GC gc) +} + +declare 61 mac { + Atom XInternAtom(Display* display,_Xconst char* atom_name, \ + Bool only_if_exists) +} + +declare 62 mac { + void XSetBackground(Display* display, GC gc, \ + unsigned long foreground) +} + +declare 63 mac { + void XSetForeground(Display* display, GC gc, \ + unsigned long foreground) +} + +declare 64 mac { + void XSetClipMask(Display* display, GC gc, Pixmap pixmap) +} + +declare 65 mac { + void XSetClipOrigin(Display* display, GC gc, \ + int clip_x_origin, int clip_y_origin) +} + +declare 66 mac { + void XSetTSOrigin(Display* display, GC gc, \ + int ts_x_origin, int ts_y_origin) +} + +declare 67 mac { + void XChangeGC(Display * d, GC gc, unsigned long mask, XGCValues *values) +} + +declare 68 mac { + void XSetFont(Display *display, GC gc, Font font) +} + +declare 69 mac { + void XSetArcMode(Display *display, GC gc, int arc_mode) +} + +declare 70 mac { + void XSetStipple(Display *display, GC gc, Pixmap stipple) +} + +declare 71 mac { + void XSetFillRule(Display *display, GC gc, int fill_rule) +} + +declare 72 mac { + void XSetFillStyle(Display *display, GC gc, int fill_style) +} + +declare 73 mac { + void XSetFunction(Display *display, GC gc, int function) +} + +declare 74 mac { + void XSetLineAttributes(Display *display, GC gc, \ + unsigned int line_width, int line_style, \ + int cap_style, int join_style) +} + +declare 75 mac { + int _XInitImageFuncPtrs(XImage *image) +} + +declare 76 mac { + XIC XCreateIC(void) +} + +declare 77 mac { + XVisualInfo *XGetVisualInfo(Display* display, long vinfo_mask, \ + XVisualInfo* vinfo_template, int* nitems_return) +} + +declare 78 mac { + void XSetWMClientMachine(Display* display, Window w, \ + XTextProperty* text_prop) +} + +declare 79 mac { + Status XStringListToTextProperty(char** list, int count, \ + XTextProperty* text_prop_return) +} +declare 80 mac { + void XDrawSegments(Display *display, Drawable d, GC gc, \ + XSegment *segments, int nsegments) +} +declare 81 mac { + void XForceScreenSaver(Display* display, int mode) +} + diff --git a/tk/generic/tkInt.h b/tk/generic/tkInt.h index 359b6c99150..1164edd4b1c 100644 --- a/tk/generic/tkInt.h +++ b/tk/generic/tkInt.h @@ -27,18 +27,12 @@ #include <tkPort.h> #endif -#ifdef BUILD_tk -# undef TCL_STORAGE_CLASS -# define TCL_STORAGE_CLASS DLLEXPORT -#endif - /* * Opaque type declarations: */ typedef struct TkColormap TkColormap; typedef struct TkGrabEvent TkGrabEvent; -typedef struct Tk_PostscriptInfo Tk_PostscriptInfo; typedef struct TkpCursor_ *TkpCursor; typedef struct TkRegion_ *TkRegion; typedef struct TkStressedCmap TkStressedCmap; @@ -87,16 +81,37 @@ typedef struct TkClassProcs { typedef struct TkCursor { Tk_Cursor cursor; /* System specific identifier for cursor. */ - int refCount; /* Number of active uses of cursor. */ + Display *display; /* Display containing cursor. Needed for + * disposal and retrieval of cursors. */ + int resourceRefCount; /* Number of active uses of this cursor (each + * active use corresponds to a call to + * Tk_AllocPreserveFromObj or Tk_Preserve). + * If this count is 0, then this structure + * is no longer valid and it isn't present + * in a hash table: it is being kept around + * only because there are objects referring + * to it. The structure is freed when + * resourceRefCount and objRefCount are + * both 0. */ + int objRefCount; /* Number of Tcl objects that reference + * this structure.. */ Tcl_HashTable *otherTable; /* Second table (other than idTable) used * to index this entry. */ Tcl_HashEntry *hashPtr; /* Entry in otherTable for this structure * (needed when deleting). */ + Tcl_HashEntry *idHashPtr; /* Entry in idTable for this structure + * (needed when deleting). */ + struct TkCursor *nextPtr; /* Points to the next TkCursor structure with + * the same name. Cursors with the same + * name but different displays are chained + * together off a single hash table entry. */ } TkCursor; /* * One of the following structures is maintained for each display - * containing a window managed by Tk: + * containing a window managed by Tk. In part, the structure is + * used to store thread-specific data, since each thread will have + * its own TkDisplay structure. */ typedef struct TkDisplay { @@ -108,6 +123,23 @@ typedef struct TkDisplay { * display. */ /* + * Information used primarily by tk3d.c: + */ + + int borderInit; /* 0 means borderTable needs initializing. */ + Tcl_HashTable borderTable; /* Maps from color name to TkBorder + * structure. */ + + /* + * Information used by tkAtom.c only: + */ + + int atomInit; /* 0 means stuff below hasn't been + * initialized yet. */ + Tcl_HashTable nameTable; /* Maps from names to Atom's. */ + Tcl_HashTable atomTable; /* Maps from Atom's back to names. */ + + /* * Information used primarily by tkBind.c: */ @@ -133,6 +165,63 @@ typedef struct TkDisplay { * may be NULL. */ /* + * Information used by tkBitmap.c only: + */ + + int bitmapInit; /* 0 means tables above need initializing. */ + int bitmapAutoNumber; /* Used to number bitmaps. */ + Tcl_HashTable bitmapNameTable; + /* Maps from name of bitmap to the first + * TkBitmap record for that name. */ + Tcl_HashTable bitmapIdTable;/* Maps from bitmap id to the TkBitmap + * structure for the bitmap. */ + Tcl_HashTable bitmapDataTable; + /* Used by Tk_GetBitmapFromData to map from + * a collection of in-core data about a + * bitmap to a reference giving an auto- + * matically-generated name for the bitmap. */ + + /* + * Information used by tkCanvas.c only: + */ + + int numIdSearches; + int numSlowSearches; + + /* + * Used by tkColor.c only: + */ + + int colorInit; /* 0 means color module needs initializing. */ + TkStressedCmap *stressPtr; /* First in list of colormaps that have + * filled up, so we have to pick an + * approximate color. */ + Tcl_HashTable colorNameTable; + /* Maps from color name to TkColor structure + * for that color. */ + Tcl_HashTable colorValueTable; + /* Maps from integer RGB values to TkColor + * structures. */ + + /* + * Used by tkCursor.c only: + */ + + int cursorInit; /* 0 means cursor module need initializing. */ + Tcl_HashTable cursorNameTable; + /* Maps from a string name to a cursor to the + * TkCursor record for the cursor. */ + Tcl_HashTable cursorDataTable; + /* Maps from a collection of in-core data + * about a cursor to a TkCursor structure. */ + Tcl_HashTable cursorIdTable; + /* Maps from a cursor id to the TkCursor + * structure for the cursor. */ + char cursorString[20]; /* Used to store a cursor id string. */ + Font cursorFont; /* Font to use for standard cursors. + * None means font not loaded yet. */ + + /* * Information used by tkError.c only: */ @@ -146,68 +235,65 @@ typedef struct TkDisplay { * gets big, handlers get cleaned up. */ /* - * Information used by tkSend.c only: + * Used by tkEvent.c only: */ - Tk_Window commTkwin; /* Window used for communication - * between interpreters during "send" - * commands. NULL means send info hasn't - * been initialized yet. */ - Atom commProperty; /* X's name for comm property. */ - Atom registryProperty; /* X's name for property containing - * registry of interpreter names. */ - Atom appNameProperty; /* X's name for property used to hold the - * application name on each comm window. */ + struct TkWindowEvent *delayedMotionPtr; + /* Points to a malloc-ed motion event + * whose processing has been delayed in + * the hopes that another motion event + * will come along right away and we can + * merge the two of them together. NULL + * means that there is no delayed motion + * event. */ /* - * Information used by tkSelect.c and tkClipboard.c only: + * Information used by tkFocus.c only: */ - struct TkSelectionInfo *selectionInfoPtr; - /* First in list of selection information - * records. Each entry contains information - * about the current owner of a particular - * selection on this display. */ - Atom multipleAtom; /* Atom for MULTIPLE. None means - * selection stuff isn't initialized. */ - Atom incrAtom; /* Atom for INCR. */ - Atom targetsAtom; /* Atom for TARGETS. */ - Atom timestampAtom; /* Atom for TIMESTAMP. */ - Atom textAtom; /* Atom for TEXT. */ - Atom compoundTextAtom; /* Atom for COMPOUND_TEXT. */ - Atom applicationAtom; /* Atom for TK_APPLICATION. */ - Atom windowAtom; /* Atom for TK_WINDOW. */ - Atom clipboardAtom; /* Atom for CLIPBOARD. */ + int focusDebug; /* 1 means collect focus debugging + * statistics. */ + struct TkWindow *implicitWinPtr; + /* If the focus arrived at a toplevel window + * implicitly via an Enter event (rather + * than via a FocusIn event), this points + * to the toplevel window. Otherwise it is + * NULL. */ + struct TkWindow *focusPtr; /* Points to the window on this display that + * should be receiving keyboard events. When + * multiple applications on the display have + * the focus, this will refer to the + * innermost window in the innermost + * application. This information isn't used + * under Unix or Windows, but it's needed on + * the Macintosh. */ - Tk_Window clipWindow; /* Window used for clipboard ownership and to - * retrieve selections between processes. NULL - * means clipboard info hasn't been - * initialized. */ - int clipboardActive; /* 1 means we currently own the clipboard - * selection, 0 means we don't. */ - struct TkMainInfo *clipboardAppPtr; - /* Last application that owned clipboard. */ - struct TkClipboardTarget *clipTargetPtr; - /* First in list of clipboard type information - * records. Each entry contains information - * about the buffers for a given selection - * target. */ + /* + * Information used by tkGC.c only: + */ + + Tcl_HashTable gcValueTable; /* Maps from a GC's values to a TkGC structure + * describing a GC with those values. */ + Tcl_HashTable gcIdTable; /* Maps from a GC to a TkGC. */ + int gcInit; /* 0 means the tables below need + * initializing. */ /* - * Information used by tkAtom.c only: + * Information used by tkGeometry.c only: */ - int atomInit; /* 0 means stuff below hasn't been - * initialized yet. */ - Tcl_HashTable nameTable; /* Maps from names to Atom's. */ - Tcl_HashTable atomTable; /* Maps from Atom's back to names. */ + Tcl_HashTable maintainHashTable; + /* Hash table that maps from a master's + * Tk_Window token to a list of slaves + * managed by that master. */ + int geomInit; /* - * Information used by tkCursor.c only: + * Information used by tkGet.c only: */ - - Font cursorFont; /* Font to use for standard cursors. - * None means font not loaded yet. */ + + Tcl_HashTable uidTable; /* Stores all Tk_Uid used in a thread. */ + int uidInit; /* 0 means uidTable needs initializing. */ /* * Information used by tkGrab.c only: @@ -245,6 +331,100 @@ typedef struct TkDisplay { * in tkGrab.c. */ /* + * Information used by tkGrid.c only: + */ + + int gridInit; /* 0 means table below needs initializing. */ + Tcl_HashTable gridHashTable;/* Maps from Tk_Window tokens to + * corresponding Grid structures. */ + + /* + * Information used by tkImage.c only: + */ + + int imageId; /* Value used to number image ids. */ + + /* + * Information used by tkMacWinMenu.c only: + */ + + int postCommandGeneration; + + /* + * Information used by tkOption.c only. + */ + + + + /* + * Information used by tkPack.c only. + */ + + int packInit; /* 0 means table below needs initializing. */ + Tcl_HashTable packerHashTable; + /* Maps from Tk_Window tokens to + * corresponding Packer structures. */ + + + /* + * Information used by tkPlace.c only. + */ + + int placeInit; /* 0 means tables below need initializing. */ + Tcl_HashTable masterTable; /* Maps from Tk_Window toke to the Master + * structure for the window, if it exists. */ + Tcl_HashTable slaveTable; /* Maps from Tk_Window toke to the Slave + * structure for the window, if it exists. */ + + /* + * Information used by tkSelect.c and tkClipboard.c only: + */ + + struct TkSelectionInfo *selectionInfoPtr; + /* First in list of selection information + * records. Each entry contains information + * about the current owner of a particular + * selection on this display. */ + Atom multipleAtom; /* Atom for MULTIPLE. None means + * selection stuff isn't initialized. */ + Atom incrAtom; /* Atom for INCR. */ + Atom targetsAtom; /* Atom for TARGETS. */ + Atom timestampAtom; /* Atom for TIMESTAMP. */ + Atom textAtom; /* Atom for TEXT. */ + Atom compoundTextAtom; /* Atom for COMPOUND_TEXT. */ + Atom applicationAtom; /* Atom for TK_APPLICATION. */ + Atom windowAtom; /* Atom for TK_WINDOW. */ + Atom clipboardAtom; /* Atom for CLIPBOARD. */ + + Tk_Window clipWindow; /* Window used for clipboard ownership and to + * retrieve selections between processes. NULL + * means clipboard info hasn't been + * initialized. */ + int clipboardActive; /* 1 means we currently own the clipboard + * selection, 0 means we don't. */ + struct TkMainInfo *clipboardAppPtr; + /* Last application that owned clipboard. */ + struct TkClipboardTarget *clipTargetPtr; + /* First in list of clipboard type information + * records. Each entry contains information + * about the buffers for a given selection + * target. */ + + /* + * Information used by tkSend.c only: + */ + + Tk_Window commTkwin; /* Window used for communication + * between interpreters during "send" + * commands. NULL means send info hasn't + * been initialized yet. */ + Atom commProperty; /* X's name for comm property. */ + Atom registryProperty; /* X's name for property containing + * registry of interpreter names. */ + Atom appNameProperty; /* X's name for property used to hold the + * application name on each comm window. */ + + /* * Information used by tkXId.c only: */ @@ -263,6 +443,19 @@ typedef struct TkDisplay { * hasn't. */ /* + * Information used by tkUnixWm.c and tkWinWm.c only: + */ + + int wmTracing; /* Used to enable or disable tracing in + * this module. If tracing is enabled, + * then information is printed on + * standard output about interesting + * interactions with the window manager. */ + struct TkWmInfo *firstWmPtr; /* Points to first top-level window. */ + struct TkWmInfo *foregroundWmPtr; + /* Points to the foreground window. */ + + /* * Information maintained by tkWindow.c for use later on by tkXId.c: */ @@ -283,46 +476,6 @@ typedef struct TkDisplay { * allocated for this display. */ /* - * Information used by tkFocus.c only: - */ - - struct TkWindow *implicitWinPtr; - /* If the focus arrived at a toplevel window - * implicitly via an Enter event (rather - * than via a FocusIn event), this points - * to the toplevel window. Otherwise it is - * NULL. */ - struct TkWindow *focusPtr; /* Points to the window on this display that - * should be receiving keyboard events. When - * multiple applications on the display have - * the focus, this will refer to the - * innermost window in the innermost - * application. This information isn't used - * under Unix or Windows, but it's needed on - * the Macintosh. */ - - /* - * Used by tkColor.c only: - */ - - TkStressedCmap *stressPtr; /* First in list of colormaps that have - * filled up, so we have to pick an - * approximate color. */ - - /* - * Used by tkEvent.c only: - */ - - struct TkWindowEvent *delayedMotionPtr; - /* Points to a malloc-ed motion event - * whose processing has been delayed in - * the hopes that another motion event - * will come along right away and we can - * merge the two of them together. NULL - * means that there is no delayed motion - * event. */ - - /* * Miscellaneous information: */ @@ -336,6 +489,16 @@ typedef struct TkDisplay { * the display when we no longer have any * Tk applications using it. */ + /* + * The following field were all added for Tk8.3 + */ + int mouseButtonState; /* current mouse button state for this + * display */ + int warpInProgress; + Window warpWindow; + int warpX; + int warpY; + int useInputMethods; /* Whether to use input methods */ } TkDisplay; /* @@ -373,6 +536,9 @@ typedef struct TkErrorHandler { * list. */ } TkErrorHandler; + + + /* * One of the following structures exists for each event handler * created by calling Tk_CreateEventHandler. This information @@ -393,7 +559,7 @@ typedef struct TkEventHandler { /* * Tk keeps one of the following data structures for each main - * window (created by a call to Tk_CreateMainWindow). It stores + * window (created by a call to TkCreateMainWindow). It stores * information that is shared by all of the windows associated * with a particular main window. */ @@ -415,10 +581,10 @@ typedef struct TkMainInfo { /* Used in conjunction with "bind" command * to bind events to Tcl commands. */ TkBindInfo bindInfo; /* Information used by tkBind.c on a per - * interpreter basis. */ + * application basis. */ struct TkFontInfo *fontInfoPtr; - /* Hold named font tables. Used only by - * tkFont.c. */ + /* Information used by tkFont.c on a per + * application basis. */ /* * Information used only by tkFocus.c and tk*Embed.c: @@ -685,296 +851,239 @@ extern TkDisplay *tkDisplayList; #define EMBEDDED_APP_WANTS_FOCUS (NotifyNormal + 20) /* + * The following special modifier mask bits are defined, to indicate + * logical modifiers such as Meta and Alt that may float among the + * actual modifier bits. + */ + +#define META_MASK (AnyModifier<<1) +#define ALT_MASK (AnyModifier<<2) + +/* * Miscellaneous variables shared among Tk modules but not exported * to the outside world: */ -extern Tk_Uid tkActiveUid; +extern Tk_SmoothMethod tkBezierSmoothMethod; extern Tk_ImageType tkBitmapImageType; -extern Tk_Uid tkDisabledUid; extern Tk_PhotoImageFormat tkImgFmtGIF; extern void (*tkHandleEventProc) _ANSI_ARGS_(( XEvent* eventPtr)); extern Tk_PhotoImageFormat tkImgFmtPPM; extern TkMainInfo *tkMainWindowList; -extern Tk_Uid tkNormalUid; extern Tk_ImageType tkPhotoImageType; extern Tcl_HashTable tkPredefBitmapTable; extern int tkSendSerial; +#include "tkIntDecls.h" + +#ifdef BUILD_tk +# undef TCL_STORAGE_CLASS +# define TCL_STORAGE_CLASS DLLEXPORT +#endif + /* * Internal procedures shared among Tk modules but not exported * to the outside world: */ -EXTERN char * TkAlignImageData _ANSI_ARGS_((XImage *image, - int alignment, int bitOrder)); -EXTERN TkWindow * TkAllocWindow _ANSI_ARGS_((TkDisplay *dispPtr, - int screenNum, TkWindow *parentPtr)); -EXTERN void TkBezierPoints _ANSI_ARGS_((double control[], - int numSteps, double *coordPtr)); -EXTERN void TkBezierScreenPoints _ANSI_ARGS_((Tk_Canvas canvas, - double control[], int numSteps, - XPoint *xPointPtr)); -EXTERN void TkBindDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkBindEventProc _ANSI_ARGS_((TkWindow *winPtr, - XEvent *eventPtr)); -EXTERN void TkBindFree _ANSI_ARGS_((TkMainInfo *mainPtr)); -EXTERN void TkBindInit _ANSI_ARGS_((TkMainInfo *mainPtr)); -EXTERN void TkChangeEventWindow _ANSI_ARGS_((XEvent *eventPtr, - TkWindow *winPtr)); -#ifndef TkClipBox -EXTERN void TkClipBox _ANSI_ARGS_((TkRegion rgn, - XRectangle* rect_return)); -#endif -EXTERN int TkClipInit _ANSI_ARGS_((Tcl_Interp *interp, - TkDisplay *dispPtr)); -EXTERN void TkComputeAnchor _ANSI_ARGS_((Tk_Anchor anchor, - Tk_Window tkwin, int padX, int padY, - int innerWidth, int innerHeight, int *xPtr, - int *yPtr)); -EXTERN int TkCopyAndGlobalEval _ANSI_ARGS_((Tcl_Interp *interp, - char *script)); -EXTERN unsigned long TkCreateBindingProcedure _ANSI_ARGS_(( - Tcl_Interp *interp, Tk_BindingTable bindingTable, - ClientData object, char *eventString, - TkBindEvalProc *evalProc, TkBindFreeProc *freeProc, - ClientData clientData)); -EXTERN TkCursor * TkCreateCursorFromData _ANSI_ARGS_((Tk_Window tkwin, - char *source, char *mask, int width, int height, - int xHot, int yHot, XColor fg, XColor bg)); -EXTERN int TkCreateFrame _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv, - int toplevel, char *appName)); -EXTERN Tk_Window TkCreateMainWindow _ANSI_ARGS_((Tcl_Interp *interp, - char *screenName, char *baseName)); -#ifndef TkCreateRegion -EXTERN TkRegion TkCreateRegion _ANSI_ARGS_((void)); -#endif -EXTERN Time TkCurrentTime _ANSI_ARGS_((TkDisplay *dispPtr)); +EXTERN int Tk_AfterCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_BellObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_BindCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_BindtagsCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_ButtonObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_CanvasObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[])); +EXTERN int Tk_CheckbuttonObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_ClipboardCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_ChooseColorObjCmd _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[])); +EXTERN int Tk_ChooseDirectoryObjCmd _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[])); +EXTERN int Tk_ChooseFontObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_DestroyObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_EntryObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_EventObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_FileeventCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_FrameObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_FocusObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_FontObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_GetOpenFileObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_GetSaveFileObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_GrabCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_GridCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_ImageObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_LabelObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_ListboxObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_LowerObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_MenubuttonObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_MessageBoxObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_MessageCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_OptionObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_PackCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_PlaceCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_RadiobuttonObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_RaiseObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_ScaleObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_ScrollbarCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_SelectionCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_SendCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_SendObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_TextCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_TkObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_TkwaitCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); +EXTERN int Tk_ToplevelObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_UpdateObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_WinfoObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +EXTERN int Tk_WmCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int argc, char **argv)); + +void TkConsolePrint _ANSI_ARGS_((Tcl_Interp *interp, + int devId, char *buffer, long size)); + +EXTERN void TkEventInit _ANSI_ARGS_((void)); + +EXTERN int TkCreateMenuCmd _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int TkDeadAppCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); -EXTERN void TkDeleteAllImages _ANSI_ARGS_((TkMainInfo *mainPtr)); -#ifndef TkDestroyRegion -EXTERN void TkDestroyRegion _ANSI_ARGS_((TkRegion rgn)); -#endif -EXTERN void TkDoConfigureNotify _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkDrawInsetFocusHighlight _ANSI_ARGS_(( - Tk_Window tkwin, GC gc, int width, - Drawable drawable, int padding)); -EXTERN void TkEventDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkFillPolygon _ANSI_ARGS_((Tk_Canvas canvas, - double *coordPtr, int numPoints, Display *display, - Drawable drawable, GC gc, GC outlineGC)); -EXTERN int TkFindStateNum _ANSI_ARGS_((Tcl_Interp *interp, - CONST char *option, CONST TkStateMap *mapPtr, - CONST char *strKey)); -EXTERN char * TkFindStateString _ANSI_ARGS_(( - CONST TkStateMap *mapPtr, int numKey)); -EXTERN void TkFocusDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkFocusFilterEvent _ANSI_ARGS_((TkWindow *winPtr, - XEvent *eventPtr)); -EXTERN TkWindow * TkFocusKeyEvent _ANSI_ARGS_((TkWindow *winPtr, - XEvent *eventPtr)); -EXTERN void TkFontPkgInit _ANSI_ARGS_((TkMainInfo *mainPtr)); -EXTERN void TkFontPkgFree _ANSI_ARGS_((TkMainInfo *mainPtr)); -EXTERN void TkFreeBindingTags _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkFreeCursor _ANSI_ARGS_((TkCursor *cursorPtr)); -EXTERN void TkFreeWindowId _ANSI_ARGS_((TkDisplay *dispPtr, - Window w)); -EXTERN void TkGenerateActivateEvents _ANSI_ARGS_(( - TkWindow *winPtr, int active)); -EXTERN char * TkGetBitmapData _ANSI_ARGS_((Tcl_Interp *interp, - char *string, char *fileName, int *widthPtr, - int *heightPtr, int *hotXPtr, int *hotYPtr)); -EXTERN void TkGetButtPoints _ANSI_ARGS_((double p1[], double p2[], - double width, int project, double m1[], - double m2[])); -EXTERN TkCursor * TkGetCursorByName _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, Tk_Uid string)); -EXTERN char * TkGetDefaultScreenName _ANSI_ARGS_((Tcl_Interp *interp, - char *screenName)); -EXTERN TkDisplay * TkGetDisplay _ANSI_ARGS_((Display *display)); -EXTERN int TkGetDisplayOf _ANSI_ARGS_((Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[], - Tk_Window *tkwinPtr)); -EXTERN TkWindow * TkGetFocusWin _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkGetInterpNames _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin)); -EXTERN int TkGetMiterPoints _ANSI_ARGS_((double p1[], double p2[], - double p3[], double width, double m1[], - double m2[])); -EXTERN void TkGetPointerCoords _ANSI_ARGS_((Tk_Window tkwin, - int *xPtr, int *yPtr)); -EXTERN int TkGetProlog _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN void TkGetServerInfo _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin)); -EXTERN void TkGrabDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkGrabState _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkIncludePoint _ANSI_ARGS_((Tk_Item *itemPtr, - double *pointPtr)); -EXTERN void TkInitXId _ANSI_ARGS_((TkDisplay *dispPtr)); -EXTERN void TkInOutEvents _ANSI_ARGS_((XEvent *eventPtr, - TkWindow *sourcePtr, TkWindow *destPtr, - int leaveType, int enterType, - Tcl_QueuePosition position)); -EXTERN void TkInstallFrameMenu _ANSI_ARGS_((Tk_Window tkwin)); -#ifndef TkIntersectRegion -EXTERN void TkIntersectRegion _ANSI_ARGS_((TkRegion sra, - TkRegion srcb, TkRegion dr_return)); -#endif -EXTERN char * TkKeysymToString _ANSI_ARGS_((KeySym keysym)); -EXTERN int TkLineToArea _ANSI_ARGS_((double end1Ptr[2], - double end2Ptr[2], double rectPtr[4])); -EXTERN double TkLineToPoint _ANSI_ARGS_((double end1Ptr[2], - double end2Ptr[2], double pointPtr[2])); -EXTERN int TkMakeBezierCurve _ANSI_ARGS_((Tk_Canvas canvas, - double *pointPtr, int numPoints, int numSteps, - XPoint xPoints[], double dblPoints[])); -EXTERN void TkMakeBezierPostscript _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Canvas canvas, double *pointPtr, - int numPoints)); -EXTERN void TkOptionClassChanged _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkOptionDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkOvalToArea _ANSI_ARGS_((double *ovalPtr, - double *rectPtr)); -EXTERN double TkOvalToPoint _ANSI_ARGS_((double ovalPtr[4], - double width, int filled, double pointPtr[2])); -EXTERN int TkpChangeFocus _ANSI_ARGS_((TkWindow *winPtr, - int force)); -EXTERN void TkpCloseDisplay _ANSI_ARGS_((TkDisplay *dispPtr)); -EXTERN void TkpClaimFocus _ANSI_ARGS_((TkWindow *topLevelPtr, - int force)); -#ifndef TkpCmapStressed -EXTERN int TkpCmapStressed _ANSI_ARGS_((Tk_Window tkwin, - Colormap colormap)); -#endif -#ifndef TkpCreateNativeBitmap -EXTERN Pixmap TkpCreateNativeBitmap _ANSI_ARGS_((Display *display, - char * source)); -#endif -#ifndef TkpDefineNativeBitmaps -EXTERN void TkpDefineNativeBitmaps _ANSI_ARGS_((void)); -#endif -EXTERN void TkpDisplayWarning _ANSI_ARGS_((char *msg, - char *title)); -EXTERN void TkpGetAppName _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_DString *name)); -EXTERN unsigned long TkpGetMS _ANSI_ARGS_((void)); -#ifndef TkpGetNativeAppBitmap -EXTERN Pixmap TkpGetNativeAppBitmap _ANSI_ARGS_((Display *display, - char *name, int *width, int *height)); -#endif -EXTERN TkWindow * TkpGetOtherWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN TkWindow * TkpGetWrapperWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkpInit _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN void TkpInitializeMenuBindings _ANSI_ARGS_(( - Tcl_Interp *interp, Tk_BindingTable bindingTable)); -EXTERN void TkpMakeContainer _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void TkpMakeMenuWindow _ANSI_ARGS_((Tk_Window tkwin, - int transient)); -EXTERN Window TkpMakeWindow _ANSI_ARGS_((TkWindow *winPtr, - Window parent)); -EXTERN void TkpMenuNotifyToplevelCreate _ANSI_ARGS_(( - Tcl_Interp *, char *menuName)); -EXTERN TkDisplay * TkpOpenDisplay _ANSI_ARGS_((char *display_name)); -EXTERN void TkPointerDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkPointerEvent _ANSI_ARGS_((XEvent *eventPtr, - TkWindow *winPtr)); -EXTERN int TkPolygonToArea _ANSI_ARGS_((double *polyPtr, - int numPoints, double *rectPtr)); -EXTERN double TkPolygonToPoint _ANSI_ARGS_((double *polyPtr, - int numPoints, double *pointPtr)); -EXTERN int TkPositionInTree _ANSI_ARGS_((TkWindow *winPtr, - TkWindow *treePtr)); -#ifndef TkpPrintWindowId -EXTERN void TkpPrintWindowId _ANSI_ARGS_((char *buf, - Window window)); -#endif -EXTERN void TkpRedirectKeyEvent _ANSI_ARGS_((TkWindow *winPtr, - XEvent *eventPtr)); -#ifndef TkpScanWindowId -EXTERN int TkpScanWindowId _ANSI_ARGS_((Tcl_Interp *interp, - char *string, int *idPtr)); -#endif -EXTERN void TkpSetCapture _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkpSetCursor _ANSI_ARGS_((TkpCursor cursor)); -EXTERN void TkpSetMainMenubar _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *menuName)); -#ifndef TkpSync -EXTERN void TkpSync _ANSI_ARGS_((Display *display)); -#endif + EXTERN int TkpTestembedCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); -EXTERN int TkpUseWindow _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *string)); -#ifndef TkPutImage -EXTERN void TkPutImage _ANSI_ARGS_((unsigned long *colors, - int ncolors, Display* display, Drawable d, - GC gc, XImage* image, int src_x, int src_y, - int dest_x, int dest_y, unsigned int width, - unsigned int height)); -#endif -EXTERN int TkpWindowWasRecentlyDeleted _ANSI_ARGS_((Window win, - TkDisplay *dispPtr)); -EXTERN void TkpWmSetState _ANSI_ARGS_((TkWindow *winPtr, - int state)); -EXTERN void TkQueueEventForAllChildren _ANSI_ARGS_(( - TkWindow *winPtr, XEvent *eventPtr)); -EXTERN int TkReadBitmapFile _ANSI_ARGS_((Display* display, - Drawable d, CONST char* filename, - unsigned int* width_return, - unsigned int* height_return, - Pixmap* bitmap_return, - int* x_hot_return, int* y_hot_return)); -#ifndef TkRectInRegion -EXTERN int TkRectInRegion _ANSI_ARGS_((TkRegion rgn, - int x, int y, unsigned int width, - unsigned int height)); -#endif -EXTERN int TkScrollWindow _ANSI_ARGS_((Tk_Window tkwin, GC gc, - int x, int y, int width, int height, int dx, - int dy, TkRegion damageRgn)); -EXTERN void TkSelDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkSelEventProc _ANSI_ARGS_((Tk_Window tkwin, - XEvent *eventPtr)); -EXTERN void TkSelInit _ANSI_ARGS_((Tk_Window tkwin)); -EXTERN void TkSelPropProc _ANSI_ARGS_((XEvent *eventPtr)); -EXTERN void TkSetClassProcs _ANSI_ARGS_((Tk_Window tkwin, - TkClassProcs *procs, ClientData instanceData)); -#ifndef TkSetPixmapColormap -EXTERN void TkSetPixmapColormap _ANSI_ARGS_((Pixmap pixmap, - Colormap colormap)); -#endif -#ifndef TkSetRegion -EXTERN void TkSetRegion _ANSI_ARGS_((Display* display, GC gc, - TkRegion rgn)); -#endif -EXTERN void TkSetWindowMenuBar _ANSI_ARGS_((Tcl_Interp *interp, - Tk_Window tkwin, char *oldMenuName, - char *menuName)); -EXTERN KeySym TkStringToKeysym _ANSI_ARGS_((char *name)); -EXTERN int TkThickPolyLineToArea _ANSI_ARGS_((double *coordPtr, - int numPoints, double width, int capStyle, - int joinStyle, double *rectPtr)); -#ifndef TkUnionRectWithRegion -EXTERN void TkUnionRectWithRegion _ANSI_ARGS_((XRectangle* rect, - TkRegion src, TkRegion dr_return)); -#endif -EXTERN void TkWmAddToColormapWindows _ANSI_ARGS_(( - TkWindow *winPtr)); -EXTERN void TkWmDeadWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN TkWindow * TkWmFocusToplevel _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkWmMapWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkWmNewWindow _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkWmProtocolEventProc _ANSI_ARGS_((TkWindow *winPtr, - XEvent *evenvPtr)); -EXTERN void TkWmRemoveFromColormapWindows _ANSI_ARGS_(( - TkWindow *winPtr)); -EXTERN void TkWmRestackToplevel _ANSI_ARGS_((TkWindow *winPtr, - int aboveBelow, TkWindow *otherPtr)); -EXTERN void TkWmSetClass _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN void TkWmUnmapWindow _ANSI_ARGS_((TkWindow *winPtr)); +EXTERN int TkCanvasGetCoordObj _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tcl_Obj *obj, + double *doublePtr)); +EXTERN int TkCanvasDashParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, char *widgRec, + int offset)); +EXTERN char * TkCanvasDashPrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkGetDoublePixels _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, CONST char *string, + double *doublePtr)); +EXTERN int TkOffsetParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, char *widgRec, + int offset)); +EXTERN char * TkOffsetPrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkOrientParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, + char *widgRec, int offset)); +EXTERN char * TkOrientPrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkPixelParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, char *widgRec, + int offset)); +EXTERN char * TkPixelPrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkPostscriptImage _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, Tk_PostscriptInfo psInfo, + XImage *ximage, int x, int y, int width, + int height)); +EXTERN int TkSmoothParseProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, + CONST char *value, char *recordPtr, int offset)); +EXTERN char * TkSmoothPrintProc _ANSI_ARGS_((ClientData clientData, + Tk_Window tkwin, char *recordPtr, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkStateParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, + char *widgRec, int offset)); +EXTERN char * TkStatePrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); +EXTERN int TkTileParseProc _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, char *widgRec, + int offset)); +EXTERN char * TkTilePrintProc _ANSI_ARGS_(( + ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); /* * Unsupported commands. @@ -987,8 +1096,10 @@ EXTERN void TkRegisterColorGC _ANSI_ARGS_((XColor *, Display *, GC, unsigned long)); EXTERN void TkDeregisterColorGC _ANSI_ARGS_((XColor *, GC, unsigned long)); + # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLIMPORT - #endif /* _TKINT */ + + diff --git a/tk/generic/tkIntDecls.h b/tk/generic/tkIntDecls.h new file mode 100644 index 00000000000..0e37d59f8b1 --- /dev/null +++ b/tk/generic/tkIntDecls.h @@ -0,0 +1,1485 @@ +/* + * tkIntDecls.h -- + * + * This file contains the declarations for all unsupported + * functions that are exported by the Tk library. These + * interfaces are not guaranteed to remain the same between + * versions. Use at your own risk. + * + * Copyright (c) 1998-1999 by Scriptics Corporation. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +#ifndef _TKINTDECLS +#define _TKINTDECLS + +#ifdef BUILD_tk +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLEXPORT +#endif + +/* + * WARNING: This file is automatically generated by the tools/genStubs.tcl + * script. Any modifications to the function declarations below should be made + * in the generic/tkInt.decls script. + */ + +/* !BEGIN!: Do not edit below this line. */ + +/* + * Exported function declarations: + */ + +/* 0 */ +EXTERN TkWindow * TkAllocWindow _ANSI_ARGS_((TkDisplay * dispPtr, + int screenNum, TkWindow * parentPtr)); +/* 1 */ +EXTERN void TkBezierPoints _ANSI_ARGS_((double control[], + int numSteps, double * coordPtr)); +/* 2 */ +EXTERN void TkBezierScreenPoints _ANSI_ARGS_((Tk_Canvas canvas, + double control[], int numSteps, + XPoint * xPointPtr)); +/* 3 */ +EXTERN void TkBindDeadWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 4 */ +EXTERN void TkBindEventProc _ANSI_ARGS_((TkWindow * winPtr, + XEvent * eventPtr)); +/* 5 */ +EXTERN void TkBindFree _ANSI_ARGS_((TkMainInfo * mainPtr)); +/* 6 */ +EXTERN void TkBindInit _ANSI_ARGS_((TkMainInfo * mainPtr)); +/* 7 */ +EXTERN void TkChangeEventWindow _ANSI_ARGS_((XEvent * eventPtr, + TkWindow * winPtr)); +/* 8 */ +EXTERN int TkClipInit _ANSI_ARGS_((Tcl_Interp * interp, + TkDisplay * dispPtr)); +/* 9 */ +EXTERN void TkComputeAnchor _ANSI_ARGS_((Tk_Anchor anchor, + Tk_Window tkwin, int padX, int padY, + int innerWidth, int innerHeight, int * xPtr, + int * yPtr)); +/* 10 */ +EXTERN int TkCopyAndGlobalEval _ANSI_ARGS_((Tcl_Interp * interp, + char * script)); +/* 11 */ +EXTERN unsigned long TkCreateBindingProcedure _ANSI_ARGS_(( + Tcl_Interp * interp, + Tk_BindingTable bindingTable, + ClientData object, char * eventString, + TkBindEvalProc * evalProc, + TkBindFreeProc * freeProc, + ClientData clientData)); +/* 12 */ +EXTERN TkCursor * TkCreateCursorFromData _ANSI_ARGS_((Tk_Window tkwin, + char * source, char * mask, int width, + int height, int xHot, int yHot, XColor fg, + XColor bg)); +/* 13 */ +EXTERN int TkCreateFrame _ANSI_ARGS_((ClientData clientData, + Tcl_Interp * interp, int argc, char ** argv, + int toplevel, char * appName)); +/* 14 */ +EXTERN Tk_Window TkCreateMainWindow _ANSI_ARGS_((Tcl_Interp * interp, + char * screenName, char * baseName)); +/* 15 */ +EXTERN Time TkCurrentTime _ANSI_ARGS_((TkDisplay * dispPtr)); +/* 16 */ +EXTERN void TkDeleteAllImages _ANSI_ARGS_((TkMainInfo * mainPtr)); +/* 17 */ +EXTERN void TkDoConfigureNotify _ANSI_ARGS_((TkWindow * winPtr)); +/* 18 */ +EXTERN void TkDrawInsetFocusHighlight _ANSI_ARGS_(( + Tk_Window tkwin, GC gc, int width, + Drawable drawable, int padding)); +/* 19 */ +EXTERN void TkEventDeadWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 20 */ +EXTERN void TkFillPolygon _ANSI_ARGS_((Tk_Canvas canvas, + double * coordPtr, int numPoints, + Display * display, Drawable drawable, GC gc, + GC outlineGC)); +/* 21 */ +EXTERN int TkFindStateNum _ANSI_ARGS_((Tcl_Interp * interp, + CONST char * option, + CONST TkStateMap * mapPtr, + CONST char * strKey)); +/* 22 */ +EXTERN char * TkFindStateString _ANSI_ARGS_(( + CONST TkStateMap * mapPtr, int numKey)); +/* 23 */ +EXTERN void TkFocusDeadWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 24 */ +EXTERN int TkFocusFilterEvent _ANSI_ARGS_((TkWindow * winPtr, + XEvent * eventPtr)); +/* 25 */ +EXTERN TkWindow * TkFocusKeyEvent _ANSI_ARGS_((TkWindow * winPtr, + XEvent * eventPtr)); +/* 26 */ +EXTERN void TkFontPkgInit _ANSI_ARGS_((TkMainInfo * mainPtr)); +/* 27 */ +EXTERN void TkFontPkgFree _ANSI_ARGS_((TkMainInfo * mainPtr)); +/* 28 */ +EXTERN void TkFreeBindingTags _ANSI_ARGS_((TkWindow * winPtr)); +/* 29 */ +EXTERN void TkpFreeCursor _ANSI_ARGS_((TkCursor * cursorPtr)); +/* 30 */ +EXTERN char * TkGetBitmapData _ANSI_ARGS_((Tcl_Interp * interp, + char * string, char * fileName, + int * widthPtr, int * heightPtr, + int * hotXPtr, int * hotYPtr)); +/* 31 */ +EXTERN void TkGetButtPoints _ANSI_ARGS_((double p1[], + double p2[], double width, int project, + double m1[], double m2[])); +/* 32 */ +EXTERN TkCursor * TkGetCursorByName _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tk_Uid string)); +/* 33 */ +EXTERN char * TkGetDefaultScreenName _ANSI_ARGS_(( + Tcl_Interp * interp, char * screenName)); +/* 34 */ +EXTERN TkDisplay * TkGetDisplay _ANSI_ARGS_((Display * display)); +/* 35 */ +EXTERN int TkGetDisplayOf _ANSI_ARGS_((Tcl_Interp * interp, + int objc, Tcl_Obj *CONST objv[], + Tk_Window * tkwinPtr)); +/* 36 */ +EXTERN TkWindow * TkGetFocusWin _ANSI_ARGS_((TkWindow * winPtr)); +/* 37 */ +EXTERN int TkGetInterpNames _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin)); +/* 38 */ +EXTERN int TkGetMiterPoints _ANSI_ARGS_((double p1[], + double p2[], double p3[], double width, + double m1[], double m2[])); +/* 39 */ +EXTERN void TkGetPointerCoords _ANSI_ARGS_((Tk_Window tkwin, + int * xPtr, int * yPtr)); +/* 40 */ +EXTERN void TkGetServerInfo _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin)); +/* 41 */ +EXTERN void TkGrabDeadWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 42 */ +EXTERN int TkGrabState _ANSI_ARGS_((TkWindow * winPtr)); +/* 43 */ +EXTERN void TkIncludePoint _ANSI_ARGS_((Tk_Item * itemPtr, + double * pointPtr)); +/* 44 */ +EXTERN void TkInOutEvents _ANSI_ARGS_((XEvent * eventPtr, + TkWindow * sourcePtr, TkWindow * destPtr, + int leaveType, int enterType, + Tcl_QueuePosition position)); +/* 45 */ +EXTERN void TkInstallFrameMenu _ANSI_ARGS_((Tk_Window tkwin)); +/* 46 */ +EXTERN char * TkKeysymToString _ANSI_ARGS_((KeySym keysym)); +/* 47 */ +EXTERN int TkLineToArea _ANSI_ARGS_((double end1Ptr[], + double end2Ptr[], double rectPtr[])); +/* 48 */ +EXTERN double TkLineToPoint _ANSI_ARGS_((double end1Ptr[], + double end2Ptr[], double pointPtr[])); +/* 49 */ +EXTERN int TkMakeBezierCurve _ANSI_ARGS_((Tk_Canvas canvas, + double * pointPtr, int numPoints, + int numSteps, XPoint xPoints[], + double dblPoints[])); +/* 50 */ +EXTERN void TkMakeBezierPostscript _ANSI_ARGS_(( + Tcl_Interp * interp, Tk_Canvas canvas, + double * pointPtr, int numPoints)); +/* 51 */ +EXTERN void TkOptionClassChanged _ANSI_ARGS_((TkWindow * winPtr)); +/* 52 */ +EXTERN void TkOptionDeadWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 53 */ +EXTERN int TkOvalToArea _ANSI_ARGS_((double * ovalPtr, + double * rectPtr)); +/* 54 */ +EXTERN double TkOvalToPoint _ANSI_ARGS_((double ovalPtr[], + double width, int filled, double pointPtr[])); +/* 55 */ +EXTERN int TkpChangeFocus _ANSI_ARGS_((TkWindow * winPtr, + int force)); +/* 56 */ +EXTERN void TkpCloseDisplay _ANSI_ARGS_((TkDisplay * dispPtr)); +/* 57 */ +EXTERN void TkpClaimFocus _ANSI_ARGS_((TkWindow * topLevelPtr, + int force)); +/* 58 */ +EXTERN void TkpDisplayWarning _ANSI_ARGS_((char * msg, + char * title)); +/* 59 */ +EXTERN void TkpGetAppName _ANSI_ARGS_((Tcl_Interp * interp, + Tcl_DString * name)); +/* 60 */ +EXTERN TkWindow * TkpGetOtherWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 61 */ +EXTERN TkWindow * TkpGetWrapperWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 62 */ +EXTERN int TkpInit _ANSI_ARGS_((Tcl_Interp * interp)); +/* 63 */ +EXTERN void TkpInitializeMenuBindings _ANSI_ARGS_(( + Tcl_Interp * interp, + Tk_BindingTable bindingTable)); +/* 64 */ +EXTERN void TkpMakeContainer _ANSI_ARGS_((Tk_Window tkwin)); +/* 65 */ +EXTERN void TkpMakeMenuWindow _ANSI_ARGS_((Tk_Window tkwin, + int transient)); +/* 66 */ +EXTERN Window TkpMakeWindow _ANSI_ARGS_((TkWindow * winPtr, + Window parent)); +/* 67 */ +EXTERN void TkpMenuNotifyToplevelCreate _ANSI_ARGS_(( + Tcl_Interp * interp1, char * menuName)); +/* 68 */ +EXTERN TkDisplay * TkpOpenDisplay _ANSI_ARGS_((char * display_name)); +/* 69 */ +EXTERN int TkPointerEvent _ANSI_ARGS_((XEvent * eventPtr, + TkWindow * winPtr)); +/* 70 */ +EXTERN int TkPolygonToArea _ANSI_ARGS_((double * polyPtr, + int numPoints, double * rectPtr)); +/* 71 */ +EXTERN double TkPolygonToPoint _ANSI_ARGS_((double * polyPtr, + int numPoints, double * pointPtr)); +/* 72 */ +EXTERN int TkPositionInTree _ANSI_ARGS_((TkWindow * winPtr, + TkWindow * treePtr)); +/* 73 */ +EXTERN void TkpRedirectKeyEvent _ANSI_ARGS_((TkWindow * winPtr, + XEvent * eventPtr)); +/* 74 */ +EXTERN void TkpSetMainMenubar _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, char * menuName)); +/* 75 */ +EXTERN int TkpUseWindow _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, char * string)); +/* 76 */ +EXTERN int TkpWindowWasRecentlyDeleted _ANSI_ARGS_((Window win, + TkDisplay * dispPtr)); +/* 77 */ +EXTERN void TkQueueEventForAllChildren _ANSI_ARGS_(( + TkWindow * winPtr, XEvent * eventPtr)); +/* 78 */ +EXTERN int TkReadBitmapFile _ANSI_ARGS_((Display* display, + Drawable d, CONST char* filename, + unsigned int* width_return, + unsigned int* height_return, + Pixmap* bitmap_return, int* x_hot_return, + int* y_hot_return)); +/* 79 */ +EXTERN int TkScrollWindow _ANSI_ARGS_((Tk_Window tkwin, GC gc, + int x, int y, int width, int height, int dx, + int dy, TkRegion damageRgn)); +/* 80 */ +EXTERN void TkSelDeadWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 81 */ +EXTERN void TkSelEventProc _ANSI_ARGS_((Tk_Window tkwin, + XEvent * eventPtr)); +/* 82 */ +EXTERN void TkSelInit _ANSI_ARGS_((Tk_Window tkwin)); +/* 83 */ +EXTERN void TkSelPropProc _ANSI_ARGS_((XEvent * eventPtr)); +/* 84 */ +EXTERN void TkSetClassProcs _ANSI_ARGS_((Tk_Window tkwin, + TkClassProcs * procs, + ClientData instanceData)); +/* 85 */ +EXTERN void TkSetWindowMenuBar _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, char * oldMenuName, + char * menuName)); +/* 86 */ +EXTERN KeySym TkStringToKeysym _ANSI_ARGS_((char * name)); +/* 87 */ +EXTERN int TkThickPolyLineToArea _ANSI_ARGS_((double * coordPtr, + int numPoints, double width, int capStyle, + int joinStyle, double * rectPtr)); +/* 88 */ +EXTERN void TkWmAddToColormapWindows _ANSI_ARGS_(( + TkWindow * winPtr)); +/* 89 */ +EXTERN void TkWmDeadWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 90 */ +EXTERN TkWindow * TkWmFocusToplevel _ANSI_ARGS_((TkWindow * winPtr)); +/* 91 */ +EXTERN void TkWmMapWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 92 */ +EXTERN void TkWmNewWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 93 */ +EXTERN void TkWmProtocolEventProc _ANSI_ARGS_((TkWindow * winPtr, + XEvent * evenvPtr)); +/* 94 */ +EXTERN void TkWmRemoveFromColormapWindows _ANSI_ARGS_(( + TkWindow * winPtr)); +/* 95 */ +EXTERN void TkWmRestackToplevel _ANSI_ARGS_((TkWindow * winPtr, + int aboveBelow, TkWindow * otherPtr)); +/* 96 */ +EXTERN void TkWmSetClass _ANSI_ARGS_((TkWindow * winPtr)); +/* 97 */ +EXTERN void TkWmUnmapWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 98 */ +EXTERN Tcl_Obj * TkDebugBitmap _ANSI_ARGS_((Tk_Window tkwin, + char * name)); +/* 99 */ +EXTERN Tcl_Obj * TkDebugBorder _ANSI_ARGS_((Tk_Window tkwin, + char * name)); +/* 100 */ +EXTERN Tcl_Obj * TkDebugCursor _ANSI_ARGS_((Tk_Window tkwin, + char * name)); +/* 101 */ +EXTERN Tcl_Obj * TkDebugColor _ANSI_ARGS_((Tk_Window tkwin, + char * name)); +/* 102 */ +EXTERN Tcl_Obj * TkDebugConfig _ANSI_ARGS_((Tcl_Interp * interp, + Tk_OptionTable table)); +/* 103 */ +EXTERN Tcl_Obj * TkDebugFont _ANSI_ARGS_((Tk_Window tkwin, + char * name)); +/* 104 */ +EXTERN int TkFindStateNumObj _ANSI_ARGS_((Tcl_Interp * interp, + Tcl_Obj * optionPtr, + CONST TkStateMap * mapPtr, Tcl_Obj * keyPtr)); +/* 105 */ +EXTERN Tcl_HashTable * TkGetBitmapPredefTable _ANSI_ARGS_((void)); +/* 106 */ +EXTERN TkDisplay * TkGetDisplayList _ANSI_ARGS_((void)); +/* 107 */ +EXTERN TkMainInfo * TkGetMainInfoList _ANSI_ARGS_((void)); +/* 108 */ +EXTERN int TkGetWindowFromObj _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Window tkwin, Tcl_Obj * objPtr, + Tk_Window * windowPtr)); +/* 109 */ +EXTERN char * TkpGetString _ANSI_ARGS_((TkWindow * winPtr, + XEvent * eventPtr, Tcl_DString * dsPtr)); +/* 110 */ +EXTERN void TkpGetSubFonts _ANSI_ARGS_((Tcl_Interp * interp, + Tk_Font tkfont)); +/* 111 */ +EXTERN Tcl_Obj * TkpGetSystemDefault _ANSI_ARGS_((Tk_Window tkwin, + char * dbName, char * className)); +/* 112 */ +EXTERN void TkpMenuThreadInit _ANSI_ARGS_((void)); +#ifdef __WIN32__ +/* 113 */ +EXTERN void TkClipBox _ANSI_ARGS_((TkRegion rgn, + XRectangle* rect_return)); +#endif /* __WIN32__ */ +#ifdef MAC_TCL +/* 113 */ +EXTERN void TkClipBox _ANSI_ARGS_((TkRegion rgn, + XRectangle* rect_return)); +#endif /* MAC_TCL */ +#ifdef __WIN32__ +/* 114 */ +EXTERN TkRegion TkCreateRegion _ANSI_ARGS_((void)); +#endif /* __WIN32__ */ +#ifdef MAC_TCL +/* 114 */ +EXTERN TkRegion TkCreateRegion _ANSI_ARGS_((void)); +#endif /* MAC_TCL */ +#ifdef __WIN32__ +/* 115 */ +EXTERN void TkDestroyRegion _ANSI_ARGS_((TkRegion rgn)); +#endif /* __WIN32__ */ +#ifdef MAC_TCL +/* 115 */ +EXTERN void TkDestroyRegion _ANSI_ARGS_((TkRegion rgn)); +#endif /* MAC_TCL */ +#ifdef __WIN32__ +/* 116 */ +EXTERN void TkIntersectRegion _ANSI_ARGS_((TkRegion sra, + TkRegion srcb, TkRegion dr_return)); +#endif /* __WIN32__ */ +#ifdef MAC_TCL +/* 116 */ +EXTERN void TkIntersectRegion _ANSI_ARGS_((TkRegion sra, + TkRegion srcb, TkRegion dr_return)); +#endif /* MAC_TCL */ +#ifdef __WIN32__ +/* 117 */ +EXTERN int TkRectInRegion _ANSI_ARGS_((TkRegion rgn, int x, + int y, unsigned int width, + unsigned int height)); +#endif /* __WIN32__ */ +#ifdef MAC_TCL +/* 117 */ +EXTERN int TkRectInRegion _ANSI_ARGS_((TkRegion rgn, int x, + int y, unsigned int width, + unsigned int height)); +#endif /* MAC_TCL */ +#ifdef __WIN32__ +/* 118 */ +EXTERN void TkSetRegion _ANSI_ARGS_((Display* display, GC gc, + TkRegion rgn)); +#endif /* __WIN32__ */ +#ifdef MAC_TCL +/* 118 */ +EXTERN void TkSetRegion _ANSI_ARGS_((Display* display, GC gc, + TkRegion rgn)); +#endif /* MAC_TCL */ +#ifdef __WIN32__ +/* 119 */ +EXTERN void TkUnionRectWithRegion _ANSI_ARGS_((XRectangle* rect, + TkRegion src, TkRegion dr_return)); +#endif /* __WIN32__ */ +#ifdef MAC_TCL +/* 119 */ +EXTERN void TkUnionRectWithRegion _ANSI_ARGS_((XRectangle* rect, + TkRegion src, TkRegion dr_return)); +#endif /* MAC_TCL */ +#ifdef MAC_TCL +/* 120 */ +EXTERN void TkGenerateActivateEvents _ANSI_ARGS_(( + TkWindow * winPtr, int active)); +#endif /* MAC_TCL */ +#ifdef MAC_TCL +/* 121 */ +EXTERN Pixmap TkpCreateNativeBitmap _ANSI_ARGS_((Display * display, + char * source)); +#endif /* MAC_TCL */ +#ifdef MAC_TCL +/* 122 */ +EXTERN void TkpDefineNativeBitmaps _ANSI_ARGS_((void)); +#endif /* MAC_TCL */ +#ifdef MAC_TCL +/* 123 */ +EXTERN unsigned long TkpGetMS _ANSI_ARGS_((void)); +#endif /* MAC_TCL */ +#ifdef MAC_TCL +/* 124 */ +EXTERN Pixmap TkpGetNativeAppBitmap _ANSI_ARGS_((Display * display, + CONST char * name, int * width, int * height)); +#endif /* MAC_TCL */ +#ifdef MAC_TCL +/* 125 */ +EXTERN void TkPointerDeadWindow _ANSI_ARGS_((TkWindow * winPtr)); +#endif /* MAC_TCL */ +#ifdef MAC_TCL +/* 126 */ +EXTERN void TkpSetCapture _ANSI_ARGS_((TkWindow * winPtr)); +#endif /* MAC_TCL */ +#ifdef MAC_TCL +/* 127 */ +EXTERN void TkpSetCursor _ANSI_ARGS_((TkpCursor cursor)); +#endif /* MAC_TCL */ +#ifdef MAC_TCL +/* 128 */ +EXTERN void TkpWmSetState _ANSI_ARGS_((TkWindow * winPtr, + int state)); +#endif /* MAC_TCL */ +/* Slot 129 is reserved */ +#ifdef MAC_TCL +/* 130 */ +EXTERN Window TkGetTransientMaster _ANSI_ARGS_((TkWindow * winPtr)); +#endif /* MAC_TCL */ +#ifdef MAC_TCL +/* 131 */ +EXTERN int TkGenerateButtonEvent _ANSI_ARGS_((int x, int y, + Window window, unsigned int state)); +#endif /* MAC_TCL */ +/* Slot 132 is reserved */ +#ifdef MAC_TCL +/* 133 */ +EXTERN void TkGenWMDestroyEvent _ANSI_ARGS_((Tk_Window tkwin)); +#endif /* MAC_TCL */ +#ifdef MAC_TCL +/* 134 */ +EXTERN void TkGenWMConfigureEvent _ANSI_ARGS_((Tk_Window tkwin, + int x, int y, int width, int height, + int flags)); +#endif /* MAC_TCL */ +/* 135 */ +EXTERN void TkpDrawHighlightBorder _ANSI_ARGS_((Tk_Window tkwin, + GC fgGC, GC bgGC, int highlightWidth, + Drawable drawable)); +/* 136 */ +EXTERN void TkSetFocusWin _ANSI_ARGS_((TkWindow * winPtr, + int force)); +/* 137 */ +EXTERN void TkpSetKeycodeAndState _ANSI_ARGS_((Tk_Window tkwin, + KeySym keySym, XEvent * eventPtr)); +/* 138 */ +EXTERN KeySym TkpGetKeySym _ANSI_ARGS_((TkDisplay * dispPtr, + XEvent * eventPtr)); +/* 139 */ +EXTERN void TkpInitKeymapInfo _ANSI_ARGS_((TkDisplay * dispPtr)); + +typedef struct TkIntStubs { + int magic; + struct TkIntStubHooks *hooks; + + TkWindow * (*tkAllocWindow) _ANSI_ARGS_((TkDisplay * dispPtr, int screenNum, TkWindow * parentPtr)); /* 0 */ + void (*tkBezierPoints) _ANSI_ARGS_((double control[], int numSteps, double * coordPtr)); /* 1 */ + void (*tkBezierScreenPoints) _ANSI_ARGS_((Tk_Canvas canvas, double control[], int numSteps, XPoint * xPointPtr)); /* 2 */ + void (*tkBindDeadWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 3 */ + void (*tkBindEventProc) _ANSI_ARGS_((TkWindow * winPtr, XEvent * eventPtr)); /* 4 */ + void (*tkBindFree) _ANSI_ARGS_((TkMainInfo * mainPtr)); /* 5 */ + void (*tkBindInit) _ANSI_ARGS_((TkMainInfo * mainPtr)); /* 6 */ + void (*tkChangeEventWindow) _ANSI_ARGS_((XEvent * eventPtr, TkWindow * winPtr)); /* 7 */ + int (*tkClipInit) _ANSI_ARGS_((Tcl_Interp * interp, TkDisplay * dispPtr)); /* 8 */ + void (*tkComputeAnchor) _ANSI_ARGS_((Tk_Anchor anchor, Tk_Window tkwin, int padX, int padY, int innerWidth, int innerHeight, int * xPtr, int * yPtr)); /* 9 */ + int (*tkCopyAndGlobalEval) _ANSI_ARGS_((Tcl_Interp * interp, char * script)); /* 10 */ + unsigned long (*tkCreateBindingProcedure) _ANSI_ARGS_((Tcl_Interp * interp, Tk_BindingTable bindingTable, ClientData object, char * eventString, TkBindEvalProc * evalProc, TkBindFreeProc * freeProc, ClientData clientData)); /* 11 */ + TkCursor * (*tkCreateCursorFromData) _ANSI_ARGS_((Tk_Window tkwin, char * source, char * mask, int width, int height, int xHot, int yHot, XColor fg, XColor bg)); /* 12 */ + int (*tkCreateFrame) _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char ** argv, int toplevel, char * appName)); /* 13 */ + Tk_Window (*tkCreateMainWindow) _ANSI_ARGS_((Tcl_Interp * interp, char * screenName, char * baseName)); /* 14 */ + Time (*tkCurrentTime) _ANSI_ARGS_((TkDisplay * dispPtr)); /* 15 */ + void (*tkDeleteAllImages) _ANSI_ARGS_((TkMainInfo * mainPtr)); /* 16 */ + void (*tkDoConfigureNotify) _ANSI_ARGS_((TkWindow * winPtr)); /* 17 */ + void (*tkDrawInsetFocusHighlight) _ANSI_ARGS_((Tk_Window tkwin, GC gc, int width, Drawable drawable, int padding)); /* 18 */ + void (*tkEventDeadWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 19 */ + void (*tkFillPolygon) _ANSI_ARGS_((Tk_Canvas canvas, double * coordPtr, int numPoints, Display * display, Drawable drawable, GC gc, GC outlineGC)); /* 20 */ + int (*tkFindStateNum) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * option, CONST TkStateMap * mapPtr, CONST char * strKey)); /* 21 */ + char * (*tkFindStateString) _ANSI_ARGS_((CONST TkStateMap * mapPtr, int numKey)); /* 22 */ + void (*tkFocusDeadWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 23 */ + int (*tkFocusFilterEvent) _ANSI_ARGS_((TkWindow * winPtr, XEvent * eventPtr)); /* 24 */ + TkWindow * (*tkFocusKeyEvent) _ANSI_ARGS_((TkWindow * winPtr, XEvent * eventPtr)); /* 25 */ + void (*tkFontPkgInit) _ANSI_ARGS_((TkMainInfo * mainPtr)); /* 26 */ + void (*tkFontPkgFree) _ANSI_ARGS_((TkMainInfo * mainPtr)); /* 27 */ + void (*tkFreeBindingTags) _ANSI_ARGS_((TkWindow * winPtr)); /* 28 */ + void (*tkpFreeCursor) _ANSI_ARGS_((TkCursor * cursorPtr)); /* 29 */ + char * (*tkGetBitmapData) _ANSI_ARGS_((Tcl_Interp * interp, char * string, char * fileName, int * widthPtr, int * heightPtr, int * hotXPtr, int * hotYPtr)); /* 30 */ + void (*tkGetButtPoints) _ANSI_ARGS_((double p1[], double p2[], double width, int project, double m1[], double m2[])); /* 31 */ + TkCursor * (*tkGetCursorByName) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tk_Uid string)); /* 32 */ + char * (*tkGetDefaultScreenName) _ANSI_ARGS_((Tcl_Interp * interp, char * screenName)); /* 33 */ + TkDisplay * (*tkGetDisplay) _ANSI_ARGS_((Display * display)); /* 34 */ + int (*tkGetDisplayOf) _ANSI_ARGS_((Tcl_Interp * interp, int objc, Tcl_Obj *CONST objv[], Tk_Window * tkwinPtr)); /* 35 */ + TkWindow * (*tkGetFocusWin) _ANSI_ARGS_((TkWindow * winPtr)); /* 36 */ + int (*tkGetInterpNames) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin)); /* 37 */ + int (*tkGetMiterPoints) _ANSI_ARGS_((double p1[], double p2[], double p3[], double width, double m1[], double m2[])); /* 38 */ + void (*tkGetPointerCoords) _ANSI_ARGS_((Tk_Window tkwin, int * xPtr, int * yPtr)); /* 39 */ + void (*tkGetServerInfo) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin)); /* 40 */ + void (*tkGrabDeadWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 41 */ + int (*tkGrabState) _ANSI_ARGS_((TkWindow * winPtr)); /* 42 */ + void (*tkIncludePoint) _ANSI_ARGS_((Tk_Item * itemPtr, double * pointPtr)); /* 43 */ + void (*tkInOutEvents) _ANSI_ARGS_((XEvent * eventPtr, TkWindow * sourcePtr, TkWindow * destPtr, int leaveType, int enterType, Tcl_QueuePosition position)); /* 44 */ + void (*tkInstallFrameMenu) _ANSI_ARGS_((Tk_Window tkwin)); /* 45 */ + char * (*tkKeysymToString) _ANSI_ARGS_((KeySym keysym)); /* 46 */ + int (*tkLineToArea) _ANSI_ARGS_((double end1Ptr[], double end2Ptr[], double rectPtr[])); /* 47 */ + double (*tkLineToPoint) _ANSI_ARGS_((double end1Ptr[], double end2Ptr[], double pointPtr[])); /* 48 */ + int (*tkMakeBezierCurve) _ANSI_ARGS_((Tk_Canvas canvas, double * pointPtr, int numPoints, int numSteps, XPoint xPoints[], double dblPoints[])); /* 49 */ + void (*tkMakeBezierPostscript) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Canvas canvas, double * pointPtr, int numPoints)); /* 50 */ + void (*tkOptionClassChanged) _ANSI_ARGS_((TkWindow * winPtr)); /* 51 */ + void (*tkOptionDeadWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 52 */ + int (*tkOvalToArea) _ANSI_ARGS_((double * ovalPtr, double * rectPtr)); /* 53 */ + double (*tkOvalToPoint) _ANSI_ARGS_((double ovalPtr[], double width, int filled, double pointPtr[])); /* 54 */ + int (*tkpChangeFocus) _ANSI_ARGS_((TkWindow * winPtr, int force)); /* 55 */ + void (*tkpCloseDisplay) _ANSI_ARGS_((TkDisplay * dispPtr)); /* 56 */ + void (*tkpClaimFocus) _ANSI_ARGS_((TkWindow * topLevelPtr, int force)); /* 57 */ + void (*tkpDisplayWarning) _ANSI_ARGS_((char * msg, char * title)); /* 58 */ + void (*tkpGetAppName) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_DString * name)); /* 59 */ + TkWindow * (*tkpGetOtherWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 60 */ + TkWindow * (*tkpGetWrapperWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 61 */ + int (*tkpInit) _ANSI_ARGS_((Tcl_Interp * interp)); /* 62 */ + void (*tkpInitializeMenuBindings) _ANSI_ARGS_((Tcl_Interp * interp, Tk_BindingTable bindingTable)); /* 63 */ + void (*tkpMakeContainer) _ANSI_ARGS_((Tk_Window tkwin)); /* 64 */ + void (*tkpMakeMenuWindow) _ANSI_ARGS_((Tk_Window tkwin, int transient)); /* 65 */ + Window (*tkpMakeWindow) _ANSI_ARGS_((TkWindow * winPtr, Window parent)); /* 66 */ + void (*tkpMenuNotifyToplevelCreate) _ANSI_ARGS_((Tcl_Interp * interp1, char * menuName)); /* 67 */ + TkDisplay * (*tkpOpenDisplay) _ANSI_ARGS_((char * display_name)); /* 68 */ + int (*tkPointerEvent) _ANSI_ARGS_((XEvent * eventPtr, TkWindow * winPtr)); /* 69 */ + int (*tkPolygonToArea) _ANSI_ARGS_((double * polyPtr, int numPoints, double * rectPtr)); /* 70 */ + double (*tkPolygonToPoint) _ANSI_ARGS_((double * polyPtr, int numPoints, double * pointPtr)); /* 71 */ + int (*tkPositionInTree) _ANSI_ARGS_((TkWindow * winPtr, TkWindow * treePtr)); /* 72 */ + void (*tkpRedirectKeyEvent) _ANSI_ARGS_((TkWindow * winPtr, XEvent * eventPtr)); /* 73 */ + void (*tkpSetMainMenubar) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * menuName)); /* 74 */ + int (*tkpUseWindow) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * string)); /* 75 */ + int (*tkpWindowWasRecentlyDeleted) _ANSI_ARGS_((Window win, TkDisplay * dispPtr)); /* 76 */ + void (*tkQueueEventForAllChildren) _ANSI_ARGS_((TkWindow * winPtr, XEvent * eventPtr)); /* 77 */ + int (*tkReadBitmapFile) _ANSI_ARGS_((Display* display, Drawable d, CONST char* filename, unsigned int* width_return, unsigned int* height_return, Pixmap* bitmap_return, int* x_hot_return, int* y_hot_return)); /* 78 */ + int (*tkScrollWindow) _ANSI_ARGS_((Tk_Window tkwin, GC gc, int x, int y, int width, int height, int dx, int dy, TkRegion damageRgn)); /* 79 */ + void (*tkSelDeadWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 80 */ + void (*tkSelEventProc) _ANSI_ARGS_((Tk_Window tkwin, XEvent * eventPtr)); /* 81 */ + void (*tkSelInit) _ANSI_ARGS_((Tk_Window tkwin)); /* 82 */ + void (*tkSelPropProc) _ANSI_ARGS_((XEvent * eventPtr)); /* 83 */ + void (*tkSetClassProcs) _ANSI_ARGS_((Tk_Window tkwin, TkClassProcs * procs, ClientData instanceData)); /* 84 */ + void (*tkSetWindowMenuBar) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, char * oldMenuName, char * menuName)); /* 85 */ + KeySym (*tkStringToKeysym) _ANSI_ARGS_((char * name)); /* 86 */ + int (*tkThickPolyLineToArea) _ANSI_ARGS_((double * coordPtr, int numPoints, double width, int capStyle, int joinStyle, double * rectPtr)); /* 87 */ + void (*tkWmAddToColormapWindows) _ANSI_ARGS_((TkWindow * winPtr)); /* 88 */ + void (*tkWmDeadWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 89 */ + TkWindow * (*tkWmFocusToplevel) _ANSI_ARGS_((TkWindow * winPtr)); /* 90 */ + void (*tkWmMapWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 91 */ + void (*tkWmNewWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 92 */ + void (*tkWmProtocolEventProc) _ANSI_ARGS_((TkWindow * winPtr, XEvent * evenvPtr)); /* 93 */ + void (*tkWmRemoveFromColormapWindows) _ANSI_ARGS_((TkWindow * winPtr)); /* 94 */ + void (*tkWmRestackToplevel) _ANSI_ARGS_((TkWindow * winPtr, int aboveBelow, TkWindow * otherPtr)); /* 95 */ + void (*tkWmSetClass) _ANSI_ARGS_((TkWindow * winPtr)); /* 96 */ + void (*tkWmUnmapWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 97 */ + Tcl_Obj * (*tkDebugBitmap) _ANSI_ARGS_((Tk_Window tkwin, char * name)); /* 98 */ + Tcl_Obj * (*tkDebugBorder) _ANSI_ARGS_((Tk_Window tkwin, char * name)); /* 99 */ + Tcl_Obj * (*tkDebugCursor) _ANSI_ARGS_((Tk_Window tkwin, char * name)); /* 100 */ + Tcl_Obj * (*tkDebugColor) _ANSI_ARGS_((Tk_Window tkwin, char * name)); /* 101 */ + Tcl_Obj * (*tkDebugConfig) _ANSI_ARGS_((Tcl_Interp * interp, Tk_OptionTable table)); /* 102 */ + Tcl_Obj * (*tkDebugFont) _ANSI_ARGS_((Tk_Window tkwin, char * name)); /* 103 */ + int (*tkFindStateNumObj) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * optionPtr, CONST TkStateMap * mapPtr, Tcl_Obj * keyPtr)); /* 104 */ + Tcl_HashTable * (*tkGetBitmapPredefTable) _ANSI_ARGS_((void)); /* 105 */ + TkDisplay * (*tkGetDisplayList) _ANSI_ARGS_((void)); /* 106 */ + TkMainInfo * (*tkGetMainInfoList) _ANSI_ARGS_((void)); /* 107 */ + int (*tkGetWindowFromObj) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, Tcl_Obj * objPtr, Tk_Window * windowPtr)); /* 108 */ + char * (*tkpGetString) _ANSI_ARGS_((TkWindow * winPtr, XEvent * eventPtr, Tcl_DString * dsPtr)); /* 109 */ + void (*tkpGetSubFonts) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Font tkfont)); /* 110 */ + Tcl_Obj * (*tkpGetSystemDefault) _ANSI_ARGS_((Tk_Window tkwin, char * dbName, char * className)); /* 111 */ + void (*tkpMenuThreadInit) _ANSI_ARGS_((void)); /* 112 */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved113; +#endif /* UNIX */ +#ifdef __WIN32__ + void (*tkClipBox) _ANSI_ARGS_((TkRegion rgn, XRectangle* rect_return)); /* 113 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkClipBox) _ANSI_ARGS_((TkRegion rgn, XRectangle* rect_return)); /* 113 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved114; +#endif /* UNIX */ +#ifdef __WIN32__ + TkRegion (*tkCreateRegion) _ANSI_ARGS_((void)); /* 114 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkRegion (*tkCreateRegion) _ANSI_ARGS_((void)); /* 114 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved115; +#endif /* UNIX */ +#ifdef __WIN32__ + void (*tkDestroyRegion) _ANSI_ARGS_((TkRegion rgn)); /* 115 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkDestroyRegion) _ANSI_ARGS_((TkRegion rgn)); /* 115 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved116; +#endif /* UNIX */ +#ifdef __WIN32__ + void (*tkIntersectRegion) _ANSI_ARGS_((TkRegion sra, TkRegion srcb, TkRegion dr_return)); /* 116 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkIntersectRegion) _ANSI_ARGS_((TkRegion sra, TkRegion srcb, TkRegion dr_return)); /* 116 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved117; +#endif /* UNIX */ +#ifdef __WIN32__ + int (*tkRectInRegion) _ANSI_ARGS_((TkRegion rgn, int x, int y, unsigned int width, unsigned int height)); /* 117 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + int (*tkRectInRegion) _ANSI_ARGS_((TkRegion rgn, int x, int y, unsigned int width, unsigned int height)); /* 117 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved118; +#endif /* UNIX */ +#ifdef __WIN32__ + void (*tkSetRegion) _ANSI_ARGS_((Display* display, GC gc, TkRegion rgn)); /* 118 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkSetRegion) _ANSI_ARGS_((Display* display, GC gc, TkRegion rgn)); /* 118 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved119; +#endif /* UNIX */ +#ifdef __WIN32__ + void (*tkUnionRectWithRegion) _ANSI_ARGS_((XRectangle* rect, TkRegion src, TkRegion dr_return)); /* 119 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkUnionRectWithRegion) _ANSI_ARGS_((XRectangle* rect, TkRegion src, TkRegion dr_return)); /* 119 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved120; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved120; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkGenerateActivateEvents) _ANSI_ARGS_((TkWindow * winPtr, int active)); /* 120 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved121; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved121; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + Pixmap (*tkpCreateNativeBitmap) _ANSI_ARGS_((Display * display, char * source)); /* 121 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved122; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved122; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkpDefineNativeBitmaps) _ANSI_ARGS_((void)); /* 122 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved123; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved123; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + unsigned long (*tkpGetMS) _ANSI_ARGS_((void)); /* 123 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved124; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved124; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + Pixmap (*tkpGetNativeAppBitmap) _ANSI_ARGS_((Display * display, CONST char * name, int * width, int * height)); /* 124 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved125; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved125; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkPointerDeadWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 125 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved126; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved126; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkpSetCapture) _ANSI_ARGS_((TkWindow * winPtr)); /* 126 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved127; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved127; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkpSetCursor) _ANSI_ARGS_((TkpCursor cursor)); /* 127 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved128; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved128; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkpWmSetState) _ANSI_ARGS_((TkWindow * winPtr, int state)); /* 128 */ +#endif /* MAC_TCL */ + void *reserved129; +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved130; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved130; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + Window (*tkGetTransientMaster) _ANSI_ARGS_((TkWindow * winPtr)); /* 130 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved131; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved131; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + int (*tkGenerateButtonEvent) _ANSI_ARGS_((int x, int y, Window window, unsigned int state)); /* 131 */ +#endif /* MAC_TCL */ + void *reserved132; +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved133; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved133; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkGenWMDestroyEvent) _ANSI_ARGS_((Tk_Window tkwin)); /* 133 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved134; +#endif /* UNIX */ +#ifdef __WIN32__ + void *reserved134; +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkGenWMConfigureEvent) _ANSI_ARGS_((Tk_Window tkwin, int x, int y, int width, int height, int flags)); /* 134 */ +#endif /* MAC_TCL */ + void (*tkpDrawHighlightBorder) _ANSI_ARGS_((Tk_Window tkwin, GC fgGC, GC bgGC, int highlightWidth, Drawable drawable)); /* 135 */ + void (*tkSetFocusWin) _ANSI_ARGS_((TkWindow * winPtr, int force)); /* 136 */ + void (*tkpSetKeycodeAndState) _ANSI_ARGS_((Tk_Window tkwin, KeySym keySym, XEvent * eventPtr)); /* 137 */ + KeySym (*tkpGetKeySym) _ANSI_ARGS_((TkDisplay * dispPtr, XEvent * eventPtr)); /* 138 */ + void (*tkpInitKeymapInfo) _ANSI_ARGS_((TkDisplay * dispPtr)); /* 139 */ +} TkIntStubs; + +#ifdef __cplusplus +extern "C" { +#endif +extern TkIntStubs *tkIntStubsPtr; +#ifdef __cplusplus +} +#endif + +#if defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) + +/* + * Inline function declarations: + */ + +#ifndef TkAllocWindow +#define TkAllocWindow \ + (tkIntStubsPtr->tkAllocWindow) /* 0 */ +#endif +#ifndef TkBezierPoints +#define TkBezierPoints \ + (tkIntStubsPtr->tkBezierPoints) /* 1 */ +#endif +#ifndef TkBezierScreenPoints +#define TkBezierScreenPoints \ + (tkIntStubsPtr->tkBezierScreenPoints) /* 2 */ +#endif +#ifndef TkBindDeadWindow +#define TkBindDeadWindow \ + (tkIntStubsPtr->tkBindDeadWindow) /* 3 */ +#endif +#ifndef TkBindEventProc +#define TkBindEventProc \ + (tkIntStubsPtr->tkBindEventProc) /* 4 */ +#endif +#ifndef TkBindFree +#define TkBindFree \ + (tkIntStubsPtr->tkBindFree) /* 5 */ +#endif +#ifndef TkBindInit +#define TkBindInit \ + (tkIntStubsPtr->tkBindInit) /* 6 */ +#endif +#ifndef TkChangeEventWindow +#define TkChangeEventWindow \ + (tkIntStubsPtr->tkChangeEventWindow) /* 7 */ +#endif +#ifndef TkClipInit +#define TkClipInit \ + (tkIntStubsPtr->tkClipInit) /* 8 */ +#endif +#ifndef TkComputeAnchor +#define TkComputeAnchor \ + (tkIntStubsPtr->tkComputeAnchor) /* 9 */ +#endif +#ifndef TkCopyAndGlobalEval +#define TkCopyAndGlobalEval \ + (tkIntStubsPtr->tkCopyAndGlobalEval) /* 10 */ +#endif +#ifndef TkCreateBindingProcedure +#define TkCreateBindingProcedure \ + (tkIntStubsPtr->tkCreateBindingProcedure) /* 11 */ +#endif +#ifndef TkCreateCursorFromData +#define TkCreateCursorFromData \ + (tkIntStubsPtr->tkCreateCursorFromData) /* 12 */ +#endif +#ifndef TkCreateFrame +#define TkCreateFrame \ + (tkIntStubsPtr->tkCreateFrame) /* 13 */ +#endif +#ifndef TkCreateMainWindow +#define TkCreateMainWindow \ + (tkIntStubsPtr->tkCreateMainWindow) /* 14 */ +#endif +#ifndef TkCurrentTime +#define TkCurrentTime \ + (tkIntStubsPtr->tkCurrentTime) /* 15 */ +#endif +#ifndef TkDeleteAllImages +#define TkDeleteAllImages \ + (tkIntStubsPtr->tkDeleteAllImages) /* 16 */ +#endif +#ifndef TkDoConfigureNotify +#define TkDoConfigureNotify \ + (tkIntStubsPtr->tkDoConfigureNotify) /* 17 */ +#endif +#ifndef TkDrawInsetFocusHighlight +#define TkDrawInsetFocusHighlight \ + (tkIntStubsPtr->tkDrawInsetFocusHighlight) /* 18 */ +#endif +#ifndef TkEventDeadWindow +#define TkEventDeadWindow \ + (tkIntStubsPtr->tkEventDeadWindow) /* 19 */ +#endif +#ifndef TkFillPolygon +#define TkFillPolygon \ + (tkIntStubsPtr->tkFillPolygon) /* 20 */ +#endif +#ifndef TkFindStateNum +#define TkFindStateNum \ + (tkIntStubsPtr->tkFindStateNum) /* 21 */ +#endif +#ifndef TkFindStateString +#define TkFindStateString \ + (tkIntStubsPtr->tkFindStateString) /* 22 */ +#endif +#ifndef TkFocusDeadWindow +#define TkFocusDeadWindow \ + (tkIntStubsPtr->tkFocusDeadWindow) /* 23 */ +#endif +#ifndef TkFocusFilterEvent +#define TkFocusFilterEvent \ + (tkIntStubsPtr->tkFocusFilterEvent) /* 24 */ +#endif +#ifndef TkFocusKeyEvent +#define TkFocusKeyEvent \ + (tkIntStubsPtr->tkFocusKeyEvent) /* 25 */ +#endif +#ifndef TkFontPkgInit +#define TkFontPkgInit \ + (tkIntStubsPtr->tkFontPkgInit) /* 26 */ +#endif +#ifndef TkFontPkgFree +#define TkFontPkgFree \ + (tkIntStubsPtr->tkFontPkgFree) /* 27 */ +#endif +#ifndef TkFreeBindingTags +#define TkFreeBindingTags \ + (tkIntStubsPtr->tkFreeBindingTags) /* 28 */ +#endif +#ifndef TkpFreeCursor +#define TkpFreeCursor \ + (tkIntStubsPtr->tkpFreeCursor) /* 29 */ +#endif +#ifndef TkGetBitmapData +#define TkGetBitmapData \ + (tkIntStubsPtr->tkGetBitmapData) /* 30 */ +#endif +#ifndef TkGetButtPoints +#define TkGetButtPoints \ + (tkIntStubsPtr->tkGetButtPoints) /* 31 */ +#endif +#ifndef TkGetCursorByName +#define TkGetCursorByName \ + (tkIntStubsPtr->tkGetCursorByName) /* 32 */ +#endif +#ifndef TkGetDefaultScreenName +#define TkGetDefaultScreenName \ + (tkIntStubsPtr->tkGetDefaultScreenName) /* 33 */ +#endif +#ifndef TkGetDisplay +#define TkGetDisplay \ + (tkIntStubsPtr->tkGetDisplay) /* 34 */ +#endif +#ifndef TkGetDisplayOf +#define TkGetDisplayOf \ + (tkIntStubsPtr->tkGetDisplayOf) /* 35 */ +#endif +#ifndef TkGetFocusWin +#define TkGetFocusWin \ + (tkIntStubsPtr->tkGetFocusWin) /* 36 */ +#endif +#ifndef TkGetInterpNames +#define TkGetInterpNames \ + (tkIntStubsPtr->tkGetInterpNames) /* 37 */ +#endif +#ifndef TkGetMiterPoints +#define TkGetMiterPoints \ + (tkIntStubsPtr->tkGetMiterPoints) /* 38 */ +#endif +#ifndef TkGetPointerCoords +#define TkGetPointerCoords \ + (tkIntStubsPtr->tkGetPointerCoords) /* 39 */ +#endif +#ifndef TkGetServerInfo +#define TkGetServerInfo \ + (tkIntStubsPtr->tkGetServerInfo) /* 40 */ +#endif +#ifndef TkGrabDeadWindow +#define TkGrabDeadWindow \ + (tkIntStubsPtr->tkGrabDeadWindow) /* 41 */ +#endif +#ifndef TkGrabState +#define TkGrabState \ + (tkIntStubsPtr->tkGrabState) /* 42 */ +#endif +#ifndef TkIncludePoint +#define TkIncludePoint \ + (tkIntStubsPtr->tkIncludePoint) /* 43 */ +#endif +#ifndef TkInOutEvents +#define TkInOutEvents \ + (tkIntStubsPtr->tkInOutEvents) /* 44 */ +#endif +#ifndef TkInstallFrameMenu +#define TkInstallFrameMenu \ + (tkIntStubsPtr->tkInstallFrameMenu) /* 45 */ +#endif +#ifndef TkKeysymToString +#define TkKeysymToString \ + (tkIntStubsPtr->tkKeysymToString) /* 46 */ +#endif +#ifndef TkLineToArea +#define TkLineToArea \ + (tkIntStubsPtr->tkLineToArea) /* 47 */ +#endif +#ifndef TkLineToPoint +#define TkLineToPoint \ + (tkIntStubsPtr->tkLineToPoint) /* 48 */ +#endif +#ifndef TkMakeBezierCurve +#define TkMakeBezierCurve \ + (tkIntStubsPtr->tkMakeBezierCurve) /* 49 */ +#endif +#ifndef TkMakeBezierPostscript +#define TkMakeBezierPostscript \ + (tkIntStubsPtr->tkMakeBezierPostscript) /* 50 */ +#endif +#ifndef TkOptionClassChanged +#define TkOptionClassChanged \ + (tkIntStubsPtr->tkOptionClassChanged) /* 51 */ +#endif +#ifndef TkOptionDeadWindow +#define TkOptionDeadWindow \ + (tkIntStubsPtr->tkOptionDeadWindow) /* 52 */ +#endif +#ifndef TkOvalToArea +#define TkOvalToArea \ + (tkIntStubsPtr->tkOvalToArea) /* 53 */ +#endif +#ifndef TkOvalToPoint +#define TkOvalToPoint \ + (tkIntStubsPtr->tkOvalToPoint) /* 54 */ +#endif +#ifndef TkpChangeFocus +#define TkpChangeFocus \ + (tkIntStubsPtr->tkpChangeFocus) /* 55 */ +#endif +#ifndef TkpCloseDisplay +#define TkpCloseDisplay \ + (tkIntStubsPtr->tkpCloseDisplay) /* 56 */ +#endif +#ifndef TkpClaimFocus +#define TkpClaimFocus \ + (tkIntStubsPtr->tkpClaimFocus) /* 57 */ +#endif +#ifndef TkpDisplayWarning +#define TkpDisplayWarning \ + (tkIntStubsPtr->tkpDisplayWarning) /* 58 */ +#endif +#ifndef TkpGetAppName +#define TkpGetAppName \ + (tkIntStubsPtr->tkpGetAppName) /* 59 */ +#endif +#ifndef TkpGetOtherWindow +#define TkpGetOtherWindow \ + (tkIntStubsPtr->tkpGetOtherWindow) /* 60 */ +#endif +#ifndef TkpGetWrapperWindow +#define TkpGetWrapperWindow \ + (tkIntStubsPtr->tkpGetWrapperWindow) /* 61 */ +#endif +#ifndef TkpInit +#define TkpInit \ + (tkIntStubsPtr->tkpInit) /* 62 */ +#endif +#ifndef TkpInitializeMenuBindings +#define TkpInitializeMenuBindings \ + (tkIntStubsPtr->tkpInitializeMenuBindings) /* 63 */ +#endif +#ifndef TkpMakeContainer +#define TkpMakeContainer \ + (tkIntStubsPtr->tkpMakeContainer) /* 64 */ +#endif +#ifndef TkpMakeMenuWindow +#define TkpMakeMenuWindow \ + (tkIntStubsPtr->tkpMakeMenuWindow) /* 65 */ +#endif +#ifndef TkpMakeWindow +#define TkpMakeWindow \ + (tkIntStubsPtr->tkpMakeWindow) /* 66 */ +#endif +#ifndef TkpMenuNotifyToplevelCreate +#define TkpMenuNotifyToplevelCreate \ + (tkIntStubsPtr->tkpMenuNotifyToplevelCreate) /* 67 */ +#endif +#ifndef TkpOpenDisplay +#define TkpOpenDisplay \ + (tkIntStubsPtr->tkpOpenDisplay) /* 68 */ +#endif +#ifndef TkPointerEvent +#define TkPointerEvent \ + (tkIntStubsPtr->tkPointerEvent) /* 69 */ +#endif +#ifndef TkPolygonToArea +#define TkPolygonToArea \ + (tkIntStubsPtr->tkPolygonToArea) /* 70 */ +#endif +#ifndef TkPolygonToPoint +#define TkPolygonToPoint \ + (tkIntStubsPtr->tkPolygonToPoint) /* 71 */ +#endif +#ifndef TkPositionInTree +#define TkPositionInTree \ + (tkIntStubsPtr->tkPositionInTree) /* 72 */ +#endif +#ifndef TkpRedirectKeyEvent +#define TkpRedirectKeyEvent \ + (tkIntStubsPtr->tkpRedirectKeyEvent) /* 73 */ +#endif +#ifndef TkpSetMainMenubar +#define TkpSetMainMenubar \ + (tkIntStubsPtr->tkpSetMainMenubar) /* 74 */ +#endif +#ifndef TkpUseWindow +#define TkpUseWindow \ + (tkIntStubsPtr->tkpUseWindow) /* 75 */ +#endif +#ifndef TkpWindowWasRecentlyDeleted +#define TkpWindowWasRecentlyDeleted \ + (tkIntStubsPtr->tkpWindowWasRecentlyDeleted) /* 76 */ +#endif +#ifndef TkQueueEventForAllChildren +#define TkQueueEventForAllChildren \ + (tkIntStubsPtr->tkQueueEventForAllChildren) /* 77 */ +#endif +#ifndef TkReadBitmapFile +#define TkReadBitmapFile \ + (tkIntStubsPtr->tkReadBitmapFile) /* 78 */ +#endif +#ifndef TkScrollWindow +#define TkScrollWindow \ + (tkIntStubsPtr->tkScrollWindow) /* 79 */ +#endif +#ifndef TkSelDeadWindow +#define TkSelDeadWindow \ + (tkIntStubsPtr->tkSelDeadWindow) /* 80 */ +#endif +#ifndef TkSelEventProc +#define TkSelEventProc \ + (tkIntStubsPtr->tkSelEventProc) /* 81 */ +#endif +#ifndef TkSelInit +#define TkSelInit \ + (tkIntStubsPtr->tkSelInit) /* 82 */ +#endif +#ifndef TkSelPropProc +#define TkSelPropProc \ + (tkIntStubsPtr->tkSelPropProc) /* 83 */ +#endif +#ifndef TkSetClassProcs +#define TkSetClassProcs \ + (tkIntStubsPtr->tkSetClassProcs) /* 84 */ +#endif +#ifndef TkSetWindowMenuBar +#define TkSetWindowMenuBar \ + (tkIntStubsPtr->tkSetWindowMenuBar) /* 85 */ +#endif +#ifndef TkStringToKeysym +#define TkStringToKeysym \ + (tkIntStubsPtr->tkStringToKeysym) /* 86 */ +#endif +#ifndef TkThickPolyLineToArea +#define TkThickPolyLineToArea \ + (tkIntStubsPtr->tkThickPolyLineToArea) /* 87 */ +#endif +#ifndef TkWmAddToColormapWindows +#define TkWmAddToColormapWindows \ + (tkIntStubsPtr->tkWmAddToColormapWindows) /* 88 */ +#endif +#ifndef TkWmDeadWindow +#define TkWmDeadWindow \ + (tkIntStubsPtr->tkWmDeadWindow) /* 89 */ +#endif +#ifndef TkWmFocusToplevel +#define TkWmFocusToplevel \ + (tkIntStubsPtr->tkWmFocusToplevel) /* 90 */ +#endif +#ifndef TkWmMapWindow +#define TkWmMapWindow \ + (tkIntStubsPtr->tkWmMapWindow) /* 91 */ +#endif +#ifndef TkWmNewWindow +#define TkWmNewWindow \ + (tkIntStubsPtr->tkWmNewWindow) /* 92 */ +#endif +#ifndef TkWmProtocolEventProc +#define TkWmProtocolEventProc \ + (tkIntStubsPtr->tkWmProtocolEventProc) /* 93 */ +#endif +#ifndef TkWmRemoveFromColormapWindows +#define TkWmRemoveFromColormapWindows \ + (tkIntStubsPtr->tkWmRemoveFromColormapWindows) /* 94 */ +#endif +#ifndef TkWmRestackToplevel +#define TkWmRestackToplevel \ + (tkIntStubsPtr->tkWmRestackToplevel) /* 95 */ +#endif +#ifndef TkWmSetClass +#define TkWmSetClass \ + (tkIntStubsPtr->tkWmSetClass) /* 96 */ +#endif +#ifndef TkWmUnmapWindow +#define TkWmUnmapWindow \ + (tkIntStubsPtr->tkWmUnmapWindow) /* 97 */ +#endif +#ifndef TkDebugBitmap +#define TkDebugBitmap \ + (tkIntStubsPtr->tkDebugBitmap) /* 98 */ +#endif +#ifndef TkDebugBorder +#define TkDebugBorder \ + (tkIntStubsPtr->tkDebugBorder) /* 99 */ +#endif +#ifndef TkDebugCursor +#define TkDebugCursor \ + (tkIntStubsPtr->tkDebugCursor) /* 100 */ +#endif +#ifndef TkDebugColor +#define TkDebugColor \ + (tkIntStubsPtr->tkDebugColor) /* 101 */ +#endif +#ifndef TkDebugConfig +#define TkDebugConfig \ + (tkIntStubsPtr->tkDebugConfig) /* 102 */ +#endif +#ifndef TkDebugFont +#define TkDebugFont \ + (tkIntStubsPtr->tkDebugFont) /* 103 */ +#endif +#ifndef TkFindStateNumObj +#define TkFindStateNumObj \ + (tkIntStubsPtr->tkFindStateNumObj) /* 104 */ +#endif +#ifndef TkGetBitmapPredefTable +#define TkGetBitmapPredefTable \ + (tkIntStubsPtr->tkGetBitmapPredefTable) /* 105 */ +#endif +#ifndef TkGetDisplayList +#define TkGetDisplayList \ + (tkIntStubsPtr->tkGetDisplayList) /* 106 */ +#endif +#ifndef TkGetMainInfoList +#define TkGetMainInfoList \ + (tkIntStubsPtr->tkGetMainInfoList) /* 107 */ +#endif +#ifndef TkGetWindowFromObj +#define TkGetWindowFromObj \ + (tkIntStubsPtr->tkGetWindowFromObj) /* 108 */ +#endif +#ifndef TkpGetString +#define TkpGetString \ + (tkIntStubsPtr->tkpGetString) /* 109 */ +#endif +#ifndef TkpGetSubFonts +#define TkpGetSubFonts \ + (tkIntStubsPtr->tkpGetSubFonts) /* 110 */ +#endif +#ifndef TkpGetSystemDefault +#define TkpGetSystemDefault \ + (tkIntStubsPtr->tkpGetSystemDefault) /* 111 */ +#endif +#ifndef TkpMenuThreadInit +#define TkpMenuThreadInit \ + (tkIntStubsPtr->tkpMenuThreadInit) /* 112 */ +#endif +#ifdef __WIN32__ +#ifndef TkClipBox +#define TkClipBox \ + (tkIntStubsPtr->tkClipBox) /* 113 */ +#endif +#endif /* __WIN32__ */ +#ifdef MAC_TCL +#ifndef TkClipBox +#define TkClipBox \ + (tkIntStubsPtr->tkClipBox) /* 113 */ +#endif +#endif /* MAC_TCL */ +#ifdef __WIN32__ +#ifndef TkCreateRegion +#define TkCreateRegion \ + (tkIntStubsPtr->tkCreateRegion) /* 114 */ +#endif +#endif /* __WIN32__ */ +#ifdef MAC_TCL +#ifndef TkCreateRegion +#define TkCreateRegion \ + (tkIntStubsPtr->tkCreateRegion) /* 114 */ +#endif +#endif /* MAC_TCL */ +#ifdef __WIN32__ +#ifndef TkDestroyRegion +#define TkDestroyRegion \ + (tkIntStubsPtr->tkDestroyRegion) /* 115 */ +#endif +#endif /* __WIN32__ */ +#ifdef MAC_TCL +#ifndef TkDestroyRegion +#define TkDestroyRegion \ + (tkIntStubsPtr->tkDestroyRegion) /* 115 */ +#endif +#endif /* MAC_TCL */ +#ifdef __WIN32__ +#ifndef TkIntersectRegion +#define TkIntersectRegion \ + (tkIntStubsPtr->tkIntersectRegion) /* 116 */ +#endif +#endif /* __WIN32__ */ +#ifdef MAC_TCL +#ifndef TkIntersectRegion +#define TkIntersectRegion \ + (tkIntStubsPtr->tkIntersectRegion) /* 116 */ +#endif +#endif /* MAC_TCL */ +#ifdef __WIN32__ +#ifndef TkRectInRegion +#define TkRectInRegion \ + (tkIntStubsPtr->tkRectInRegion) /* 117 */ +#endif +#endif /* __WIN32__ */ +#ifdef MAC_TCL +#ifndef TkRectInRegion +#define TkRectInRegion \ + (tkIntStubsPtr->tkRectInRegion) /* 117 */ +#endif +#endif /* MAC_TCL */ +#ifdef __WIN32__ +#ifndef TkSetRegion +#define TkSetRegion \ + (tkIntStubsPtr->tkSetRegion) /* 118 */ +#endif +#endif /* __WIN32__ */ +#ifdef MAC_TCL +#ifndef TkSetRegion +#define TkSetRegion \ + (tkIntStubsPtr->tkSetRegion) /* 118 */ +#endif +#endif /* MAC_TCL */ +#ifdef __WIN32__ +#ifndef TkUnionRectWithRegion +#define TkUnionRectWithRegion \ + (tkIntStubsPtr->tkUnionRectWithRegion) /* 119 */ +#endif +#endif /* __WIN32__ */ +#ifdef MAC_TCL +#ifndef TkUnionRectWithRegion +#define TkUnionRectWithRegion \ + (tkIntStubsPtr->tkUnionRectWithRegion) /* 119 */ +#endif +#endif /* MAC_TCL */ + +#ifdef MAC_TCL +#ifndef TkGenerateActivateEvents +#define TkGenerateActivateEvents \ + (tkIntStubsPtr->tkGenerateActivateEvents) /* 120 */ +#endif +#endif /* MAC_TCL */ +#ifdef MAC_TCL +#ifndef TkpCreateNativeBitmap +#define TkpCreateNativeBitmap \ + (tkIntStubsPtr->tkpCreateNativeBitmap) /* 121 */ +#endif +#endif /* MAC_TCL */ +#ifdef MAC_TCL +#ifndef TkpDefineNativeBitmaps +#define TkpDefineNativeBitmaps \ + (tkIntStubsPtr->tkpDefineNativeBitmaps) /* 122 */ +#endif +#endif /* MAC_TCL */ +#ifdef MAC_TCL +#ifndef TkpGetMS +#define TkpGetMS \ + (tkIntStubsPtr->tkpGetMS) /* 123 */ +#endif +#endif /* MAC_TCL */ +#ifdef MAC_TCL +#ifndef TkpGetNativeAppBitmap +#define TkpGetNativeAppBitmap \ + (tkIntStubsPtr->tkpGetNativeAppBitmap) /* 124 */ +#endif +#endif /* MAC_TCL */ +#ifdef MAC_TCL +#ifndef TkPointerDeadWindow +#define TkPointerDeadWindow \ + (tkIntStubsPtr->tkPointerDeadWindow) /* 125 */ +#endif +#endif /* MAC_TCL */ +#ifdef MAC_TCL +#ifndef TkpSetCapture +#define TkpSetCapture \ + (tkIntStubsPtr->tkpSetCapture) /* 126 */ +#endif +#endif /* MAC_TCL */ +#ifdef MAC_TCL +#ifndef TkpSetCursor +#define TkpSetCursor \ + (tkIntStubsPtr->tkpSetCursor) /* 127 */ +#endif +#endif /* MAC_TCL */ +#ifdef MAC_TCL +#ifndef TkpWmSetState +#define TkpWmSetState \ + (tkIntStubsPtr->tkpWmSetState) /* 128 */ +#endif +#endif /* MAC_TCL */ +/* Slot 129 is reserved */ +#ifdef MAC_TCL +#ifndef TkGetTransientMaster +#define TkGetTransientMaster \ + (tkIntStubsPtr->tkGetTransientMaster) /* 130 */ +#endif +#endif /* MAC_TCL */ +#ifdef MAC_TCL +#ifndef TkGenerateButtonEvent +#define TkGenerateButtonEvent \ + (tkIntStubsPtr->tkGenerateButtonEvent) /* 131 */ +#endif +#endif /* MAC_TCL */ +/* Slot 132 is reserved */ +#ifdef MAC_TCL +#ifndef TkGenWMDestroyEvent +#define TkGenWMDestroyEvent \ + (tkIntStubsPtr->tkGenWMDestroyEvent) /* 133 */ +#endif +#endif /* MAC_TCL */ +#ifdef MAC_TCL +#ifndef TkGenWMConfigureEvent +#define TkGenWMConfigureEvent \ + (tkIntStubsPtr->tkGenWMConfigureEvent) /* 134 */ +#endif +#endif /* MAC_TCL */ +#ifndef TkpDrawHighlightBorder +#define TkpDrawHighlightBorder \ + (tkIntStubsPtr->tkpDrawHighlightBorder) /* 135 */ +#endif +#ifndef TkSetFocusWin +#define TkSetFocusWin \ + (tkIntStubsPtr->tkSetFocusWin) /* 136 */ +#endif +#ifndef TkpSetKeycodeAndState +#define TkpSetKeycodeAndState \ + (tkIntStubsPtr->tkpSetKeycodeAndState) /* 137 */ +#endif +#ifndef TkpGetKeySym +#define TkpGetKeySym \ + (tkIntStubsPtr->tkpGetKeySym) /* 138 */ +#endif +#ifndef TkpInitKeymapInfo +#define TkpInitKeymapInfo \ + (tkIntStubsPtr->tkpInitKeymapInfo) /* 139 */ +#endif + +#endif /* defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) */ + +/* !END!: Do not edit above this line. */ + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#endif /* _TKINTDECLS */ + + diff --git a/tk/generic/tkIntPlatDecls.h b/tk/generic/tkIntPlatDecls.h new file mode 100644 index 00000000000..d3240233fe8 --- /dev/null +++ b/tk/generic/tkIntPlatDecls.h @@ -0,0 +1,885 @@ +/* + * tkIntPlatDecls.h -- + * + * This file contains the declarations for all platform dependent + * unsupported functions that are exported by the Tk library. These + * interfaces are not guaranteed to remain the same between + * versions. Use at your own risk. + * + * Copyright (c) 1998-1999 by Scriptics Corporation. + * All rights reserved. + * + * RCS: @(#) $Id$ + */ + +#ifndef _TKINTPLATDECLS +#define _TKINTPLATDECLS + +#ifdef BUILD_tk +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLEXPORT +#endif + +/* + * WARNING: This file is automatically generated by the tools/genStubs.tcl + * script. Any modifications to the function declarations below should be made + * in the generic/tkInt.decls script. + */ + +/* !BEGIN!: Do not edit below this line. */ + +/* + * Exported function declarations: + */ + +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ +/* 0 */ +EXTERN void TkCreateXEventSource _ANSI_ARGS_((void)); +/* 1 */ +EXTERN void TkFreeWindowId _ANSI_ARGS_((TkDisplay * dispPtr, + Window w)); +/* 2 */ +EXTERN void TkInitXId _ANSI_ARGS_((TkDisplay * dispPtr)); +/* 3 */ +EXTERN int TkpCmapStressed _ANSI_ARGS_((Tk_Window tkwin, + Colormap colormap)); +/* 4 */ +EXTERN void TkpSync _ANSI_ARGS_((Display * display)); +/* 5 */ +EXTERN Window TkUnixContainerId _ANSI_ARGS_((TkWindow * winPtr)); +/* 6 */ +EXTERN int TkUnixDoOneXEvent _ANSI_ARGS_((Tcl_Time * timePtr)); +/* 7 */ +EXTERN void TkUnixSetMenubar _ANSI_ARGS_((Tk_Window tkwin, + Tk_Window menubar)); +#endif /* UNIX */ +#ifdef __WIN32__ +/* 0 */ +EXTERN char * TkAlignImageData _ANSI_ARGS_((XImage * image, + int alignment, int bitOrder)); +/* Slot 1 is reserved */ +/* 2 */ +EXTERN void TkGenerateActivateEvents _ANSI_ARGS_(( + TkWindow * winPtr, int active)); +/* 3 */ +EXTERN unsigned long TkpGetMS _ANSI_ARGS_((void)); +/* 4 */ +EXTERN void TkPointerDeadWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 5 */ +EXTERN void TkpPrintWindowId _ANSI_ARGS_((char * buf, + Window window)); +/* 6 */ +EXTERN int TkpScanWindowId _ANSI_ARGS_((Tcl_Interp * interp, + char * string, int * idPtr)); +/* 7 */ +EXTERN void TkpSetCapture _ANSI_ARGS_((TkWindow * winPtr)); +/* 8 */ +EXTERN void TkpSetCursor _ANSI_ARGS_((TkpCursor cursor)); +/* 9 */ +EXTERN void TkpWmSetState _ANSI_ARGS_((TkWindow * winPtr, + int state)); +/* 10 */ +EXTERN void TkSetPixmapColormap _ANSI_ARGS_((Pixmap pixmap, + Colormap colormap)); +/* 11 */ +EXTERN void TkWinCancelMouseTimer _ANSI_ARGS_((void)); +/* 12 */ +EXTERN void TkWinClipboardRender _ANSI_ARGS_(( + TkDisplay * dispPtr, UINT format)); +/* 13 */ +EXTERN LRESULT TkWinEmbeddedEventProc _ANSI_ARGS_((HWND hwnd, + UINT message, WPARAM wParam, LPARAM lParam)); +/* 14 */ +EXTERN void TkWinFillRect _ANSI_ARGS_((HDC dc, int x, int y, + int width, int height, int pixel)); +/* 15 */ +EXTERN COLORREF TkWinGetBorderPixels _ANSI_ARGS_((Tk_Window tkwin, + Tk_3DBorder border, int which)); +/* 16 */ +EXTERN HDC TkWinGetDrawableDC _ANSI_ARGS_((Display * display, + Drawable d, TkWinDCState* state)); +/* 17 */ +EXTERN int TkWinGetModifierState _ANSI_ARGS_((void)); +/* 18 */ +EXTERN HPALETTE TkWinGetSystemPalette _ANSI_ARGS_((void)); +/* 19 */ +EXTERN HWND TkWinGetWrapperWindow _ANSI_ARGS_((Tk_Window tkwin)); +/* 20 */ +EXTERN int TkWinHandleMenuEvent _ANSI_ARGS_((HWND * phwnd, + UINT * pMessage, WPARAM * pwParam, + LPARAM * plParam, LRESULT * plResult)); +/* 21 */ +EXTERN int TkWinIndexOfColor _ANSI_ARGS_((XColor * colorPtr)); +/* 22 */ +EXTERN void TkWinReleaseDrawableDC _ANSI_ARGS_((Drawable d, + HDC hdc, TkWinDCState* state)); +/* 23 */ +EXTERN LRESULT TkWinResendEvent _ANSI_ARGS_((WNDPROC wndproc, + HWND hwnd, XEvent * eventPtr)); +/* 24 */ +EXTERN HPALETTE TkWinSelectPalette _ANSI_ARGS_((HDC dc, + Colormap colormap)); +/* 25 */ +EXTERN void TkWinSetMenu _ANSI_ARGS_((Tk_Window tkwin, + HMENU hMenu)); +/* 26 */ +EXTERN void TkWinSetWindowPos _ANSI_ARGS_((HWND hwnd, + HWND siblingHwnd, int pos)); +/* 27 */ +EXTERN void TkWinWmCleanup _ANSI_ARGS_((HINSTANCE hInstance)); +/* 28 */ +EXTERN void TkWinXCleanup _ANSI_ARGS_((HINSTANCE hInstance)); +/* 29 */ +EXTERN void TkWinXInit _ANSI_ARGS_((HINSTANCE hInstance)); +/* 30 */ +EXTERN void TkWinSetForegroundWindow _ANSI_ARGS_(( + TkWindow * winPtr)); +/* 31 */ +EXTERN void TkWinDialogDebug _ANSI_ARGS_((int debug)); +/* 32 */ +EXTERN Tcl_Obj * TkWinGetMenuSystemDefault _ANSI_ARGS_(( + Tk_Window tkwin, char * dbName, + char * className)); +/* 33 */ +EXTERN int TkWinGetPlatformId _ANSI_ARGS_((void)); +#endif /* __WIN32__ */ +#ifdef MAC_TCL +/* 0 */ +EXTERN void TkGenerateActivateEvents _ANSI_ARGS_(( + TkWindow * winPtr, int active)); +/* 1 */ +EXTERN Pixmap TkpCreateNativeBitmap _ANSI_ARGS_((Display * display, + char * source)); +/* 2 */ +EXTERN void TkpDefineNativeBitmaps _ANSI_ARGS_((void)); +/* 3 */ +EXTERN unsigned long TkpGetMS _ANSI_ARGS_((void)); +/* 4 */ +EXTERN Pixmap TkpGetNativeAppBitmap _ANSI_ARGS_((Display * display, + char * name, int * width, int * height)); +/* 5 */ +EXTERN void TkPointerDeadWindow _ANSI_ARGS_((TkWindow * winPtr)); +/* 6 */ +EXTERN void TkpSetCapture _ANSI_ARGS_((TkWindow * winPtr)); +/* 7 */ +EXTERN void TkpSetCursor _ANSI_ARGS_((TkpCursor cursor)); +/* 8 */ +EXTERN void TkpWmSetState _ANSI_ARGS_((TkWindow * winPtr, + int state)); +/* 9 */ +EXTERN int HandleWMEvent _ANSI_ARGS_((EventRecord * theEvent)); +/* 10 */ +EXTERN void TkAboutDlg _ANSI_ARGS_((void)); +/* 11 */ +EXTERN void TkCreateMacEventSource _ANSI_ARGS_((void)); +/* 12 */ +EXTERN void TkFontList _ANSI_ARGS_((Tcl_Interp * interp, + Display * display)); +/* 13 */ +EXTERN Window TkGetTransientMaster _ANSI_ARGS_((TkWindow * winPtr)); +/* 14 */ +EXTERN int TkGenerateButtonEvent _ANSI_ARGS_((int x, int y, + Window window, unsigned int state)); +/* 15 */ +EXTERN int TkGetCharPositions _ANSI_ARGS_(( + XFontStruct * font_struct, char * string, + int count, short * buffer)); +/* 16 */ +EXTERN void TkGenWMDestroyEvent _ANSI_ARGS_((Tk_Window tkwin)); +/* 17 */ +EXTERN void TkGenWMConfigureEvent _ANSI_ARGS_((Tk_Window tkwin, + int x, int y, int width, int height, + int flags)); +/* 18 */ +EXTERN unsigned int TkMacButtonKeyState _ANSI_ARGS_((void)); +/* 19 */ +EXTERN void TkMacClearMenubarActive _ANSI_ARGS_((void)); +/* 20 */ +EXTERN int TkMacConvertEvent _ANSI_ARGS_(( + EventRecord * eventPtr)); +/* 21 */ +EXTERN int TkMacDispatchMenuEvent _ANSI_ARGS_((int menuID, + int index)); +/* 22 */ +EXTERN void TkMacInstallCursor _ANSI_ARGS_((int resizeOverride)); +/* 23 */ +EXTERN int TkMacConvertTkEvent _ANSI_ARGS_(( + EventRecord * eventPtr, Window window)); +/* 24 */ +EXTERN void TkMacHandleTearoffMenu _ANSI_ARGS_((void)); +/* 25 */ +EXTERN void tkMacInstallMWConsole _ANSI_ARGS_(( + Tcl_Interp * interp)); +/* 26 */ +EXTERN void TkMacInvalClipRgns _ANSI_ARGS_((TkWindow * winPtr)); +/* 27 */ +EXTERN void TkMacDoHLEvent _ANSI_ARGS_((EventRecord * theEvent)); +/* 28 */ +EXTERN void TkMacFontInfo _ANSI_ARGS_((Font fontId, + short * family, short * style, short * size)); +/* 29 */ +EXTERN Time TkMacGenerateTime _ANSI_ARGS_((void)); +/* 30 */ +EXTERN GWorldPtr TkMacGetDrawablePort _ANSI_ARGS_((Drawable drawable)); +/* 31 */ +EXTERN TkWindow * TkMacGetScrollbarGrowWindow _ANSI_ARGS_(( + TkWindow * winPtr)); +/* 32 */ +EXTERN Window TkMacGetXWindow _ANSI_ARGS_((WindowRef macWinPtr)); +/* 33 */ +EXTERN int TkMacGrowToplevel _ANSI_ARGS_((WindowRef whichWindow, + Point start)); +/* 34 */ +EXTERN void TkMacHandleMenuSelect _ANSI_ARGS_((long mResult, + int optionKeyPressed)); +/* 35 */ +EXTERN int TkMacHaveAppearance _ANSI_ARGS_((void)); +/* 36 */ +EXTERN void TkMacInitAppleEvents _ANSI_ARGS_(( + Tcl_Interp * interp)); +/* 37 */ +EXTERN void TkMacInitMenus _ANSI_ARGS_((Tcl_Interp * interp)); +/* 38 */ +EXTERN void TkMacInvalidateWindow _ANSI_ARGS_(( + MacDrawable * macWin, int flag)); +/* 39 */ +EXTERN int TkMacIsCharacterMissing _ANSI_ARGS_((Tk_Font tkfont, + unsigned int searchChar)); +/* 40 */ +EXTERN void TkMacMakeRealWindowExist _ANSI_ARGS_(( + TkWindow * winPtr)); +/* 41 */ +EXTERN BitMapPtr TkMacMakeStippleMap _ANSI_ARGS_((Drawable d1, + Drawable d2)); +/* 42 */ +EXTERN void TkMacMenuClick _ANSI_ARGS_((void)); +/* 43 */ +EXTERN void TkMacRegisterOffScreenWindow _ANSI_ARGS_(( + Window window, GWorldPtr portPtr)); +/* 44 */ +EXTERN int TkMacResizable _ANSI_ARGS_((TkWindow * winPtr)); +/* 45 */ +EXTERN void TkMacSetEmbedRgn _ANSI_ARGS_((TkWindow * winPtr, + RgnHandle rgn)); +/* 46 */ +EXTERN void TkMacSetHelpMenuItemCount _ANSI_ARGS_((void)); +/* 47 */ +EXTERN void TkMacSetScrollbarGrow _ANSI_ARGS_((TkWindow * winPtr, + int flag)); +/* 48 */ +EXTERN void TkMacSetUpClippingRgn _ANSI_ARGS_((Drawable drawable)); +/* 49 */ +EXTERN void TkMacSetUpGraphicsPort _ANSI_ARGS_((GC gc)); +/* 50 */ +EXTERN void TkMacUpdateClipRgn _ANSI_ARGS_((TkWindow * winPtr)); +/* 51 */ +EXTERN void TkMacUnregisterMacWindow _ANSI_ARGS_(( + GWorldPtr portPtr)); +/* 52 */ +EXTERN int TkMacUseMenuID _ANSI_ARGS_((short macID)); +/* 53 */ +EXTERN RgnHandle TkMacVisableClipRgn _ANSI_ARGS_((TkWindow * winPtr)); +/* 54 */ +EXTERN void TkMacWinBounds _ANSI_ARGS_((TkWindow * winPtr, + Rect * geometry)); +/* 55 */ +EXTERN void TkMacWindowOffset _ANSI_ARGS_((WindowRef wRef, + int * xOffset, int * yOffset)); +/* 56 */ +EXTERN void TkResumeClipboard _ANSI_ARGS_((void)); +/* 57 */ +EXTERN int TkSetMacColor _ANSI_ARGS_((unsigned long pixel, + RGBColor * macColor)); +/* 58 */ +EXTERN void TkSetWMName _ANSI_ARGS_((TkWindow * winPtr, + Tk_Uid titleUid)); +/* 59 */ +EXTERN void TkSuspendClipboard _ANSI_ARGS_((void)); +/* 60 */ +EXTERN int TkWMGrowToplevel _ANSI_ARGS_((WindowRef whichWindow, + Point start)); +/* 61 */ +EXTERN int TkMacZoomToplevel _ANSI_ARGS_((WindowPtr whichWindow, + Point where, short zoomPart)); +/* 62 */ +EXTERN Tk_Window Tk_TopCoordsToWindow _ANSI_ARGS_((Tk_Window tkwin, + int rootX, int rootY, int * newX, int * newY)); +/* 63 */ +EXTERN MacDrawable * TkMacContainerId _ANSI_ARGS_((TkWindow * winPtr)); +/* 64 */ +EXTERN MacDrawable * TkMacGetHostToplevel _ANSI_ARGS_((TkWindow * winPtr)); +#endif /* MAC_TCL */ + +typedef struct TkIntPlatStubs { + int magic; + struct TkIntPlatStubHooks *hooks; + +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void (*tkCreateXEventSource) _ANSI_ARGS_((void)); /* 0 */ + void (*tkFreeWindowId) _ANSI_ARGS_((TkDisplay * dispPtr, Window w)); /* 1 */ + void (*tkInitXId) _ANSI_ARGS_((TkDisplay * dispPtr)); /* 2 */ + int (*tkpCmapStressed) _ANSI_ARGS_((Tk_Window tkwin, Colormap colormap)); /* 3 */ + void (*tkpSync) _ANSI_ARGS_((Display * display)); /* 4 */ + Window (*tkUnixContainerId) _ANSI_ARGS_((TkWindow * winPtr)); /* 5 */ + int (*tkUnixDoOneXEvent) _ANSI_ARGS_((Tcl_Time * timePtr)); /* 6 */ + void (*tkUnixSetMenubar) _ANSI_ARGS_((Tk_Window tkwin, Tk_Window menubar)); /* 7 */ +#endif /* UNIX */ +#ifdef __WIN32__ + char * (*tkAlignImageData) _ANSI_ARGS_((XImage * image, int alignment, int bitOrder)); /* 0 */ + void *reserved1; + void (*tkGenerateActivateEvents) _ANSI_ARGS_((TkWindow * winPtr, int active)); /* 2 */ + unsigned long (*tkpGetMS) _ANSI_ARGS_((void)); /* 3 */ + void (*tkPointerDeadWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 4 */ + void (*tkpPrintWindowId) _ANSI_ARGS_((char * buf, Window window)); /* 5 */ + int (*tkpScanWindowId) _ANSI_ARGS_((Tcl_Interp * interp, char * string, int * idPtr)); /* 6 */ + void (*tkpSetCapture) _ANSI_ARGS_((TkWindow * winPtr)); /* 7 */ + void (*tkpSetCursor) _ANSI_ARGS_((TkpCursor cursor)); /* 8 */ + void (*tkpWmSetState) _ANSI_ARGS_((TkWindow * winPtr, int state)); /* 9 */ + void (*tkSetPixmapColormap) _ANSI_ARGS_((Pixmap pixmap, Colormap colormap)); /* 10 */ + void (*tkWinCancelMouseTimer) _ANSI_ARGS_((void)); /* 11 */ + void (*tkWinClipboardRender) _ANSI_ARGS_((TkDisplay * dispPtr, UINT format)); /* 12 */ + LRESULT (*tkWinEmbeddedEventProc) _ANSI_ARGS_((HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)); /* 13 */ + void (*tkWinFillRect) _ANSI_ARGS_((HDC dc, int x, int y, int width, int height, int pixel)); /* 14 */ + COLORREF (*tkWinGetBorderPixels) _ANSI_ARGS_((Tk_Window tkwin, Tk_3DBorder border, int which)); /* 15 */ + HDC (*tkWinGetDrawableDC) _ANSI_ARGS_((Display * display, Drawable d, TkWinDCState* state)); /* 16 */ + int (*tkWinGetModifierState) _ANSI_ARGS_((void)); /* 17 */ + HPALETTE (*tkWinGetSystemPalette) _ANSI_ARGS_((void)); /* 18 */ + HWND (*tkWinGetWrapperWindow) _ANSI_ARGS_((Tk_Window tkwin)); /* 19 */ + int (*tkWinHandleMenuEvent) _ANSI_ARGS_((HWND * phwnd, UINT * pMessage, WPARAM * pwParam, LPARAM * plParam, LRESULT * plResult)); /* 20 */ + int (*tkWinIndexOfColor) _ANSI_ARGS_((XColor * colorPtr)); /* 21 */ + void (*tkWinReleaseDrawableDC) _ANSI_ARGS_((Drawable d, HDC hdc, TkWinDCState* state)); /* 22 */ + LRESULT (*tkWinResendEvent) _ANSI_ARGS_((WNDPROC wndproc, HWND hwnd, XEvent * eventPtr)); /* 23 */ + HPALETTE (*tkWinSelectPalette) _ANSI_ARGS_((HDC dc, Colormap colormap)); /* 24 */ + void (*tkWinSetMenu) _ANSI_ARGS_((Tk_Window tkwin, HMENU hMenu)); /* 25 */ + void (*tkWinSetWindowPos) _ANSI_ARGS_((HWND hwnd, HWND siblingHwnd, int pos)); /* 26 */ + void (*tkWinWmCleanup) _ANSI_ARGS_((HINSTANCE hInstance)); /* 27 */ + void (*tkWinXCleanup) _ANSI_ARGS_((HINSTANCE hInstance)); /* 28 */ + void (*tkWinXInit) _ANSI_ARGS_((HINSTANCE hInstance)); /* 29 */ + void (*tkWinSetForegroundWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 30 */ + void (*tkWinDialogDebug) _ANSI_ARGS_((int debug)); /* 31 */ + Tcl_Obj * (*tkWinGetMenuSystemDefault) _ANSI_ARGS_((Tk_Window tkwin, char * dbName, char * className)); /* 32 */ + int (*tkWinGetPlatformId) _ANSI_ARGS_((void)); /* 33 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkGenerateActivateEvents) _ANSI_ARGS_((TkWindow * winPtr, int active)); /* 0 */ + Pixmap (*tkpCreateNativeBitmap) _ANSI_ARGS_((Display * display, char * source)); /* 1 */ + void (*tkpDefineNativeBitmaps) _ANSI_ARGS_((void)); /* 2 */ + unsigned long (*tkpGetMS) _ANSI_ARGS_((void)); /* 3 */ + Pixmap (*tkpGetNativeAppBitmap) _ANSI_ARGS_((Display * display, char * name, int * width, int * height)); /* 4 */ + void (*tkPointerDeadWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 5 */ + void (*tkpSetCapture) _ANSI_ARGS_((TkWindow * winPtr)); /* 6 */ + void (*tkpSetCursor) _ANSI_ARGS_((TkpCursor cursor)); /* 7 */ + void (*tkpWmSetState) _ANSI_ARGS_((TkWindow * winPtr, int state)); /* 8 */ + int (*handleWMEvent) _ANSI_ARGS_((EventRecord * theEvent)); /* 9 */ + void (*tkAboutDlg) _ANSI_ARGS_((void)); /* 10 */ + void (*tkCreateMacEventSource) _ANSI_ARGS_((void)); /* 11 */ + void (*tkFontList) _ANSI_ARGS_((Tcl_Interp * interp, Display * display)); /* 12 */ + Window (*tkGetTransientMaster) _ANSI_ARGS_((TkWindow * winPtr)); /* 13 */ + int (*tkGenerateButtonEvent) _ANSI_ARGS_((int x, int y, Window window, unsigned int state)); /* 14 */ + int (*tkGetCharPositions) _ANSI_ARGS_((XFontStruct * font_struct, char * string, int count, short * buffer)); /* 15 */ + void (*tkGenWMDestroyEvent) _ANSI_ARGS_((Tk_Window tkwin)); /* 16 */ + void (*tkGenWMConfigureEvent) _ANSI_ARGS_((Tk_Window tkwin, int x, int y, int width, int height, int flags)); /* 17 */ + unsigned int (*tkMacButtonKeyState) _ANSI_ARGS_((void)); /* 18 */ + void (*tkMacClearMenubarActive) _ANSI_ARGS_((void)); /* 19 */ + int (*tkMacConvertEvent) _ANSI_ARGS_((EventRecord * eventPtr)); /* 20 */ + int (*tkMacDispatchMenuEvent) _ANSI_ARGS_((int menuID, int index)); /* 21 */ + void (*tkMacInstallCursor) _ANSI_ARGS_((int resizeOverride)); /* 22 */ + int (*tkMacConvertTkEvent) _ANSI_ARGS_((EventRecord * eventPtr, Window window)); /* 23 */ + void (*tkMacHandleTearoffMenu) _ANSI_ARGS_((void)); /* 24 */ + void (*tkMacInstallMWConsole) _ANSI_ARGS_((Tcl_Interp * interp)); /* 25 */ + void (*tkMacInvalClipRgns) _ANSI_ARGS_((TkWindow * winPtr)); /* 26 */ + void (*tkMacDoHLEvent) _ANSI_ARGS_((EventRecord * theEvent)); /* 27 */ + void (*tkMacFontInfo) _ANSI_ARGS_((Font fontId, short * family, short * style, short * size)); /* 28 */ + Time (*tkMacGenerateTime) _ANSI_ARGS_((void)); /* 29 */ + GWorldPtr (*tkMacGetDrawablePort) _ANSI_ARGS_((Drawable drawable)); /* 30 */ + TkWindow * (*tkMacGetScrollbarGrowWindow) _ANSI_ARGS_((TkWindow * winPtr)); /* 31 */ + Window (*tkMacGetXWindow) _ANSI_ARGS_((WindowRef macWinPtr)); /* 32 */ + int (*tkMacGrowToplevel) _ANSI_ARGS_((WindowRef whichWindow, Point start)); /* 33 */ + void (*tkMacHandleMenuSelect) _ANSI_ARGS_((long mResult, int optionKeyPressed)); /* 34 */ + int (*tkMacHaveAppearance) _ANSI_ARGS_((void)); /* 35 */ + void (*tkMacInitAppleEvents) _ANSI_ARGS_((Tcl_Interp * interp)); /* 36 */ + void (*tkMacInitMenus) _ANSI_ARGS_((Tcl_Interp * interp)); /* 37 */ + void (*tkMacInvalidateWindow) _ANSI_ARGS_((MacDrawable * macWin, int flag)); /* 38 */ + int (*tkMacIsCharacterMissing) _ANSI_ARGS_((Tk_Font tkfont, unsigned int searchChar)); /* 39 */ + void (*tkMacMakeRealWindowExist) _ANSI_ARGS_((TkWindow * winPtr)); /* 40 */ + BitMapPtr (*tkMacMakeStippleMap) _ANSI_ARGS_((Drawable d1, Drawable d2)); /* 41 */ + void (*tkMacMenuClick) _ANSI_ARGS_((void)); /* 42 */ + void (*tkMacRegisterOffScreenWindow) _ANSI_ARGS_((Window window, GWorldPtr portPtr)); /* 43 */ + int (*tkMacResizable) _ANSI_ARGS_((TkWindow * winPtr)); /* 44 */ + void (*tkMacSetEmbedRgn) _ANSI_ARGS_((TkWindow * winPtr, RgnHandle rgn)); /* 45 */ + void (*tkMacSetHelpMenuItemCount) _ANSI_ARGS_((void)); /* 46 */ + void (*tkMacSetScrollbarGrow) _ANSI_ARGS_((TkWindow * winPtr, int flag)); /* 47 */ + void (*tkMacSetUpClippingRgn) _ANSI_ARGS_((Drawable drawable)); /* 48 */ + void (*tkMacSetUpGraphicsPort) _ANSI_ARGS_((GC gc)); /* 49 */ + void (*tkMacUpdateClipRgn) _ANSI_ARGS_((TkWindow * winPtr)); /* 50 */ + void (*tkMacUnregisterMacWindow) _ANSI_ARGS_((GWorldPtr portPtr)); /* 51 */ + int (*tkMacUseMenuID) _ANSI_ARGS_((short macID)); /* 52 */ + RgnHandle (*tkMacVisableClipRgn) _ANSI_ARGS_((TkWindow * winPtr)); /* 53 */ + void (*tkMacWinBounds) _ANSI_ARGS_((TkWindow * winPtr, Rect * geometry)); /* 54 */ + void (*tkMacWindowOffset) _ANSI_ARGS_((WindowRef wRef, int * xOffset, int * yOffset)); /* 55 */ + void (*tkResumeClipboard) _ANSI_ARGS_((void)); /* 56 */ + int (*tkSetMacColor) _ANSI_ARGS_((unsigned long pixel, RGBColor * macColor)); /* 57 */ + void (*tkSetWMName) _ANSI_ARGS_((TkWindow * winPtr, Tk_Uid titleUid)); /* 58 */ + void (*tkSuspendClipboard) _ANSI_ARGS_((void)); /* 59 */ + int (*tkWMGrowToplevel) _ANSI_ARGS_((WindowRef whichWindow, Point start)); /* 60 */ + int (*tkMacZoomToplevel) _ANSI_ARGS_((WindowPtr whichWindow, Point where, short zoomPart)); /* 61 */ + Tk_Window (*tk_TopCoordsToWindow) _ANSI_ARGS_((Tk_Window tkwin, int rootX, int rootY, int * newX, int * newY)); /* 62 */ + MacDrawable * (*tkMacContainerId) _ANSI_ARGS_((TkWindow * winPtr)); /* 63 */ + MacDrawable * (*tkMacGetHostToplevel) _ANSI_ARGS_((TkWindow * winPtr)); /* 64 */ +#endif /* MAC_TCL */ +} TkIntPlatStubs; + +#ifdef __cplusplus +extern "C" { +#endif +extern TkIntPlatStubs *tkIntPlatStubsPtr; +#ifdef __cplusplus +} +#endif + +#if defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) + +/* + * Inline function declarations: + */ + +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ +#ifndef TkCreateXEventSource +#define TkCreateXEventSource \ + (tkIntPlatStubsPtr->tkCreateXEventSource) /* 0 */ +#endif +#ifndef TkFreeWindowId +#define TkFreeWindowId \ + (tkIntPlatStubsPtr->tkFreeWindowId) /* 1 */ +#endif +#ifndef TkInitXId +#define TkInitXId \ + (tkIntPlatStubsPtr->tkInitXId) /* 2 */ +#endif +#ifndef TkpCmapStressed +#define TkpCmapStressed \ + (tkIntPlatStubsPtr->tkpCmapStressed) /* 3 */ +#endif +#ifndef TkpSync +#define TkpSync \ + (tkIntPlatStubsPtr->tkpSync) /* 4 */ +#endif +#ifndef TkUnixContainerId +#define TkUnixContainerId \ + (tkIntPlatStubsPtr->tkUnixContainerId) /* 5 */ +#endif +#ifndef TkUnixDoOneXEvent +#define TkUnixDoOneXEvent \ + (tkIntPlatStubsPtr->tkUnixDoOneXEvent) /* 6 */ +#endif +#ifndef TkUnixSetMenubar +#define TkUnixSetMenubar \ + (tkIntPlatStubsPtr->tkUnixSetMenubar) /* 7 */ +#endif +#endif /* UNIX */ +#ifdef __WIN32__ +#ifndef TkAlignImageData +#define TkAlignImageData \ + (tkIntPlatStubsPtr->tkAlignImageData) /* 0 */ +#endif +/* Slot 1 is reserved */ +#ifndef TkGenerateActivateEvents +#define TkGenerateActivateEvents \ + (tkIntPlatStubsPtr->tkGenerateActivateEvents) /* 2 */ +#endif +#ifndef TkpGetMS +#define TkpGetMS \ + (tkIntPlatStubsPtr->tkpGetMS) /* 3 */ +#endif +#ifndef TkPointerDeadWindow +#define TkPointerDeadWindow \ + (tkIntPlatStubsPtr->tkPointerDeadWindow) /* 4 */ +#endif +#ifndef TkpPrintWindowId +#define TkpPrintWindowId \ + (tkIntPlatStubsPtr->tkpPrintWindowId) /* 5 */ +#endif +#ifndef TkpScanWindowId +#define TkpScanWindowId \ + (tkIntPlatStubsPtr->tkpScanWindowId) /* 6 */ +#endif +#ifndef TkpSetCapture +#define TkpSetCapture \ + (tkIntPlatStubsPtr->tkpSetCapture) /* 7 */ +#endif +#ifndef TkpSetCursor +#define TkpSetCursor \ + (tkIntPlatStubsPtr->tkpSetCursor) /* 8 */ +#endif +#ifndef TkpWmSetState +#define TkpWmSetState \ + (tkIntPlatStubsPtr->tkpWmSetState) /* 9 */ +#endif +#ifndef TkSetPixmapColormap +#define TkSetPixmapColormap \ + (tkIntPlatStubsPtr->tkSetPixmapColormap) /* 10 */ +#endif +#ifndef TkWinCancelMouseTimer +#define TkWinCancelMouseTimer \ + (tkIntPlatStubsPtr->tkWinCancelMouseTimer) /* 11 */ +#endif +#ifndef TkWinClipboardRender +#define TkWinClipboardRender \ + (tkIntPlatStubsPtr->tkWinClipboardRender) /* 12 */ +#endif +#ifndef TkWinEmbeddedEventProc +#define TkWinEmbeddedEventProc \ + (tkIntPlatStubsPtr->tkWinEmbeddedEventProc) /* 13 */ +#endif +#ifndef TkWinFillRect +#define TkWinFillRect \ + (tkIntPlatStubsPtr->tkWinFillRect) /* 14 */ +#endif +#ifndef TkWinGetBorderPixels +#define TkWinGetBorderPixels \ + (tkIntPlatStubsPtr->tkWinGetBorderPixels) /* 15 */ +#endif +#ifndef TkWinGetDrawableDC +#define TkWinGetDrawableDC \ + (tkIntPlatStubsPtr->tkWinGetDrawableDC) /* 16 */ +#endif +#ifndef TkWinGetModifierState +#define TkWinGetModifierState \ + (tkIntPlatStubsPtr->tkWinGetModifierState) /* 17 */ +#endif +#ifndef TkWinGetSystemPalette +#define TkWinGetSystemPalette \ + (tkIntPlatStubsPtr->tkWinGetSystemPalette) /* 18 */ +#endif +#ifndef TkWinGetWrapperWindow +#define TkWinGetWrapperWindow \ + (tkIntPlatStubsPtr->tkWinGetWrapperWindow) /* 19 */ +#endif +#ifndef TkWinHandleMenuEvent +#define TkWinHandleMenuEvent \ + (tkIntPlatStubsPtr->tkWinHandleMenuEvent) /* 20 */ +#endif +#ifndef TkWinIndexOfColor +#define TkWinIndexOfColor \ + (tkIntPlatStubsPtr->tkWinIndexOfColor) /* 21 */ +#endif +#ifndef TkWinReleaseDrawableDC +#define TkWinReleaseDrawableDC \ + (tkIntPlatStubsPtr->tkWinReleaseDrawableDC) /* 22 */ +#endif +#ifndef TkWinResendEvent +#define TkWinResendEvent \ + (tkIntPlatStubsPtr->tkWinResendEvent) /* 23 */ +#endif +#ifndef TkWinSelectPalette +#define TkWinSelectPalette \ + (tkIntPlatStubsPtr->tkWinSelectPalette) /* 24 */ +#endif +#ifndef TkWinSetMenu +#define TkWinSetMenu \ + (tkIntPlatStubsPtr->tkWinSetMenu) /* 25 */ +#endif +#ifndef TkWinSetWindowPos +#define TkWinSetWindowPos \ + (tkIntPlatStubsPtr->tkWinSetWindowPos) /* 26 */ +#endif +#ifndef TkWinWmCleanup +#define TkWinWmCleanup \ + (tkIntPlatStubsPtr->tkWinWmCleanup) /* 27 */ +#endif +#ifndef TkWinXCleanup +#define TkWinXCleanup \ + (tkIntPlatStubsPtr->tkWinXCleanup) /* 28 */ +#endif +#ifndef TkWinXInit +#define TkWinXInit \ + (tkIntPlatStubsPtr->tkWinXInit) /* 29 */ +#endif +#ifndef TkWinSetForegroundWindow +#define TkWinSetForegroundWindow \ + (tkIntPlatStubsPtr->tkWinSetForegroundWindow) /* 30 */ +#endif +#ifndef TkWinDialogDebug +#define TkWinDialogDebug \ + (tkIntPlatStubsPtr->tkWinDialogDebug) /* 31 */ +#endif +#ifndef TkWinGetMenuSystemDefault +#define TkWinGetMenuSystemDefault \ + (tkIntPlatStubsPtr->tkWinGetMenuSystemDefault) /* 32 */ +#endif +#ifndef TkWinGetPlatformId +#define TkWinGetPlatformId \ + (tkIntPlatStubsPtr->tkWinGetPlatformId) /* 33 */ +#endif +#endif /* __WIN32__ */ +#ifdef MAC_TCL +#ifndef TkGenerateActivateEvents +#define TkGenerateActivateEvents \ + (tkIntPlatStubsPtr->tkGenerateActivateEvents) /* 0 */ +#endif +#ifndef TkpCreateNativeBitmap +#define TkpCreateNativeBitmap \ + (tkIntPlatStubsPtr->tkpCreateNativeBitmap) /* 1 */ +#endif +#ifndef TkpDefineNativeBitmaps +#define TkpDefineNativeBitmaps \ + (tkIntPlatStubsPtr->tkpDefineNativeBitmaps) /* 2 */ +#endif +#ifndef TkpGetMS +#define TkpGetMS \ + (tkIntPlatStubsPtr->tkpGetMS) /* 3 */ +#endif +#ifndef TkpGetNativeAppBitmap +#define TkpGetNativeAppBitmap \ + (tkIntPlatStubsPtr->tkpGetNativeAppBitmap) /* 4 */ +#endif +#ifndef TkPointerDeadWindow +#define TkPointerDeadWindow \ + (tkIntPlatStubsPtr->tkPointerDeadWindow) /* 5 */ +#endif +#ifndef TkpSetCapture +#define TkpSetCapture \ + (tkIntPlatStubsPtr->tkpSetCapture) /* 6 */ +#endif +#ifndef TkpSetCursor +#define TkpSetCursor \ + (tkIntPlatStubsPtr->tkpSetCursor) /* 7 */ +#endif +#ifndef TkpWmSetState +#define TkpWmSetState \ + (tkIntPlatStubsPtr->tkpWmSetState) /* 8 */ +#endif +#ifndef HandleWMEvent +#define HandleWMEvent \ + (tkIntPlatStubsPtr->handleWMEvent) /* 9 */ +#endif +#ifndef TkAboutDlg +#define TkAboutDlg \ + (tkIntPlatStubsPtr->tkAboutDlg) /* 10 */ +#endif +#ifndef TkCreateMacEventSource +#define TkCreateMacEventSource \ + (tkIntPlatStubsPtr->tkCreateMacEventSource) /* 11 */ +#endif +#ifndef TkFontList +#define TkFontList \ + (tkIntPlatStubsPtr->tkFontList) /* 12 */ +#endif +#ifndef TkGetTransientMaster +#define TkGetTransientMaster \ + (tkIntPlatStubsPtr->tkGetTransientMaster) /* 13 */ +#endif +#ifndef TkGenerateButtonEvent +#define TkGenerateButtonEvent \ + (tkIntPlatStubsPtr->tkGenerateButtonEvent) /* 14 */ +#endif +#ifndef TkGetCharPositions +#define TkGetCharPositions \ + (tkIntPlatStubsPtr->tkGetCharPositions) /* 15 */ +#endif +#ifndef TkGenWMDestroyEvent +#define TkGenWMDestroyEvent \ + (tkIntPlatStubsPtr->tkGenWMDestroyEvent) /* 16 */ +#endif +#ifndef TkGenWMConfigureEvent +#define TkGenWMConfigureEvent \ + (tkIntPlatStubsPtr->tkGenWMConfigureEvent) /* 17 */ +#endif +#ifndef TkMacButtonKeyState +#define TkMacButtonKeyState \ + (tkIntPlatStubsPtr->tkMacButtonKeyState) /* 18 */ +#endif +#ifndef TkMacClearMenubarActive +#define TkMacClearMenubarActive \ + (tkIntPlatStubsPtr->tkMacClearMenubarActive) /* 19 */ +#endif +#ifndef TkMacConvertEvent +#define TkMacConvertEvent \ + (tkIntPlatStubsPtr->tkMacConvertEvent) /* 20 */ +#endif +#ifndef TkMacDispatchMenuEvent +#define TkMacDispatchMenuEvent \ + (tkIntPlatStubsPtr->tkMacDispatchMenuEvent) /* 21 */ +#endif +#ifndef TkMacInstallCursor +#define TkMacInstallCursor \ + (tkIntPlatStubsPtr->tkMacInstallCursor) /* 22 */ +#endif +#ifndef TkMacConvertTkEvent +#define TkMacConvertTkEvent \ + (tkIntPlatStubsPtr->tkMacConvertTkEvent) /* 23 */ +#endif +#ifndef TkMacHandleTearoffMenu +#define TkMacHandleTearoffMenu \ + (tkIntPlatStubsPtr->tkMacHandleTearoffMenu) /* 24 */ +#endif +#ifndef tkMacInstallMWConsole +#define tkMacInstallMWConsole \ + (tkIntPlatStubsPtr->tkMacInstallMWConsole) /* 25 */ +#endif +#ifndef TkMacInvalClipRgns +#define TkMacInvalClipRgns \ + (tkIntPlatStubsPtr->tkMacInvalClipRgns) /* 26 */ +#endif +#ifndef TkMacDoHLEvent +#define TkMacDoHLEvent \ + (tkIntPlatStubsPtr->tkMacDoHLEvent) /* 27 */ +#endif +#ifndef TkMacFontInfo +#define TkMacFontInfo \ + (tkIntPlatStubsPtr->tkMacFontInfo) /* 28 */ +#endif +#ifndef TkMacGenerateTime +#define TkMacGenerateTime \ + (tkIntPlatStubsPtr->tkMacGenerateTime) /* 29 */ +#endif +#ifndef TkMacGetDrawablePort +#define TkMacGetDrawablePort \ + (tkIntPlatStubsPtr->tkMacGetDrawablePort) /* 30 */ +#endif +#ifndef TkMacGetScrollbarGrowWindow +#define TkMacGetScrollbarGrowWindow \ + (tkIntPlatStubsPtr->tkMacGetScrollbarGrowWindow) /* 31 */ +#endif +#ifndef TkMacGetXWindow +#define TkMacGetXWindow \ + (tkIntPlatStubsPtr->tkMacGetXWindow) /* 32 */ +#endif +#ifndef TkMacGrowToplevel +#define TkMacGrowToplevel \ + (tkIntPlatStubsPtr->tkMacGrowToplevel) /* 33 */ +#endif +#ifndef TkMacHandleMenuSelect +#define TkMacHandleMenuSelect \ + (tkIntPlatStubsPtr->tkMacHandleMenuSelect) /* 34 */ +#endif +#ifndef TkMacHaveAppearance +#define TkMacHaveAppearance \ + (tkIntPlatStubsPtr->tkMacHaveAppearance) /* 35 */ +#endif +#ifndef TkMacInitAppleEvents +#define TkMacInitAppleEvents \ + (tkIntPlatStubsPtr->tkMacInitAppleEvents) /* 36 */ +#endif +#ifndef TkMacInitMenus +#define TkMacInitMenus \ + (tkIntPlatStubsPtr->tkMacInitMenus) /* 37 */ +#endif +#ifndef TkMacInvalidateWindow +#define TkMacInvalidateWindow \ + (tkIntPlatStubsPtr->tkMacInvalidateWindow) /* 38 */ +#endif +#ifndef TkMacIsCharacterMissing +#define TkMacIsCharacterMissing \ + (tkIntPlatStubsPtr->tkMacIsCharacterMissing) /* 39 */ +#endif +#ifndef TkMacMakeRealWindowExist +#define TkMacMakeRealWindowExist \ + (tkIntPlatStubsPtr->tkMacMakeRealWindowExist) /* 40 */ +#endif +#ifndef TkMacMakeStippleMap +#define TkMacMakeStippleMap \ + (tkIntPlatStubsPtr->tkMacMakeStippleMap) /* 41 */ +#endif +#ifndef TkMacMenuClick +#define TkMacMenuClick \ + (tkIntPlatStubsPtr->tkMacMenuClick) /* 42 */ +#endif +#ifndef TkMacRegisterOffScreenWindow +#define TkMacRegisterOffScreenWindow \ + (tkIntPlatStubsPtr->tkMacRegisterOffScreenWindow) /* 43 */ +#endif +#ifndef TkMacResizable +#define TkMacResizable \ + (tkIntPlatStubsPtr->tkMacResizable) /* 44 */ +#endif +#ifndef TkMacSetEmbedRgn +#define TkMacSetEmbedRgn \ + (tkIntPlatStubsPtr->tkMacSetEmbedRgn) /* 45 */ +#endif +#ifndef TkMacSetHelpMenuItemCount +#define TkMacSetHelpMenuItemCount \ + (tkIntPlatStubsPtr->tkMacSetHelpMenuItemCount) /* 46 */ +#endif +#ifndef TkMacSetScrollbarGrow +#define TkMacSetScrollbarGrow \ + (tkIntPlatStubsPtr->tkMacSetScrollbarGrow) /* 47 */ +#endif +#ifndef TkMacSetUpClippingRgn +#define TkMacSetUpClippingRgn \ + (tkIntPlatStubsPtr->tkMacSetUpClippingRgn) /* 48 */ +#endif +#ifndef TkMacSetUpGraphicsPort +#define TkMacSetUpGraphicsPort \ + (tkIntPlatStubsPtr->tkMacSetUpGraphicsPort) /* 49 */ +#endif +#ifndef TkMacUpdateClipRgn +#define TkMacUpdateClipRgn \ + (tkIntPlatStubsPtr->tkMacUpdateClipRgn) /* 50 */ +#endif +#ifndef TkMacUnregisterMacWindow +#define TkMacUnregisterMacWindow \ + (tkIntPlatStubsPtr->tkMacUnregisterMacWindow) /* 51 */ +#endif +#ifndef TkMacUseMenuID +#define TkMacUseMenuID \ + (tkIntPlatStubsPtr->tkMacUseMenuID) /* 52 */ +#endif +#ifndef TkMacVisableClipRgn +#define TkMacVisableClipRgn \ + (tkIntPlatStubsPtr->tkMacVisableClipRgn) /* 53 */ +#endif +#ifndef TkMacWinBounds +#define TkMacWinBounds \ + (tkIntPlatStubsPtr->tkMacWinBounds) /* 54 */ +#endif +#ifndef TkMacWindowOffset +#define TkMacWindowOffset \ + (tkIntPlatStubsPtr->tkMacWindowOffset) /* 55 */ +#endif +#ifndef TkResumeClipboard +#define TkResumeClipboard \ + (tkIntPlatStubsPtr->tkResumeClipboard) /* 56 */ +#endif +#ifndef TkSetMacColor +#define TkSetMacColor \ + (tkIntPlatStubsPtr->tkSetMacColor) /* 57 */ +#endif +#ifndef TkSetWMName +#define TkSetWMName \ + (tkIntPlatStubsPtr->tkSetWMName) /* 58 */ +#endif +#ifndef TkSuspendClipboard +#define TkSuspendClipboard \ + (tkIntPlatStubsPtr->tkSuspendClipboard) /* 59 */ +#endif +#ifndef TkWMGrowToplevel +#define TkWMGrowToplevel \ + (tkIntPlatStubsPtr->tkWMGrowToplevel) /* 60 */ +#endif +#ifndef TkMacZoomToplevel +#define TkMacZoomToplevel \ + (tkIntPlatStubsPtr->tkMacZoomToplevel) /* 61 */ +#endif +#ifndef Tk_TopCoordsToWindow +#define Tk_TopCoordsToWindow \ + (tkIntPlatStubsPtr->tk_TopCoordsToWindow) /* 62 */ +#endif +#ifndef TkMacContainerId +#define TkMacContainerId \ + (tkIntPlatStubsPtr->tkMacContainerId) /* 63 */ +#endif +#ifndef TkMacGetHostToplevel +#define TkMacGetHostToplevel \ + (tkIntPlatStubsPtr->tkMacGetHostToplevel) /* 64 */ +#endif +#endif /* MAC_TCL */ + +#endif /* defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) */ + +/* !END!: Do not edit above this line. */ + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#endif /* _TKINTPLATDECLS */ diff --git a/tk/generic/tkIntXlibDecls.h b/tk/generic/tkIntXlibDecls.h new file mode 100644 index 00000000000..7126dd6bcc6 --- /dev/null +++ b/tk/generic/tkIntXlibDecls.h @@ -0,0 +1,1674 @@ +/* + * tkIntXlibDecls.h -- + * + * This file contains the declarations for all platform dependent + * unsupported functions that are exported by the Tk library. These + * interfaces are not guaranteed to remain the same between + * versions. Use at your own risk. + * + * Copyright (c) 1998-1999 by Scriptics Corporation. + * All rights reserved. + * + * RCS: @(#) $Id$ + */ + +#ifndef _TKINTXLIBDECLS +#define _TKINTXLIBDECLS + +#ifdef MAC_TCL +#include "Xutil.h" +#else +#include "X11/Xutil.h" +#endif + +#ifdef BUILD_tk +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLEXPORT +#endif + +/* + * WARNING: This file is automatically generated by the tools/genStubs.tcl + * script. Any modifications to the function declarations below should be made + * in the generic/tkInt.decls script. + */ + +/* !BEGIN!: Do not edit below this line. */ + +/* + * Exported function declarations: + */ + +#ifdef __WIN32__ +/* 0 */ +EXTERN void XSetDashes _ANSI_ARGS_((Display* display, GC gc, + int dash_offset, _Xconst char* dash_list, + int n)); +/* 1 */ +EXTERN XModifierKeymap* XGetModifierMapping _ANSI_ARGS_((Display* d)); +/* 2 */ +EXTERN XImage * XCreateImage _ANSI_ARGS_((Display* d, Visual* v, + unsigned int ui1, int i1, int i2, char* cp, + unsigned int ui2, unsigned int ui3, int i3, + int i4)); +/* 3 */ +EXTERN XImage * XGetImage _ANSI_ARGS_((Display* d, Drawable dr, + int i1, int i2, unsigned int ui1, + unsigned int ui2, unsigned long ul, int i3)); +/* 4 */ +EXTERN char * XGetAtomName _ANSI_ARGS_((Display* d, Atom a)); +/* 5 */ +EXTERN char * XKeysymToString _ANSI_ARGS_((KeySym k)); +/* 6 */ +EXTERN Colormap XCreateColormap _ANSI_ARGS_((Display* d, Window w, + Visual* v, int i)); +/* 7 */ +EXTERN Cursor XCreatePixmapCursor _ANSI_ARGS_((Display* d, + Pixmap p1, Pixmap p2, XColor* x1, XColor* x2, + unsigned int ui1, unsigned int ui2)); +/* 8 */ +EXTERN Cursor XCreateGlyphCursor _ANSI_ARGS_((Display* d, Font f1, + Font f2, unsigned int ui1, unsigned int ui2, + XColor* x1, XColor* x2)); +/* 9 */ +EXTERN GContext XGContextFromGC _ANSI_ARGS_((GC g)); +/* 10 */ +EXTERN XHostAddress * XListHosts _ANSI_ARGS_((Display* d, int* i, Bool* b)); +/* 11 */ +EXTERN KeySym XKeycodeToKeysym _ANSI_ARGS_((Display* d, + unsigned int k, int i)); +/* 12 */ +EXTERN KeySym XStringToKeysym _ANSI_ARGS_((_Xconst char* c)); +/* 13 */ +EXTERN Window XRootWindow _ANSI_ARGS_((Display* d, int i)); +/* 14 */ +EXTERN XErrorHandler XSetErrorHandler _ANSI_ARGS_((XErrorHandler x)); +/* 15 */ +EXTERN Status XIconifyWindow _ANSI_ARGS_((Display* d, Window w, + int i)); +/* 16 */ +EXTERN Status XWithdrawWindow _ANSI_ARGS_((Display* d, Window w, + int i)); +/* 17 */ +EXTERN Status XGetWMColormapWindows _ANSI_ARGS_((Display* d, + Window w, Window** wpp, int* ip)); +/* 18 */ +EXTERN Status XAllocColor _ANSI_ARGS_((Display* d, Colormap c, + XColor* xp)); +/* 19 */ +EXTERN void XBell _ANSI_ARGS_((Display* d, int i)); +/* 20 */ +EXTERN void XChangeProperty _ANSI_ARGS_((Display* d, Window w, + Atom a1, Atom a2, int i1, int i2, + _Xconst unsigned char* c, int i3)); +/* 21 */ +EXTERN void XChangeWindowAttributes _ANSI_ARGS_((Display* d, + Window w, unsigned long ul, + XSetWindowAttributes* x)); +/* 22 */ +EXTERN void XClearWindow _ANSI_ARGS_((Display* d, Window w)); +/* 23 */ +EXTERN void XConfigureWindow _ANSI_ARGS_((Display* d, Window w, + unsigned int i, XWindowChanges* x)); +/* 24 */ +EXTERN void XCopyArea _ANSI_ARGS_((Display* d, Drawable dr1, + Drawable dr2, GC g, int i1, int i2, + unsigned int ui1, unsigned int ui2, int i3, + int i4)); +/* 25 */ +EXTERN void XCopyPlane _ANSI_ARGS_((Display* d, Drawable dr1, + Drawable dr2, GC g, int i1, int i2, + unsigned int ui1, unsigned int ui2, int i3, + int i4, unsigned long ul)); +/* 26 */ +EXTERN Pixmap XCreateBitmapFromData _ANSI_ARGS_((Display* display, + Drawable d, _Xconst char* data, + unsigned int width, unsigned int height)); +/* 27 */ +EXTERN void XDefineCursor _ANSI_ARGS_((Display* d, Window w, + Cursor c)); +/* 28 */ +EXTERN void XDeleteProperty _ANSI_ARGS_((Display* d, Window w, + Atom a)); +/* 29 */ +EXTERN void XDestroyWindow _ANSI_ARGS_((Display* d, Window w)); +/* 30 */ +EXTERN void XDrawArc _ANSI_ARGS_((Display* d, Drawable dr, GC g, + int i1, int i2, unsigned int ui1, + unsigned int ui2, int i3, int i4)); +/* 31 */ +EXTERN void XDrawLines _ANSI_ARGS_((Display* d, Drawable dr, + GC g, XPoint* x, int i1, int i2)); +/* 32 */ +EXTERN void XDrawRectangle _ANSI_ARGS_((Display* d, Drawable dr, + GC g, int i1, int i2, unsigned int ui1, + unsigned int ui2)); +/* 33 */ +EXTERN void XFillArc _ANSI_ARGS_((Display* d, Drawable dr, GC g, + int i1, int i2, unsigned int ui1, + unsigned int ui2, int i3, int i4)); +/* 34 */ +EXTERN void XFillPolygon _ANSI_ARGS_((Display* d, Drawable dr, + GC g, XPoint* x, int i1, int i2, int i3)); +/* 35 */ +EXTERN void XFillRectangles _ANSI_ARGS_((Display* d, Drawable dr, + GC g, XRectangle* x, int i)); +/* 36 */ +EXTERN void XForceScreenSaver _ANSI_ARGS_((Display* d, int i)); +/* 37 */ +EXTERN void XFreeColormap _ANSI_ARGS_((Display* d, Colormap c)); +/* 38 */ +EXTERN void XFreeColors _ANSI_ARGS_((Display* d, Colormap c, + unsigned long* ulp, int i, unsigned long ul)); +/* 39 */ +EXTERN void XFreeCursor _ANSI_ARGS_((Display* d, Cursor c)); +/* 40 */ +EXTERN void XFreeModifiermap _ANSI_ARGS_((XModifierKeymap* x)); +/* 41 */ +EXTERN Status XGetGeometry _ANSI_ARGS_((Display* d, Drawable dr, + Window* w, int* i1, int* i2, + unsigned int* ui1, unsigned int* ui2, + unsigned int* ui3, unsigned int* ui4)); +/* 42 */ +EXTERN void XGetInputFocus _ANSI_ARGS_((Display* d, Window* w, + int* i)); +/* 43 */ +EXTERN int XGetWindowProperty _ANSI_ARGS_((Display* d, Window w, + Atom a1, long l1, long l2, Bool b, Atom a2, + Atom* ap, int* ip, unsigned long* ulp1, + unsigned long* ulp2, unsigned char** cpp)); +/* 44 */ +EXTERN Status XGetWindowAttributes _ANSI_ARGS_((Display* d, + Window w, XWindowAttributes* x)); +/* 45 */ +EXTERN int XGrabKeyboard _ANSI_ARGS_((Display* d, Window w, + Bool b, int i1, int i2, Time t)); +/* 46 */ +EXTERN int XGrabPointer _ANSI_ARGS_((Display* d, Window w1, + Bool b, unsigned int ui, int i1, int i2, + Window w2, Cursor c, Time t)); +/* 47 */ +EXTERN KeyCode XKeysymToKeycode _ANSI_ARGS_((Display* d, KeySym k)); +/* 48 */ +EXTERN Status XLookupColor _ANSI_ARGS_((Display* d, Colormap c1, + _Xconst char* c2, XColor* x1, XColor* x2)); +/* 49 */ +EXTERN void XMapWindow _ANSI_ARGS_((Display* d, Window w)); +/* 50 */ +EXTERN void XMoveResizeWindow _ANSI_ARGS_((Display* d, Window w, + int i1, int i2, unsigned int ui1, + unsigned int ui2)); +/* 51 */ +EXTERN void XMoveWindow _ANSI_ARGS_((Display* d, Window w, + int i1, int i2)); +/* 52 */ +EXTERN void XNextEvent _ANSI_ARGS_((Display* d, XEvent* x)); +/* 53 */ +EXTERN void XPutBackEvent _ANSI_ARGS_((Display* d, XEvent* x)); +/* 54 */ +EXTERN void XQueryColors _ANSI_ARGS_((Display* d, Colormap c, + XColor* x, int i)); +/* 55 */ +EXTERN Bool XQueryPointer _ANSI_ARGS_((Display* d, Window w1, + Window* w2, Window* w3, int* i1, int* i2, + int* i3, int* i4, unsigned int* ui)); +/* 56 */ +EXTERN Status XQueryTree _ANSI_ARGS_((Display* d, Window w1, + Window* w2, Window* w3, Window** w4, + unsigned int* ui)); +/* 57 */ +EXTERN void XRaiseWindow _ANSI_ARGS_((Display* d, Window w)); +/* 58 */ +EXTERN void XRefreshKeyboardMapping _ANSI_ARGS_(( + XMappingEvent* x)); +/* 59 */ +EXTERN void XResizeWindow _ANSI_ARGS_((Display* d, Window w, + unsigned int ui1, unsigned int ui2)); +/* 60 */ +EXTERN void XSelectInput _ANSI_ARGS_((Display* d, Window w, + long l)); +/* 61 */ +EXTERN Status XSendEvent _ANSI_ARGS_((Display* d, Window w, Bool b, + long l, XEvent* x)); +/* 62 */ +EXTERN void XSetCommand _ANSI_ARGS_((Display* d, Window w, + char** c, int i)); +/* 63 */ +EXTERN void XSetIconName _ANSI_ARGS_((Display* d, Window w, + _Xconst char* c)); +/* 64 */ +EXTERN void XSetInputFocus _ANSI_ARGS_((Display* d, Window w, + int i, Time t)); +/* 65 */ +EXTERN void XSetSelectionOwner _ANSI_ARGS_((Display* d, Atom a, + Window w, Time t)); +/* 66 */ +EXTERN void XSetWindowBackground _ANSI_ARGS_((Display* d, + Window w, unsigned long ul)); +/* 67 */ +EXTERN void XSetWindowBackgroundPixmap _ANSI_ARGS_((Display* d, + Window w, Pixmap p)); +/* 68 */ +EXTERN void XSetWindowBorder _ANSI_ARGS_((Display* d, Window w, + unsigned long ul)); +/* 69 */ +EXTERN void XSetWindowBorderPixmap _ANSI_ARGS_((Display* d, + Window w, Pixmap p)); +/* 70 */ +EXTERN void XSetWindowBorderWidth _ANSI_ARGS_((Display* d, + Window w, unsigned int ui)); +/* 71 */ +EXTERN void XSetWindowColormap _ANSI_ARGS_((Display* d, Window w, + Colormap c)); +/* 72 */ +EXTERN Bool XTranslateCoordinates _ANSI_ARGS_((Display* d, + Window w1, Window w2, int i1, int i2, + int* i3, int* i4, Window* w3)); +/* 73 */ +EXTERN void XUngrabKeyboard _ANSI_ARGS_((Display* d, Time t)); +/* 74 */ +EXTERN void XUngrabPointer _ANSI_ARGS_((Display* d, Time t)); +/* 75 */ +EXTERN void XUnmapWindow _ANSI_ARGS_((Display* d, Window w)); +/* 76 */ +EXTERN void XWindowEvent _ANSI_ARGS_((Display* d, Window w, + long l, XEvent* x)); +/* 77 */ +EXTERN void XDestroyIC _ANSI_ARGS_((XIC x)); +/* 78 */ +EXTERN Bool XFilterEvent _ANSI_ARGS_((XEvent* x, Window w)); +/* 79 */ +EXTERN int XmbLookupString _ANSI_ARGS_((XIC xi, + XKeyPressedEvent* xk, char* c, int i, + KeySym* k, Status* s)); +/* 80 */ +EXTERN void TkPutImage _ANSI_ARGS_((unsigned long * colors, + int ncolors, Display* display, Drawable d, + GC gc, XImage* image, int src_x, int src_y, + int dest_x, int dest_y, unsigned int width, + unsigned int height)); +/* Slot 81 is reserved */ +/* 82 */ +EXTERN Status XParseColor _ANSI_ARGS_((Display * display, + Colormap map, _Xconst char* spec, + XColor * colorPtr)); +/* 83 */ +EXTERN GC XCreateGC _ANSI_ARGS_((Display* display, Drawable d, + unsigned long valuemask, XGCValues* values)); +/* 84 */ +EXTERN void XFreeGC _ANSI_ARGS_((Display* display, GC gc)); +/* 85 */ +EXTERN Atom XInternAtom _ANSI_ARGS_((Display* display, + _Xconst char* atom_name, Bool only_if_exists)); +/* 86 */ +EXTERN void XSetBackground _ANSI_ARGS_((Display* display, GC gc, + unsigned long foreground)); +/* 87 */ +EXTERN void XSetForeground _ANSI_ARGS_((Display* display, GC gc, + unsigned long foreground)); +/* 88 */ +EXTERN void XSetClipMask _ANSI_ARGS_((Display* display, GC gc, + Pixmap pixmap)); +/* 89 */ +EXTERN void XSetClipOrigin _ANSI_ARGS_((Display* display, GC gc, + int clip_x_origin, int clip_y_origin)); +/* 90 */ +EXTERN void XSetTSOrigin _ANSI_ARGS_((Display* display, GC gc, + int ts_x_origin, int ts_y_origin)); +/* 91 */ +EXTERN void XChangeGC _ANSI_ARGS_((Display * d, GC gc, + unsigned long mask, XGCValues * values)); +/* 92 */ +EXTERN void XSetFont _ANSI_ARGS_((Display * display, GC gc, + Font font)); +/* 93 */ +EXTERN void XSetArcMode _ANSI_ARGS_((Display * display, GC gc, + int arc_mode)); +/* 94 */ +EXTERN void XSetStipple _ANSI_ARGS_((Display * display, GC gc, + Pixmap stipple)); +/* 95 */ +EXTERN void XSetFillRule _ANSI_ARGS_((Display * display, GC gc, + int fill_rule)); +/* 96 */ +EXTERN void XSetFillStyle _ANSI_ARGS_((Display * display, GC gc, + int fill_style)); +/* 97 */ +EXTERN void XSetFunction _ANSI_ARGS_((Display * display, GC gc, + int function)); +/* 98 */ +EXTERN void XSetLineAttributes _ANSI_ARGS_((Display * display, + GC gc, unsigned int line_width, + int line_style, int cap_style, + int join_style)); +/* 99 */ +EXTERN int _XInitImageFuncPtrs _ANSI_ARGS_((XImage * image)); +/* 100 */ +EXTERN XIC XCreateIC _ANSI_ARGS_((void)); +/* 101 */ +EXTERN XVisualInfo * XGetVisualInfo _ANSI_ARGS_((Display* display, + long vinfo_mask, XVisualInfo* vinfo_template, + int* nitems_return)); +/* 102 */ +EXTERN void XSetWMClientMachine _ANSI_ARGS_((Display* display, + Window w, XTextProperty* text_prop)); +/* 103 */ +EXTERN Status XStringListToTextProperty _ANSI_ARGS_((char** list, + int count, XTextProperty* text_prop_return)); +/* 104 */ +EXTERN void XDrawLine _ANSI_ARGS_((Display* d, Drawable dr, GC g, + int x1, int y1, int x2, int y2)); +/* 105 */ +EXTERN void XWarpPointer _ANSI_ARGS_((Display* d, Window s, + Window dw, int sx, int sy, unsigned int sw, + unsigned int sh, int dx, int dy)); +/* 106 */ +EXTERN void XFillRectangle _ANSI_ARGS_((Display* display, + Drawable d, GC gc, int x, int y, + unsigned int width, unsigned int height)); +#endif /* __WIN32__ */ +#ifdef MAC_TCL +/* 0 */ +EXTERN void XSetDashes _ANSI_ARGS_((Display* display, GC gc, + int dash_offset, _Xconst char* dash_list, + int n)); +/* 1 */ +EXTERN XModifierKeymap* XGetModifierMapping _ANSI_ARGS_((Display* d)); +/* 2 */ +EXTERN XImage * XCreateImage _ANSI_ARGS_((Display* d, Visual* v, + unsigned int ui1, int i1, int i2, char* cp, + unsigned int ui2, unsigned int ui3, int i3, + int i4)); +/* 3 */ +EXTERN XImage * XGetImage _ANSI_ARGS_((Display* d, Drawable dr, + int i1, int i2, unsigned int ui1, + unsigned int ui2, unsigned long ul, int i3)); +/* 4 */ +EXTERN char * XGetAtomName _ANSI_ARGS_((Display* d, Atom a)); +/* 5 */ +EXTERN char * XKeysymToString _ANSI_ARGS_((KeySym k)); +/* 6 */ +EXTERN Colormap XCreateColormap _ANSI_ARGS_((Display* d, Window w, + Visual* v, int i)); +/* 7 */ +EXTERN GContext XGContextFromGC _ANSI_ARGS_((GC g)); +/* 8 */ +EXTERN KeySym XKeycodeToKeysym _ANSI_ARGS_((Display* d, KeyCode k, + int i)); +/* 9 */ +EXTERN KeySym XStringToKeysym _ANSI_ARGS_((_Xconst char* c)); +/* 10 */ +EXTERN Window XRootWindow _ANSI_ARGS_((Display* d, int i)); +/* 11 */ +EXTERN XErrorHandler XSetErrorHandler _ANSI_ARGS_((XErrorHandler x)); +/* 12 */ +EXTERN Status XAllocColor _ANSI_ARGS_((Display* d, Colormap c, + XColor* xp)); +/* 13 */ +EXTERN void XBell _ANSI_ARGS_((Display* d, int i)); +/* 14 */ +EXTERN void XChangeProperty _ANSI_ARGS_((Display* d, Window w, + Atom a1, Atom a2, int i1, int i2, + _Xconst unsigned char* c, int i3)); +/* 15 */ +EXTERN void XChangeWindowAttributes _ANSI_ARGS_((Display* d, + Window w, unsigned long ul, + XSetWindowAttributes* x)); +/* 16 */ +EXTERN void XConfigureWindow _ANSI_ARGS_((Display* d, Window w, + unsigned int i, XWindowChanges* x)); +/* 17 */ +EXTERN void XCopyArea _ANSI_ARGS_((Display* d, Drawable dr1, + Drawable dr2, GC g, int i1, int i2, + unsigned int ui1, unsigned int ui2, int i3, + int i4)); +/* 18 */ +EXTERN void XCopyPlane _ANSI_ARGS_((Display* d, Drawable dr1, + Drawable dr2, GC g, int i1, int i2, + unsigned int ui1, unsigned int ui2, int i3, + int i4, unsigned long ul)); +/* 19 */ +EXTERN Pixmap XCreateBitmapFromData _ANSI_ARGS_((Display* display, + Drawable d, _Xconst char* data, + unsigned int width, unsigned int height)); +/* 20 */ +EXTERN void XDefineCursor _ANSI_ARGS_((Display* d, Window w, + Cursor c)); +/* 21 */ +EXTERN void XDestroyWindow _ANSI_ARGS_((Display* d, Window w)); +/* 22 */ +EXTERN void XDrawArc _ANSI_ARGS_((Display* d, Drawable dr, GC g, + int i1, int i2, unsigned int ui1, + unsigned int ui2, int i3, int i4)); +/* 23 */ +EXTERN void XDrawLines _ANSI_ARGS_((Display* d, Drawable dr, + GC g, XPoint* x, int i1, int i2)); +/* 24 */ +EXTERN void XDrawRectangle _ANSI_ARGS_((Display* d, Drawable dr, + GC g, int i1, int i2, unsigned int ui1, + unsigned int ui2)); +/* 25 */ +EXTERN void XFillArc _ANSI_ARGS_((Display* d, Drawable dr, GC g, + int i1, int i2, unsigned int ui1, + unsigned int ui2, int i3, int i4)); +/* 26 */ +EXTERN void XFillPolygon _ANSI_ARGS_((Display* d, Drawable dr, + GC g, XPoint* x, int i1, int i2, int i3)); +/* 27 */ +EXTERN void XFillRectangles _ANSI_ARGS_((Display* d, Drawable dr, + GC g, XRectangle* x, int i)); +/* 28 */ +EXTERN void XFreeColormap _ANSI_ARGS_((Display* d, Colormap c)); +/* 29 */ +EXTERN void XFreeColors _ANSI_ARGS_((Display* d, Colormap c, + unsigned long* ulp, int i, unsigned long ul)); +/* 30 */ +EXTERN void XFreeModifiermap _ANSI_ARGS_((XModifierKeymap* x)); +/* 31 */ +EXTERN Status XGetGeometry _ANSI_ARGS_((Display* d, Drawable dr, + Window* w, int* i1, int* i2, + unsigned int* ui1, unsigned int* ui2, + unsigned int* ui3, unsigned int* ui4)); +/* 32 */ +EXTERN int XGetWindowProperty _ANSI_ARGS_((Display* d, Window w, + Atom a1, long l1, long l2, Bool b, Atom a2, + Atom* ap, int* ip, unsigned long* ulp1, + unsigned long* ulp2, unsigned char** cpp)); +/* 33 */ +EXTERN int XGrabKeyboard _ANSI_ARGS_((Display* d, Window w, + Bool b, int i1, int i2, Time t)); +/* 34 */ +EXTERN int XGrabPointer _ANSI_ARGS_((Display* d, Window w1, + Bool b, unsigned int ui, int i1, int i2, + Window w2, Cursor c, Time t)); +/* 35 */ +EXTERN KeyCode XKeysymToKeycode _ANSI_ARGS_((Display* d, KeySym k)); +/* 36 */ +EXTERN void XMapWindow _ANSI_ARGS_((Display* d, Window w)); +/* 37 */ +EXTERN void XMoveResizeWindow _ANSI_ARGS_((Display* d, Window w, + int i1, int i2, unsigned int ui1, + unsigned int ui2)); +/* 38 */ +EXTERN void XMoveWindow _ANSI_ARGS_((Display* d, Window w, + int i1, int i2)); +/* 39 */ +EXTERN Bool XQueryPointer _ANSI_ARGS_((Display* d, Window w1, + Window* w2, Window* w3, int* i1, int* i2, + int* i3, int* i4, unsigned int* ui)); +/* 40 */ +EXTERN void XRaiseWindow _ANSI_ARGS_((Display* d, Window w)); +/* 41 */ +EXTERN void XRefreshKeyboardMapping _ANSI_ARGS_(( + XMappingEvent* x)); +/* 42 */ +EXTERN void XResizeWindow _ANSI_ARGS_((Display* d, Window w, + unsigned int ui1, unsigned int ui2)); +/* 43 */ +EXTERN void XSelectInput _ANSI_ARGS_((Display* d, Window w, + long l)); +/* 44 */ +EXTERN Status XSendEvent _ANSI_ARGS_((Display* d, Window w, Bool b, + long l, XEvent* x)); +/* 45 */ +EXTERN void XSetIconName _ANSI_ARGS_((Display* d, Window w, + _Xconst char* c)); +/* 46 */ +EXTERN void XSetInputFocus _ANSI_ARGS_((Display* d, Window w, + int i, Time t)); +/* 47 */ +EXTERN void XSetSelectionOwner _ANSI_ARGS_((Display* d, Atom a, + Window w, Time t)); +/* 48 */ +EXTERN void XSetWindowBackground _ANSI_ARGS_((Display* d, + Window w, unsigned long ul)); +/* 49 */ +EXTERN void XSetWindowBackgroundPixmap _ANSI_ARGS_((Display* d, + Window w, Pixmap p)); +/* 50 */ +EXTERN void XSetWindowBorder _ANSI_ARGS_((Display* d, Window w, + unsigned long ul)); +/* 51 */ +EXTERN void XSetWindowBorderPixmap _ANSI_ARGS_((Display* d, + Window w, Pixmap p)); +/* 52 */ +EXTERN void XSetWindowBorderWidth _ANSI_ARGS_((Display* d, + Window w, unsigned int ui)); +/* 53 */ +EXTERN void XSetWindowColormap _ANSI_ARGS_((Display* d, Window w, + Colormap c)); +/* 54 */ +EXTERN void XUngrabKeyboard _ANSI_ARGS_((Display* d, Time t)); +/* 55 */ +EXTERN void XUngrabPointer _ANSI_ARGS_((Display* d, Time t)); +/* 56 */ +EXTERN void XUnmapWindow _ANSI_ARGS_((Display* d, Window w)); +/* 57 */ +EXTERN void TkPutImage _ANSI_ARGS_((unsigned long * colors, + int ncolors, Display* display, Drawable d, + GC gc, XImage* image, int src_x, int src_y, + int dest_x, int dest_y, unsigned int width, + unsigned int height)); +/* 58 */ +EXTERN Status XParseColor _ANSI_ARGS_((Display * display, + Colormap map, _Xconst char* spec, + XColor * colorPtr)); +/* 59 */ +EXTERN GC XCreateGC _ANSI_ARGS_((Display* display, Drawable d, + unsigned long valuemask, XGCValues* values)); +/* 60 */ +EXTERN void XFreeGC _ANSI_ARGS_((Display* display, GC gc)); +/* 61 */ +EXTERN Atom XInternAtom _ANSI_ARGS_((Display* display, + _Xconst char* atom_name, Bool only_if_exists)); +/* 62 */ +EXTERN void XSetBackground _ANSI_ARGS_((Display* display, GC gc, + unsigned long foreground)); +/* 63 */ +EXTERN void XSetForeground _ANSI_ARGS_((Display* display, GC gc, + unsigned long foreground)); +/* 64 */ +EXTERN void XSetClipMask _ANSI_ARGS_((Display* display, GC gc, + Pixmap pixmap)); +/* 65 */ +EXTERN void XSetClipOrigin _ANSI_ARGS_((Display* display, GC gc, + int clip_x_origin, int clip_y_origin)); +/* 66 */ +EXTERN void XSetTSOrigin _ANSI_ARGS_((Display* display, GC gc, + int ts_x_origin, int ts_y_origin)); +/* 67 */ +EXTERN void XChangeGC _ANSI_ARGS_((Display * d, GC gc, + unsigned long mask, XGCValues * values)); +/* 68 */ +EXTERN void XSetFont _ANSI_ARGS_((Display * display, GC gc, + Font font)); +/* 69 */ +EXTERN void XSetArcMode _ANSI_ARGS_((Display * display, GC gc, + int arc_mode)); +/* 70 */ +EXTERN void XSetStipple _ANSI_ARGS_((Display * display, GC gc, + Pixmap stipple)); +/* 71 */ +EXTERN void XSetFillRule _ANSI_ARGS_((Display * display, GC gc, + int fill_rule)); +/* 72 */ +EXTERN void XSetFillStyle _ANSI_ARGS_((Display * display, GC gc, + int fill_style)); +/* 73 */ +EXTERN void XSetFunction _ANSI_ARGS_((Display * display, GC gc, + int function)); +/* 74 */ +EXTERN void XSetLineAttributes _ANSI_ARGS_((Display * display, + GC gc, unsigned int line_width, + int line_style, int cap_style, + int join_style)); +/* 75 */ +EXTERN int _XInitImageFuncPtrs _ANSI_ARGS_((XImage * image)); +/* 76 */ +EXTERN XIC XCreateIC _ANSI_ARGS_((void)); +/* 77 */ +EXTERN XVisualInfo * XGetVisualInfo _ANSI_ARGS_((Display* display, + long vinfo_mask, XVisualInfo* vinfo_template, + int* nitems_return)); +/* 78 */ +EXTERN void XSetWMClientMachine _ANSI_ARGS_((Display* display, + Window w, XTextProperty* text_prop)); +/* 79 */ +EXTERN Status XStringListToTextProperty _ANSI_ARGS_((char** list, + int count, XTextProperty* text_prop_return)); +/* 80 */ +EXTERN void XDrawSegments _ANSI_ARGS_((Display * display, + Drawable d, GC gc, XSegment * segments, + int nsegments)); +/* 81 */ +EXTERN void XForceScreenSaver _ANSI_ARGS_((Display* display, + int mode)); +/* 82 */ +EXTERN void XDrawLine _ANSI_ARGS_((Display* d, Drawable dr, GC g, + int x1, int y1, int x2, int y2)); +/* 83 */ +EXTERN void XFillRectangle _ANSI_ARGS_((Display* display, + Drawable d, GC gc, int x, int y, + unsigned int width, unsigned int height)); +/* 84 */ +EXTERN void XClearWindow _ANSI_ARGS_((Display* d, Window w)); +/* 85 */ +EXTERN void XDrawPoint _ANSI_ARGS_((Display* display, Drawable d, + GC gc, int x, int y)); +/* 86 */ +EXTERN void XDrawPoints _ANSI_ARGS_((Display* display, + Drawable d, GC gc, XPoint * points, + int npoints, int mode)); +/* 87 */ +EXTERN void XWarpPointer _ANSI_ARGS_((Display* display, + Window src_w, Window dest_w, int src_x, + int src_y, unsigned int src_width, + unsigned int src_height, int dest_x, + int dest_y)); +/* 88 */ +EXTERN void XQueryColor _ANSI_ARGS_((Display * display, + Colormap colormap, XColor * def_in_out)); +/* 89 */ +EXTERN void XQueryColors _ANSI_ARGS_((Display * display, + Colormap colormap, XColor * defs_in_out, + int ncolors)); +#endif /* MAC_TCL */ + +typedef struct TkIntXlibStubs { + int magic; + struct TkIntXlibStubHooks *hooks; + +#ifdef __WIN32__ + void (*xSetDashes) _ANSI_ARGS_((Display* display, GC gc, int dash_offset, _Xconst char* dash_list, int n)); /* 0 */ + XModifierKeymap* (*xGetModifierMapping) _ANSI_ARGS_((Display* d)); /* 1 */ + XImage * (*xCreateImage) _ANSI_ARGS_((Display* d, Visual* v, unsigned int ui1, int i1, int i2, char* cp, unsigned int ui2, unsigned int ui3, int i3, int i4)); /* 2 */ + XImage * (*xGetImage) _ANSI_ARGS_((Display* d, Drawable dr, int i1, int i2, unsigned int ui1, unsigned int ui2, unsigned long ul, int i3)); /* 3 */ + char * (*xGetAtomName) _ANSI_ARGS_((Display* d, Atom a)); /* 4 */ + char * (*xKeysymToString) _ANSI_ARGS_((KeySym k)); /* 5 */ + Colormap (*xCreateColormap) _ANSI_ARGS_((Display* d, Window w, Visual* v, int i)); /* 6 */ + Cursor (*xCreatePixmapCursor) _ANSI_ARGS_((Display* d, Pixmap p1, Pixmap p2, XColor* x1, XColor* x2, unsigned int ui1, unsigned int ui2)); /* 7 */ + Cursor (*xCreateGlyphCursor) _ANSI_ARGS_((Display* d, Font f1, Font f2, unsigned int ui1, unsigned int ui2, XColor* x1, XColor* x2)); /* 8 */ + GContext (*xGContextFromGC) _ANSI_ARGS_((GC g)); /* 9 */ + XHostAddress * (*xListHosts) _ANSI_ARGS_((Display* d, int* i, Bool* b)); /* 10 */ + KeySym (*xKeycodeToKeysym) _ANSI_ARGS_((Display* d, unsigned int k, int i)); /* 11 */ + KeySym (*xStringToKeysym) _ANSI_ARGS_((_Xconst char* c)); /* 12 */ + Window (*xRootWindow) _ANSI_ARGS_((Display* d, int i)); /* 13 */ + XErrorHandler (*xSetErrorHandler) _ANSI_ARGS_((XErrorHandler x)); /* 14 */ + Status (*xIconifyWindow) _ANSI_ARGS_((Display* d, Window w, int i)); /* 15 */ + Status (*xWithdrawWindow) _ANSI_ARGS_((Display* d, Window w, int i)); /* 16 */ + Status (*xGetWMColormapWindows) _ANSI_ARGS_((Display* d, Window w, Window** wpp, int* ip)); /* 17 */ + Status (*xAllocColor) _ANSI_ARGS_((Display* d, Colormap c, XColor* xp)); /* 18 */ + void (*xBell) _ANSI_ARGS_((Display* d, int i)); /* 19 */ + void (*xChangeProperty) _ANSI_ARGS_((Display* d, Window w, Atom a1, Atom a2, int i1, int i2, _Xconst unsigned char* c, int i3)); /* 20 */ + void (*xChangeWindowAttributes) _ANSI_ARGS_((Display* d, Window w, unsigned long ul, XSetWindowAttributes* x)); /* 21 */ + void (*xClearWindow) _ANSI_ARGS_((Display* d, Window w)); /* 22 */ + void (*xConfigureWindow) _ANSI_ARGS_((Display* d, Window w, unsigned int i, XWindowChanges* x)); /* 23 */ + void (*xCopyArea) _ANSI_ARGS_((Display* d, Drawable dr1, Drawable dr2, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4)); /* 24 */ + void (*xCopyPlane) _ANSI_ARGS_((Display* d, Drawable dr1, Drawable dr2, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4, unsigned long ul)); /* 25 */ + Pixmap (*xCreateBitmapFromData) _ANSI_ARGS_((Display* display, Drawable d, _Xconst char* data, unsigned int width, unsigned int height)); /* 26 */ + void (*xDefineCursor) _ANSI_ARGS_((Display* d, Window w, Cursor c)); /* 27 */ + void (*xDeleteProperty) _ANSI_ARGS_((Display* d, Window w, Atom a)); /* 28 */ + void (*xDestroyWindow) _ANSI_ARGS_((Display* d, Window w)); /* 29 */ + void (*xDrawArc) _ANSI_ARGS_((Display* d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4)); /* 30 */ + void (*xDrawLines) _ANSI_ARGS_((Display* d, Drawable dr, GC g, XPoint* x, int i1, int i2)); /* 31 */ + void (*xDrawRectangle) _ANSI_ARGS_((Display* d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2)); /* 32 */ + void (*xFillArc) _ANSI_ARGS_((Display* d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4)); /* 33 */ + void (*xFillPolygon) _ANSI_ARGS_((Display* d, Drawable dr, GC g, XPoint* x, int i1, int i2, int i3)); /* 34 */ + void (*xFillRectangles) _ANSI_ARGS_((Display* d, Drawable dr, GC g, XRectangle* x, int i)); /* 35 */ + void (*xForceScreenSaver) _ANSI_ARGS_((Display* d, int i)); /* 36 */ + void (*xFreeColormap) _ANSI_ARGS_((Display* d, Colormap c)); /* 37 */ + void (*xFreeColors) _ANSI_ARGS_((Display* d, Colormap c, unsigned long* ulp, int i, unsigned long ul)); /* 38 */ + void (*xFreeCursor) _ANSI_ARGS_((Display* d, Cursor c)); /* 39 */ + void (*xFreeModifiermap) _ANSI_ARGS_((XModifierKeymap* x)); /* 40 */ + Status (*xGetGeometry) _ANSI_ARGS_((Display* d, Drawable dr, Window* w, int* i1, int* i2, unsigned int* ui1, unsigned int* ui2, unsigned int* ui3, unsigned int* ui4)); /* 41 */ + void (*xGetInputFocus) _ANSI_ARGS_((Display* d, Window* w, int* i)); /* 42 */ + int (*xGetWindowProperty) _ANSI_ARGS_((Display* d, Window w, Atom a1, long l1, long l2, Bool b, Atom a2, Atom* ap, int* ip, unsigned long* ulp1, unsigned long* ulp2, unsigned char** cpp)); /* 43 */ + Status (*xGetWindowAttributes) _ANSI_ARGS_((Display* d, Window w, XWindowAttributes* x)); /* 44 */ + int (*xGrabKeyboard) _ANSI_ARGS_((Display* d, Window w, Bool b, int i1, int i2, Time t)); /* 45 */ + int (*xGrabPointer) _ANSI_ARGS_((Display* d, Window w1, Bool b, unsigned int ui, int i1, int i2, Window w2, Cursor c, Time t)); /* 46 */ + KeyCode (*xKeysymToKeycode) _ANSI_ARGS_((Display* d, KeySym k)); /* 47 */ + Status (*xLookupColor) _ANSI_ARGS_((Display* d, Colormap c1, _Xconst char* c2, XColor* x1, XColor* x2)); /* 48 */ + void (*xMapWindow) _ANSI_ARGS_((Display* d, Window w)); /* 49 */ + void (*xMoveResizeWindow) _ANSI_ARGS_((Display* d, Window w, int i1, int i2, unsigned int ui1, unsigned int ui2)); /* 50 */ + void (*xMoveWindow) _ANSI_ARGS_((Display* d, Window w, int i1, int i2)); /* 51 */ + void (*xNextEvent) _ANSI_ARGS_((Display* d, XEvent* x)); /* 52 */ + void (*xPutBackEvent) _ANSI_ARGS_((Display* d, XEvent* x)); /* 53 */ + void (*xQueryColors) _ANSI_ARGS_((Display* d, Colormap c, XColor* x, int i)); /* 54 */ + Bool (*xQueryPointer) _ANSI_ARGS_((Display* d, Window w1, Window* w2, Window* w3, int* i1, int* i2, int* i3, int* i4, unsigned int* ui)); /* 55 */ + Status (*xQueryTree) _ANSI_ARGS_((Display* d, Window w1, Window* w2, Window* w3, Window** w4, unsigned int* ui)); /* 56 */ + void (*xRaiseWindow) _ANSI_ARGS_((Display* d, Window w)); /* 57 */ + void (*xRefreshKeyboardMapping) _ANSI_ARGS_((XMappingEvent* x)); /* 58 */ + void (*xResizeWindow) _ANSI_ARGS_((Display* d, Window w, unsigned int ui1, unsigned int ui2)); /* 59 */ + void (*xSelectInput) _ANSI_ARGS_((Display* d, Window w, long l)); /* 60 */ + Status (*xSendEvent) _ANSI_ARGS_((Display* d, Window w, Bool b, long l, XEvent* x)); /* 61 */ + void (*xSetCommand) _ANSI_ARGS_((Display* d, Window w, char** c, int i)); /* 62 */ + void (*xSetIconName) _ANSI_ARGS_((Display* d, Window w, _Xconst char* c)); /* 63 */ + void (*xSetInputFocus) _ANSI_ARGS_((Display* d, Window w, int i, Time t)); /* 64 */ + void (*xSetSelectionOwner) _ANSI_ARGS_((Display* d, Atom a, Window w, Time t)); /* 65 */ + void (*xSetWindowBackground) _ANSI_ARGS_((Display* d, Window w, unsigned long ul)); /* 66 */ + void (*xSetWindowBackgroundPixmap) _ANSI_ARGS_((Display* d, Window w, Pixmap p)); /* 67 */ + void (*xSetWindowBorder) _ANSI_ARGS_((Display* d, Window w, unsigned long ul)); /* 68 */ + void (*xSetWindowBorderPixmap) _ANSI_ARGS_((Display* d, Window w, Pixmap p)); /* 69 */ + void (*xSetWindowBorderWidth) _ANSI_ARGS_((Display* d, Window w, unsigned int ui)); /* 70 */ + void (*xSetWindowColormap) _ANSI_ARGS_((Display* d, Window w, Colormap c)); /* 71 */ + Bool (*xTranslateCoordinates) _ANSI_ARGS_((Display* d, Window w1, Window w2, int i1, int i2, int* i3, int* i4, Window* w3)); /* 72 */ + void (*xUngrabKeyboard) _ANSI_ARGS_((Display* d, Time t)); /* 73 */ + void (*xUngrabPointer) _ANSI_ARGS_((Display* d, Time t)); /* 74 */ + void (*xUnmapWindow) _ANSI_ARGS_((Display* d, Window w)); /* 75 */ + void (*xWindowEvent) _ANSI_ARGS_((Display* d, Window w, long l, XEvent* x)); /* 76 */ + void (*xDestroyIC) _ANSI_ARGS_((XIC x)); /* 77 */ + Bool (*xFilterEvent) _ANSI_ARGS_((XEvent* x, Window w)); /* 78 */ + int (*xmbLookupString) _ANSI_ARGS_((XIC xi, XKeyPressedEvent* xk, char* c, int i, KeySym* k, Status* s)); /* 79 */ + void (*tkPutImage) _ANSI_ARGS_((unsigned long * colors, int ncolors, Display* display, Drawable d, GC gc, XImage* image, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height)); /* 80 */ + void *reserved81; + Status (*xParseColor) _ANSI_ARGS_((Display * display, Colormap map, _Xconst char* spec, XColor * colorPtr)); /* 82 */ + GC (*xCreateGC) _ANSI_ARGS_((Display* display, Drawable d, unsigned long valuemask, XGCValues* values)); /* 83 */ + void (*xFreeGC) _ANSI_ARGS_((Display* display, GC gc)); /* 84 */ + Atom (*xInternAtom) _ANSI_ARGS_((Display* display, _Xconst char* atom_name, Bool only_if_exists)); /* 85 */ + void (*xSetBackground) _ANSI_ARGS_((Display* display, GC gc, unsigned long foreground)); /* 86 */ + void (*xSetForeground) _ANSI_ARGS_((Display* display, GC gc, unsigned long foreground)); /* 87 */ + void (*xSetClipMask) _ANSI_ARGS_((Display* display, GC gc, Pixmap pixmap)); /* 88 */ + void (*xSetClipOrigin) _ANSI_ARGS_((Display* display, GC gc, int clip_x_origin, int clip_y_origin)); /* 89 */ + void (*xSetTSOrigin) _ANSI_ARGS_((Display* display, GC gc, int ts_x_origin, int ts_y_origin)); /* 90 */ + void (*xChangeGC) _ANSI_ARGS_((Display * d, GC gc, unsigned long mask, XGCValues * values)); /* 91 */ + void (*xSetFont) _ANSI_ARGS_((Display * display, GC gc, Font font)); /* 92 */ + void (*xSetArcMode) _ANSI_ARGS_((Display * display, GC gc, int arc_mode)); /* 93 */ + void (*xSetStipple) _ANSI_ARGS_((Display * display, GC gc, Pixmap stipple)); /* 94 */ + void (*xSetFillRule) _ANSI_ARGS_((Display * display, GC gc, int fill_rule)); /* 95 */ + void (*xSetFillStyle) _ANSI_ARGS_((Display * display, GC gc, int fill_style)); /* 96 */ + void (*xSetFunction) _ANSI_ARGS_((Display * display, GC gc, int function)); /* 97 */ + void (*xSetLineAttributes) _ANSI_ARGS_((Display * display, GC gc, unsigned int line_width, int line_style, int cap_style, int join_style)); /* 98 */ + int (*_XInitImageFuncPtrs) _ANSI_ARGS_((XImage * image)); /* 99 */ + XIC (*xCreateIC) _ANSI_ARGS_((void)); /* 100 */ + XVisualInfo * (*xGetVisualInfo) _ANSI_ARGS_((Display* display, long vinfo_mask, XVisualInfo* vinfo_template, int* nitems_return)); /* 101 */ + void (*xSetWMClientMachine) _ANSI_ARGS_((Display* display, Window w, XTextProperty* text_prop)); /* 102 */ + Status (*xStringListToTextProperty) _ANSI_ARGS_((char** list, int count, XTextProperty* text_prop_return)); /* 103 */ + void (*xDrawLine) _ANSI_ARGS_((Display* d, Drawable dr, GC g, int x1, int y1, int x2, int y2)); /* 104 */ + void (*xWarpPointer) _ANSI_ARGS_((Display* d, Window s, Window dw, int sx, int sy, unsigned int sw, unsigned int sh, int dx, int dy)); /* 105 */ + void (*xFillRectangle) _ANSI_ARGS_((Display* display, Drawable d, GC gc, int x, int y, unsigned int width, unsigned int height)); /* 106 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*xSetDashes) _ANSI_ARGS_((Display* display, GC gc, int dash_offset, _Xconst char* dash_list, int n)); /* 0 */ + XModifierKeymap* (*xGetModifierMapping) _ANSI_ARGS_((Display* d)); /* 1 */ + XImage * (*xCreateImage) _ANSI_ARGS_((Display* d, Visual* v, unsigned int ui1, int i1, int i2, char* cp, unsigned int ui2, unsigned int ui3, int i3, int i4)); /* 2 */ + XImage * (*xGetImage) _ANSI_ARGS_((Display* d, Drawable dr, int i1, int i2, unsigned int ui1, unsigned int ui2, unsigned long ul, int i3)); /* 3 */ + char * (*xGetAtomName) _ANSI_ARGS_((Display* d, Atom a)); /* 4 */ + char * (*xKeysymToString) _ANSI_ARGS_((KeySym k)); /* 5 */ + Colormap (*xCreateColormap) _ANSI_ARGS_((Display* d, Window w, Visual* v, int i)); /* 6 */ + GContext (*xGContextFromGC) _ANSI_ARGS_((GC g)); /* 7 */ + KeySym (*xKeycodeToKeysym) _ANSI_ARGS_((Display* d, KeyCode k, int i)); /* 8 */ + KeySym (*xStringToKeysym) _ANSI_ARGS_((_Xconst char* c)); /* 9 */ + Window (*xRootWindow) _ANSI_ARGS_((Display* d, int i)); /* 10 */ + XErrorHandler (*xSetErrorHandler) _ANSI_ARGS_((XErrorHandler x)); /* 11 */ + Status (*xAllocColor) _ANSI_ARGS_((Display* d, Colormap c, XColor* xp)); /* 12 */ + void (*xBell) _ANSI_ARGS_((Display* d, int i)); /* 13 */ + void (*xChangeProperty) _ANSI_ARGS_((Display* d, Window w, Atom a1, Atom a2, int i1, int i2, _Xconst unsigned char* c, int i3)); /* 14 */ + void (*xChangeWindowAttributes) _ANSI_ARGS_((Display* d, Window w, unsigned long ul, XSetWindowAttributes* x)); /* 15 */ + void (*xConfigureWindow) _ANSI_ARGS_((Display* d, Window w, unsigned int i, XWindowChanges* x)); /* 16 */ + void (*xCopyArea) _ANSI_ARGS_((Display* d, Drawable dr1, Drawable dr2, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4)); /* 17 */ + void (*xCopyPlane) _ANSI_ARGS_((Display* d, Drawable dr1, Drawable dr2, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4, unsigned long ul)); /* 18 */ + Pixmap (*xCreateBitmapFromData) _ANSI_ARGS_((Display* display, Drawable d, _Xconst char* data, unsigned int width, unsigned int height)); /* 19 */ + void (*xDefineCursor) _ANSI_ARGS_((Display* d, Window w, Cursor c)); /* 20 */ + void (*xDestroyWindow) _ANSI_ARGS_((Display* d, Window w)); /* 21 */ + void (*xDrawArc) _ANSI_ARGS_((Display* d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4)); /* 22 */ + void (*xDrawLines) _ANSI_ARGS_((Display* d, Drawable dr, GC g, XPoint* x, int i1, int i2)); /* 23 */ + void (*xDrawRectangle) _ANSI_ARGS_((Display* d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2)); /* 24 */ + void (*xFillArc) _ANSI_ARGS_((Display* d, Drawable dr, GC g, int i1, int i2, unsigned int ui1, unsigned int ui2, int i3, int i4)); /* 25 */ + void (*xFillPolygon) _ANSI_ARGS_((Display* d, Drawable dr, GC g, XPoint* x, int i1, int i2, int i3)); /* 26 */ + void (*xFillRectangles) _ANSI_ARGS_((Display* d, Drawable dr, GC g, XRectangle* x, int i)); /* 27 */ + void (*xFreeColormap) _ANSI_ARGS_((Display* d, Colormap c)); /* 28 */ + void (*xFreeColors) _ANSI_ARGS_((Display* d, Colormap c, unsigned long* ulp, int i, unsigned long ul)); /* 29 */ + void (*xFreeModifiermap) _ANSI_ARGS_((XModifierKeymap* x)); /* 30 */ + Status (*xGetGeometry) _ANSI_ARGS_((Display* d, Drawable dr, Window* w, int* i1, int* i2, unsigned int* ui1, unsigned int* ui2, unsigned int* ui3, unsigned int* ui4)); /* 31 */ + int (*xGetWindowProperty) _ANSI_ARGS_((Display* d, Window w, Atom a1, long l1, long l2, Bool b, Atom a2, Atom* ap, int* ip, unsigned long* ulp1, unsigned long* ulp2, unsigned char** cpp)); /* 32 */ + int (*xGrabKeyboard) _ANSI_ARGS_((Display* d, Window w, Bool b, int i1, int i2, Time t)); /* 33 */ + int (*xGrabPointer) _ANSI_ARGS_((Display* d, Window w1, Bool b, unsigned int ui, int i1, int i2, Window w2, Cursor c, Time t)); /* 34 */ + KeyCode (*xKeysymToKeycode) _ANSI_ARGS_((Display* d, KeySym k)); /* 35 */ + void (*xMapWindow) _ANSI_ARGS_((Display* d, Window w)); /* 36 */ + void (*xMoveResizeWindow) _ANSI_ARGS_((Display* d, Window w, int i1, int i2, unsigned int ui1, unsigned int ui2)); /* 37 */ + void (*xMoveWindow) _ANSI_ARGS_((Display* d, Window w, int i1, int i2)); /* 38 */ + Bool (*xQueryPointer) _ANSI_ARGS_((Display* d, Window w1, Window* w2, Window* w3, int* i1, int* i2, int* i3, int* i4, unsigned int* ui)); /* 39 */ + void (*xRaiseWindow) _ANSI_ARGS_((Display* d, Window w)); /* 40 */ + void (*xRefreshKeyboardMapping) _ANSI_ARGS_((XMappingEvent* x)); /* 41 */ + void (*xResizeWindow) _ANSI_ARGS_((Display* d, Window w, unsigned int ui1, unsigned int ui2)); /* 42 */ + void (*xSelectInput) _ANSI_ARGS_((Display* d, Window w, long l)); /* 43 */ + Status (*xSendEvent) _ANSI_ARGS_((Display* d, Window w, Bool b, long l, XEvent* x)); /* 44 */ + void (*xSetIconName) _ANSI_ARGS_((Display* d, Window w, _Xconst char* c)); /* 45 */ + void (*xSetInputFocus) _ANSI_ARGS_((Display* d, Window w, int i, Time t)); /* 46 */ + void (*xSetSelectionOwner) _ANSI_ARGS_((Display* d, Atom a, Window w, Time t)); /* 47 */ + void (*xSetWindowBackground) _ANSI_ARGS_((Display* d, Window w, unsigned long ul)); /* 48 */ + void (*xSetWindowBackgroundPixmap) _ANSI_ARGS_((Display* d, Window w, Pixmap p)); /* 49 */ + void (*xSetWindowBorder) _ANSI_ARGS_((Display* d, Window w, unsigned long ul)); /* 50 */ + void (*xSetWindowBorderPixmap) _ANSI_ARGS_((Display* d, Window w, Pixmap p)); /* 51 */ + void (*xSetWindowBorderWidth) _ANSI_ARGS_((Display* d, Window w, unsigned int ui)); /* 52 */ + void (*xSetWindowColormap) _ANSI_ARGS_((Display* d, Window w, Colormap c)); /* 53 */ + void (*xUngrabKeyboard) _ANSI_ARGS_((Display* d, Time t)); /* 54 */ + void (*xUngrabPointer) _ANSI_ARGS_((Display* d, Time t)); /* 55 */ + void (*xUnmapWindow) _ANSI_ARGS_((Display* d, Window w)); /* 56 */ + void (*tkPutImage) _ANSI_ARGS_((unsigned long * colors, int ncolors, Display* display, Drawable d, GC gc, XImage* image, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height)); /* 57 */ + Status (*xParseColor) _ANSI_ARGS_((Display * display, Colormap map, _Xconst char* spec, XColor * colorPtr)); /* 58 */ + GC (*xCreateGC) _ANSI_ARGS_((Display* display, Drawable d, unsigned long valuemask, XGCValues* values)); /* 59 */ + void (*xFreeGC) _ANSI_ARGS_((Display* display, GC gc)); /* 60 */ + Atom (*xInternAtom) _ANSI_ARGS_((Display* display, _Xconst char* atom_name, Bool only_if_exists)); /* 61 */ + void (*xSetBackground) _ANSI_ARGS_((Display* display, GC gc, unsigned long foreground)); /* 62 */ + void (*xSetForeground) _ANSI_ARGS_((Display* display, GC gc, unsigned long foreground)); /* 63 */ + void (*xSetClipMask) _ANSI_ARGS_((Display* display, GC gc, Pixmap pixmap)); /* 64 */ + void (*xSetClipOrigin) _ANSI_ARGS_((Display* display, GC gc, int clip_x_origin, int clip_y_origin)); /* 65 */ + void (*xSetTSOrigin) _ANSI_ARGS_((Display* display, GC gc, int ts_x_origin, int ts_y_origin)); /* 66 */ + void (*xChangeGC) _ANSI_ARGS_((Display * d, GC gc, unsigned long mask, XGCValues * values)); /* 67 */ + void (*xSetFont) _ANSI_ARGS_((Display * display, GC gc, Font font)); /* 68 */ + void (*xSetArcMode) _ANSI_ARGS_((Display * display, GC gc, int arc_mode)); /* 69 */ + void (*xSetStipple) _ANSI_ARGS_((Display * display, GC gc, Pixmap stipple)); /* 70 */ + void (*xSetFillRule) _ANSI_ARGS_((Display * display, GC gc, int fill_rule)); /* 71 */ + void (*xSetFillStyle) _ANSI_ARGS_((Display * display, GC gc, int fill_style)); /* 72 */ + void (*xSetFunction) _ANSI_ARGS_((Display * display, GC gc, int function)); /* 73 */ + void (*xSetLineAttributes) _ANSI_ARGS_((Display * display, GC gc, unsigned int line_width, int line_style, int cap_style, int join_style)); /* 74 */ + int (*_XInitImageFuncPtrs) _ANSI_ARGS_((XImage * image)); /* 75 */ + XIC (*xCreateIC) _ANSI_ARGS_((void)); /* 76 */ + XVisualInfo * (*xGetVisualInfo) _ANSI_ARGS_((Display* display, long vinfo_mask, XVisualInfo* vinfo_template, int* nitems_return)); /* 77 */ + void (*xSetWMClientMachine) _ANSI_ARGS_((Display* display, Window w, XTextProperty* text_prop)); /* 78 */ + Status (*xStringListToTextProperty) _ANSI_ARGS_((char** list, int count, XTextProperty* text_prop_return)); /* 79 */ + void (*xDrawSegments) _ANSI_ARGS_((Display * display, Drawable d, GC gc, XSegment * segments, int nsegments)); /* 80 */ + void (*xForceScreenSaver) _ANSI_ARGS_((Display* display, int mode)); /* 81 */ + void (*xDrawLine) _ANSI_ARGS_((Display* d, Drawable dr, GC g, int x1, int y1, int x2, int y2)); /* 82 */ + void (*xFillRectangle) _ANSI_ARGS_((Display* display, Drawable d, GC gc, int x, int y, unsigned int width, unsigned int height)); /* 83 */ + void (*xClearWindow) _ANSI_ARGS_((Display* d, Window w)); /* 84 */ + void (*xDrawPoint) _ANSI_ARGS_((Display* display, Drawable d, GC gc, int x, int y)); /* 85 */ + void (*xDrawPoints) _ANSI_ARGS_((Display* display, Drawable d, GC gc, XPoint * points, int npoints, int mode)); /* 86 */ + void (*xWarpPointer) _ANSI_ARGS_((Display* display, Window src_w, Window dest_w, int src_x, int src_y, unsigned int src_width, unsigned int src_height, int dest_x, int dest_y)); /* 87 */ + void (*xQueryColor) _ANSI_ARGS_((Display * display, Colormap colormap, XColor * def_in_out)); /* 88 */ + void (*xQueryColors) _ANSI_ARGS_((Display * display, Colormap colormap, XColor * defs_in_out, int ncolors)); /* 89 */ +#endif /* MAC_TCL */ +} TkIntXlibStubs; + +#ifdef __cplusplus +extern "C" { +#endif +extern TkIntXlibStubs *tkIntXlibStubsPtr; +#ifdef __cplusplus +} +#endif + +#if defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) + +/* + * Inline function declarations: + */ + +#ifdef __WIN32__ +#ifndef XSetDashes +#define XSetDashes \ + (tkIntXlibStubsPtr->xSetDashes) /* 0 */ +#endif +#ifndef XGetModifierMapping +#define XGetModifierMapping \ + (tkIntXlibStubsPtr->xGetModifierMapping) /* 1 */ +#endif +#ifndef XCreateImage +#define XCreateImage \ + (tkIntXlibStubsPtr->xCreateImage) /* 2 */ +#endif +#ifndef XGetImage +#define XGetImage \ + (tkIntXlibStubsPtr->xGetImage) /* 3 */ +#endif +#ifndef XGetAtomName +#define XGetAtomName \ + (tkIntXlibStubsPtr->xGetAtomName) /* 4 */ +#endif +#ifndef XKeysymToString +#define XKeysymToString \ + (tkIntXlibStubsPtr->xKeysymToString) /* 5 */ +#endif +#ifndef XCreateColormap +#define XCreateColormap \ + (tkIntXlibStubsPtr->xCreateColormap) /* 6 */ +#endif +#ifndef XCreatePixmapCursor +#define XCreatePixmapCursor \ + (tkIntXlibStubsPtr->xCreatePixmapCursor) /* 7 */ +#endif +#ifndef XCreateGlyphCursor +#define XCreateGlyphCursor \ + (tkIntXlibStubsPtr->xCreateGlyphCursor) /* 8 */ +#endif +#ifndef XGContextFromGC +#define XGContextFromGC \ + (tkIntXlibStubsPtr->xGContextFromGC) /* 9 */ +#endif +#ifndef XListHosts +#define XListHosts \ + (tkIntXlibStubsPtr->xListHosts) /* 10 */ +#endif +#ifndef XKeycodeToKeysym +#define XKeycodeToKeysym \ + (tkIntXlibStubsPtr->xKeycodeToKeysym) /* 11 */ +#endif +#ifndef XStringToKeysym +#define XStringToKeysym \ + (tkIntXlibStubsPtr->xStringToKeysym) /* 12 */ +#endif +#ifndef XRootWindow +#define XRootWindow \ + (tkIntXlibStubsPtr->xRootWindow) /* 13 */ +#endif +#ifndef XSetErrorHandler +#define XSetErrorHandler \ + (tkIntXlibStubsPtr->xSetErrorHandler) /* 14 */ +#endif +#ifndef XIconifyWindow +#define XIconifyWindow \ + (tkIntXlibStubsPtr->xIconifyWindow) /* 15 */ +#endif +#ifndef XWithdrawWindow +#define XWithdrawWindow \ + (tkIntXlibStubsPtr->xWithdrawWindow) /* 16 */ +#endif +#ifndef XGetWMColormapWindows +#define XGetWMColormapWindows \ + (tkIntXlibStubsPtr->xGetWMColormapWindows) /* 17 */ +#endif +#ifndef XAllocColor +#define XAllocColor \ + (tkIntXlibStubsPtr->xAllocColor) /* 18 */ +#endif +#ifndef XBell +#define XBell \ + (tkIntXlibStubsPtr->xBell) /* 19 */ +#endif +#ifndef XChangeProperty +#define XChangeProperty \ + (tkIntXlibStubsPtr->xChangeProperty) /* 20 */ +#endif +#ifndef XChangeWindowAttributes +#define XChangeWindowAttributes \ + (tkIntXlibStubsPtr->xChangeWindowAttributes) /* 21 */ +#endif +#ifndef XClearWindow +#define XClearWindow \ + (tkIntXlibStubsPtr->xClearWindow) /* 22 */ +#endif +#ifndef XConfigureWindow +#define XConfigureWindow \ + (tkIntXlibStubsPtr->xConfigureWindow) /* 23 */ +#endif +#ifndef XCopyArea +#define XCopyArea \ + (tkIntXlibStubsPtr->xCopyArea) /* 24 */ +#endif +#ifndef XCopyPlane +#define XCopyPlane \ + (tkIntXlibStubsPtr->xCopyPlane) /* 25 */ +#endif +#ifndef XCreateBitmapFromData +#define XCreateBitmapFromData \ + (tkIntXlibStubsPtr->xCreateBitmapFromData) /* 26 */ +#endif +#ifndef XDefineCursor +#define XDefineCursor \ + (tkIntXlibStubsPtr->xDefineCursor) /* 27 */ +#endif +#ifndef XDeleteProperty +#define XDeleteProperty \ + (tkIntXlibStubsPtr->xDeleteProperty) /* 28 */ +#endif +#ifndef XDestroyWindow +#define XDestroyWindow \ + (tkIntXlibStubsPtr->xDestroyWindow) /* 29 */ +#endif +#ifndef XDrawArc +#define XDrawArc \ + (tkIntXlibStubsPtr->xDrawArc) /* 30 */ +#endif +#ifndef XDrawLines +#define XDrawLines \ + (tkIntXlibStubsPtr->xDrawLines) /* 31 */ +#endif +#ifndef XDrawRectangle +#define XDrawRectangle \ + (tkIntXlibStubsPtr->xDrawRectangle) /* 32 */ +#endif +#ifndef XFillArc +#define XFillArc \ + (tkIntXlibStubsPtr->xFillArc) /* 33 */ +#endif +#ifndef XFillPolygon +#define XFillPolygon \ + (tkIntXlibStubsPtr->xFillPolygon) /* 34 */ +#endif +#ifndef XFillRectangles +#define XFillRectangles \ + (tkIntXlibStubsPtr->xFillRectangles) /* 35 */ +#endif +#ifndef XForceScreenSaver +#define XForceScreenSaver \ + (tkIntXlibStubsPtr->xForceScreenSaver) /* 36 */ +#endif +#ifndef XFreeColormap +#define XFreeColormap \ + (tkIntXlibStubsPtr->xFreeColormap) /* 37 */ +#endif +#ifndef XFreeColors +#define XFreeColors \ + (tkIntXlibStubsPtr->xFreeColors) /* 38 */ +#endif +#ifndef XFreeCursor +#define XFreeCursor \ + (tkIntXlibStubsPtr->xFreeCursor) /* 39 */ +#endif +#ifndef XFreeModifiermap +#define XFreeModifiermap \ + (tkIntXlibStubsPtr->xFreeModifiermap) /* 40 */ +#endif +#ifndef XGetGeometry +#define XGetGeometry \ + (tkIntXlibStubsPtr->xGetGeometry) /* 41 */ +#endif +#ifndef XGetInputFocus +#define XGetInputFocus \ + (tkIntXlibStubsPtr->xGetInputFocus) /* 42 */ +#endif +#ifndef XGetWindowProperty +#define XGetWindowProperty \ + (tkIntXlibStubsPtr->xGetWindowProperty) /* 43 */ +#endif +#ifndef XGetWindowAttributes +#define XGetWindowAttributes \ + (tkIntXlibStubsPtr->xGetWindowAttributes) /* 44 */ +#endif +#ifndef XGrabKeyboard +#define XGrabKeyboard \ + (tkIntXlibStubsPtr->xGrabKeyboard) /* 45 */ +#endif +#ifndef XGrabPointer +#define XGrabPointer \ + (tkIntXlibStubsPtr->xGrabPointer) /* 46 */ +#endif +#ifndef XKeysymToKeycode +#define XKeysymToKeycode \ + (tkIntXlibStubsPtr->xKeysymToKeycode) /* 47 */ +#endif +#ifndef XLookupColor +#define XLookupColor \ + (tkIntXlibStubsPtr->xLookupColor) /* 48 */ +#endif +#ifndef XMapWindow +#define XMapWindow \ + (tkIntXlibStubsPtr->xMapWindow) /* 49 */ +#endif +#ifndef XMoveResizeWindow +#define XMoveResizeWindow \ + (tkIntXlibStubsPtr->xMoveResizeWindow) /* 50 */ +#endif +#ifndef XMoveWindow +#define XMoveWindow \ + (tkIntXlibStubsPtr->xMoveWindow) /* 51 */ +#endif +#ifndef XNextEvent +#define XNextEvent \ + (tkIntXlibStubsPtr->xNextEvent) /* 52 */ +#endif +#ifndef XPutBackEvent +#define XPutBackEvent \ + (tkIntXlibStubsPtr->xPutBackEvent) /* 53 */ +#endif +#ifndef XQueryColors +#define XQueryColors \ + (tkIntXlibStubsPtr->xQueryColors) /* 54 */ +#endif +#ifndef XQueryPointer +#define XQueryPointer \ + (tkIntXlibStubsPtr->xQueryPointer) /* 55 */ +#endif +#ifndef XQueryTree +#define XQueryTree \ + (tkIntXlibStubsPtr->xQueryTree) /* 56 */ +#endif +#ifndef XRaiseWindow +#define XRaiseWindow \ + (tkIntXlibStubsPtr->xRaiseWindow) /* 57 */ +#endif +#ifndef XRefreshKeyboardMapping +#define XRefreshKeyboardMapping \ + (tkIntXlibStubsPtr->xRefreshKeyboardMapping) /* 58 */ +#endif +#ifndef XResizeWindow +#define XResizeWindow \ + (tkIntXlibStubsPtr->xResizeWindow) /* 59 */ +#endif +#ifndef XSelectInput +#define XSelectInput \ + (tkIntXlibStubsPtr->xSelectInput) /* 60 */ +#endif +#ifndef XSendEvent +#define XSendEvent \ + (tkIntXlibStubsPtr->xSendEvent) /* 61 */ +#endif +#ifndef XSetCommand +#define XSetCommand \ + (tkIntXlibStubsPtr->xSetCommand) /* 62 */ +#endif +#ifndef XSetIconName +#define XSetIconName \ + (tkIntXlibStubsPtr->xSetIconName) /* 63 */ +#endif +#ifndef XSetInputFocus +#define XSetInputFocus \ + (tkIntXlibStubsPtr->xSetInputFocus) /* 64 */ +#endif +#ifndef XSetSelectionOwner +#define XSetSelectionOwner \ + (tkIntXlibStubsPtr->xSetSelectionOwner) /* 65 */ +#endif +#ifndef XSetWindowBackground +#define XSetWindowBackground \ + (tkIntXlibStubsPtr->xSetWindowBackground) /* 66 */ +#endif +#ifndef XSetWindowBackgroundPixmap +#define XSetWindowBackgroundPixmap \ + (tkIntXlibStubsPtr->xSetWindowBackgroundPixmap) /* 67 */ +#endif +#ifndef XSetWindowBorder +#define XSetWindowBorder \ + (tkIntXlibStubsPtr->xSetWindowBorder) /* 68 */ +#endif +#ifndef XSetWindowBorderPixmap +#define XSetWindowBorderPixmap \ + (tkIntXlibStubsPtr->xSetWindowBorderPixmap) /* 69 */ +#endif +#ifndef XSetWindowBorderWidth +#define XSetWindowBorderWidth \ + (tkIntXlibStubsPtr->xSetWindowBorderWidth) /* 70 */ +#endif +#ifndef XSetWindowColormap +#define XSetWindowColormap \ + (tkIntXlibStubsPtr->xSetWindowColormap) /* 71 */ +#endif +#ifndef XTranslateCoordinates +#define XTranslateCoordinates \ + (tkIntXlibStubsPtr->xTranslateCoordinates) /* 72 */ +#endif +#ifndef XUngrabKeyboard +#define XUngrabKeyboard \ + (tkIntXlibStubsPtr->xUngrabKeyboard) /* 73 */ +#endif +#ifndef XUngrabPointer +#define XUngrabPointer \ + (tkIntXlibStubsPtr->xUngrabPointer) /* 74 */ +#endif +#ifndef XUnmapWindow +#define XUnmapWindow \ + (tkIntXlibStubsPtr->xUnmapWindow) /* 75 */ +#endif +#ifndef XWindowEvent +#define XWindowEvent \ + (tkIntXlibStubsPtr->xWindowEvent) /* 76 */ +#endif +#ifndef XDestroyIC +#define XDestroyIC \ + (tkIntXlibStubsPtr->xDestroyIC) /* 77 */ +#endif +#ifndef XFilterEvent +#define XFilterEvent \ + (tkIntXlibStubsPtr->xFilterEvent) /* 78 */ +#endif +#ifndef XmbLookupString +#define XmbLookupString \ + (tkIntXlibStubsPtr->xmbLookupString) /* 79 */ +#endif +#ifndef TkPutImage +#define TkPutImage \ + (tkIntXlibStubsPtr->tkPutImage) /* 80 */ +#endif +/* Slot 81 is reserved */ +#ifndef XParseColor +#define XParseColor \ + (tkIntXlibStubsPtr->xParseColor) /* 82 */ +#endif +#ifndef XCreateGC +#define XCreateGC \ + (tkIntXlibStubsPtr->xCreateGC) /* 83 */ +#endif +#ifndef XFreeGC +#define XFreeGC \ + (tkIntXlibStubsPtr->xFreeGC) /* 84 */ +#endif +#ifndef XInternAtom +#define XInternAtom \ + (tkIntXlibStubsPtr->xInternAtom) /* 85 */ +#endif +#ifndef XSetBackground +#define XSetBackground \ + (tkIntXlibStubsPtr->xSetBackground) /* 86 */ +#endif +#ifndef XSetForeground +#define XSetForeground \ + (tkIntXlibStubsPtr->xSetForeground) /* 87 */ +#endif +#ifndef XSetClipMask +#define XSetClipMask \ + (tkIntXlibStubsPtr->xSetClipMask) /* 88 */ +#endif +#ifndef XSetClipOrigin +#define XSetClipOrigin \ + (tkIntXlibStubsPtr->xSetClipOrigin) /* 89 */ +#endif +#ifndef XSetTSOrigin +#define XSetTSOrigin \ + (tkIntXlibStubsPtr->xSetTSOrigin) /* 90 */ +#endif +#ifndef XChangeGC +#define XChangeGC \ + (tkIntXlibStubsPtr->xChangeGC) /* 91 */ +#endif +#ifndef XSetFont +#define XSetFont \ + (tkIntXlibStubsPtr->xSetFont) /* 92 */ +#endif +#ifndef XSetArcMode +#define XSetArcMode \ + (tkIntXlibStubsPtr->xSetArcMode) /* 93 */ +#endif +#ifndef XSetStipple +#define XSetStipple \ + (tkIntXlibStubsPtr->xSetStipple) /* 94 */ +#endif +#ifndef XSetFillRule +#define XSetFillRule \ + (tkIntXlibStubsPtr->xSetFillRule) /* 95 */ +#endif +#ifndef XSetFillStyle +#define XSetFillStyle \ + (tkIntXlibStubsPtr->xSetFillStyle) /* 96 */ +#endif +#ifndef XSetFunction +#define XSetFunction \ + (tkIntXlibStubsPtr->xSetFunction) /* 97 */ +#endif +#ifndef XSetLineAttributes +#define XSetLineAttributes \ + (tkIntXlibStubsPtr->xSetLineAttributes) /* 98 */ +#endif +#ifndef _XInitImageFuncPtrs +#define _XInitImageFuncPtrs \ + (tkIntXlibStubsPtr->_XInitImageFuncPtrs) /* 99 */ +#endif +#ifndef XCreateIC +#define XCreateIC \ + (tkIntXlibStubsPtr->xCreateIC) /* 100 */ +#endif +#ifndef XGetVisualInfo +#define XGetVisualInfo \ + (tkIntXlibStubsPtr->xGetVisualInfo) /* 101 */ +#endif +#ifndef XSetWMClientMachine +#define XSetWMClientMachine \ + (tkIntXlibStubsPtr->xSetWMClientMachine) /* 102 */ +#endif +#ifndef XStringListToTextProperty +#define XStringListToTextProperty \ + (tkIntXlibStubsPtr->xStringListToTextProperty) /* 103 */ +#endif +#ifndef XDrawLine +#define XDrawLine \ + (tkIntXlibStubsPtr->xDrawLine) /* 104 */ +#endif +#ifndef XWarpPointer +#define XWarpPointer \ + (tkIntXlibStubsPtr->xWarpPointer) /* 105 */ +#endif +#ifndef XFillRectangle +#define XFillRectangle \ + (tkIntXlibStubsPtr->xFillRectangle) /* 106 */ +#endif +#endif /* __WIN32__ */ +#ifdef MAC_TCL +#ifndef XSetDashes +#define XSetDashes \ + (tkIntXlibStubsPtr->xSetDashes) /* 0 */ +#endif +#ifndef XGetModifierMapping +#define XGetModifierMapping \ + (tkIntXlibStubsPtr->xGetModifierMapping) /* 1 */ +#endif +#ifndef XCreateImage +#define XCreateImage \ + (tkIntXlibStubsPtr->xCreateImage) /* 2 */ +#endif +#ifndef XGetImage +#define XGetImage \ + (tkIntXlibStubsPtr->xGetImage) /* 3 */ +#endif +#ifndef XGetAtomName +#define XGetAtomName \ + (tkIntXlibStubsPtr->xGetAtomName) /* 4 */ +#endif +#ifndef XKeysymToString +#define XKeysymToString \ + (tkIntXlibStubsPtr->xKeysymToString) /* 5 */ +#endif +#ifndef XCreateColormap +#define XCreateColormap \ + (tkIntXlibStubsPtr->xCreateColormap) /* 6 */ +#endif +#ifndef XGContextFromGC +#define XGContextFromGC \ + (tkIntXlibStubsPtr->xGContextFromGC) /* 7 */ +#endif +#ifndef XKeycodeToKeysym +#define XKeycodeToKeysym \ + (tkIntXlibStubsPtr->xKeycodeToKeysym) /* 8 */ +#endif +#ifndef XStringToKeysym +#define XStringToKeysym \ + (tkIntXlibStubsPtr->xStringToKeysym) /* 9 */ +#endif +#ifndef XRootWindow +#define XRootWindow \ + (tkIntXlibStubsPtr->xRootWindow) /* 10 */ +#endif +#ifndef XSetErrorHandler +#define XSetErrorHandler \ + (tkIntXlibStubsPtr->xSetErrorHandler) /* 11 */ +#endif +#ifndef XAllocColor +#define XAllocColor \ + (tkIntXlibStubsPtr->xAllocColor) /* 12 */ +#endif +#ifndef XBell +#define XBell \ + (tkIntXlibStubsPtr->xBell) /* 13 */ +#endif +#ifndef XChangeProperty +#define XChangeProperty \ + (tkIntXlibStubsPtr->xChangeProperty) /* 14 */ +#endif +#ifndef XChangeWindowAttributes +#define XChangeWindowAttributes \ + (tkIntXlibStubsPtr->xChangeWindowAttributes) /* 15 */ +#endif +#ifndef XConfigureWindow +#define XConfigureWindow \ + (tkIntXlibStubsPtr->xConfigureWindow) /* 16 */ +#endif +#ifndef XCopyArea +#define XCopyArea \ + (tkIntXlibStubsPtr->xCopyArea) /* 17 */ +#endif +#ifndef XCopyPlane +#define XCopyPlane \ + (tkIntXlibStubsPtr->xCopyPlane) /* 18 */ +#endif +#ifndef XCreateBitmapFromData +#define XCreateBitmapFromData \ + (tkIntXlibStubsPtr->xCreateBitmapFromData) /* 19 */ +#endif +#ifndef XDefineCursor +#define XDefineCursor \ + (tkIntXlibStubsPtr->xDefineCursor) /* 20 */ +#endif +#ifndef XDestroyWindow +#define XDestroyWindow \ + (tkIntXlibStubsPtr->xDestroyWindow) /* 21 */ +#endif +#ifndef XDrawArc +#define XDrawArc \ + (tkIntXlibStubsPtr->xDrawArc) /* 22 */ +#endif +#ifndef XDrawLines +#define XDrawLines \ + (tkIntXlibStubsPtr->xDrawLines) /* 23 */ +#endif +#ifndef XDrawRectangle +#define XDrawRectangle \ + (tkIntXlibStubsPtr->xDrawRectangle) /* 24 */ +#endif +#ifndef XFillArc +#define XFillArc \ + (tkIntXlibStubsPtr->xFillArc) /* 25 */ +#endif +#ifndef XFillPolygon +#define XFillPolygon \ + (tkIntXlibStubsPtr->xFillPolygon) /* 26 */ +#endif +#ifndef XFillRectangles +#define XFillRectangles \ + (tkIntXlibStubsPtr->xFillRectangles) /* 27 */ +#endif +#ifndef XFreeColormap +#define XFreeColormap \ + (tkIntXlibStubsPtr->xFreeColormap) /* 28 */ +#endif +#ifndef XFreeColors +#define XFreeColors \ + (tkIntXlibStubsPtr->xFreeColors) /* 29 */ +#endif +#ifndef XFreeModifiermap +#define XFreeModifiermap \ + (tkIntXlibStubsPtr->xFreeModifiermap) /* 30 */ +#endif +#ifndef XGetGeometry +#define XGetGeometry \ + (tkIntXlibStubsPtr->xGetGeometry) /* 31 */ +#endif +#ifndef XGetWindowProperty +#define XGetWindowProperty \ + (tkIntXlibStubsPtr->xGetWindowProperty) /* 32 */ +#endif +#ifndef XGrabKeyboard +#define XGrabKeyboard \ + (tkIntXlibStubsPtr->xGrabKeyboard) /* 33 */ +#endif +#ifndef XGrabPointer +#define XGrabPointer \ + (tkIntXlibStubsPtr->xGrabPointer) /* 34 */ +#endif +#ifndef XKeysymToKeycode +#define XKeysymToKeycode \ + (tkIntXlibStubsPtr->xKeysymToKeycode) /* 35 */ +#endif +#ifndef XMapWindow +#define XMapWindow \ + (tkIntXlibStubsPtr->xMapWindow) /* 36 */ +#endif +#ifndef XMoveResizeWindow +#define XMoveResizeWindow \ + (tkIntXlibStubsPtr->xMoveResizeWindow) /* 37 */ +#endif +#ifndef XMoveWindow +#define XMoveWindow \ + (tkIntXlibStubsPtr->xMoveWindow) /* 38 */ +#endif +#ifndef XQueryPointer +#define XQueryPointer \ + (tkIntXlibStubsPtr->xQueryPointer) /* 39 */ +#endif +#ifndef XRaiseWindow +#define XRaiseWindow \ + (tkIntXlibStubsPtr->xRaiseWindow) /* 40 */ +#endif +#ifndef XRefreshKeyboardMapping +#define XRefreshKeyboardMapping \ + (tkIntXlibStubsPtr->xRefreshKeyboardMapping) /* 41 */ +#endif +#ifndef XResizeWindow +#define XResizeWindow \ + (tkIntXlibStubsPtr->xResizeWindow) /* 42 */ +#endif +#ifndef XSelectInput +#define XSelectInput \ + (tkIntXlibStubsPtr->xSelectInput) /* 43 */ +#endif +#ifndef XSendEvent +#define XSendEvent \ + (tkIntXlibStubsPtr->xSendEvent) /* 44 */ +#endif +#ifndef XSetIconName +#define XSetIconName \ + (tkIntXlibStubsPtr->xSetIconName) /* 45 */ +#endif +#ifndef XSetInputFocus +#define XSetInputFocus \ + (tkIntXlibStubsPtr->xSetInputFocus) /* 46 */ +#endif +#ifndef XSetSelectionOwner +#define XSetSelectionOwner \ + (tkIntXlibStubsPtr->xSetSelectionOwner) /* 47 */ +#endif +#ifndef XSetWindowBackground +#define XSetWindowBackground \ + (tkIntXlibStubsPtr->xSetWindowBackground) /* 48 */ +#endif +#ifndef XSetWindowBackgroundPixmap +#define XSetWindowBackgroundPixmap \ + (tkIntXlibStubsPtr->xSetWindowBackgroundPixmap) /* 49 */ +#endif +#ifndef XSetWindowBorder +#define XSetWindowBorder \ + (tkIntXlibStubsPtr->xSetWindowBorder) /* 50 */ +#endif +#ifndef XSetWindowBorderPixmap +#define XSetWindowBorderPixmap \ + (tkIntXlibStubsPtr->xSetWindowBorderPixmap) /* 51 */ +#endif +#ifndef XSetWindowBorderWidth +#define XSetWindowBorderWidth \ + (tkIntXlibStubsPtr->xSetWindowBorderWidth) /* 52 */ +#endif +#ifndef XSetWindowColormap +#define XSetWindowColormap \ + (tkIntXlibStubsPtr->xSetWindowColormap) /* 53 */ +#endif +#ifndef XUngrabKeyboard +#define XUngrabKeyboard \ + (tkIntXlibStubsPtr->xUngrabKeyboard) /* 54 */ +#endif +#ifndef XUngrabPointer +#define XUngrabPointer \ + (tkIntXlibStubsPtr->xUngrabPointer) /* 55 */ +#endif +#ifndef XUnmapWindow +#define XUnmapWindow \ + (tkIntXlibStubsPtr->xUnmapWindow) /* 56 */ +#endif +#ifndef TkPutImage +#define TkPutImage \ + (tkIntXlibStubsPtr->tkPutImage) /* 57 */ +#endif +#ifndef XParseColor +#define XParseColor \ + (tkIntXlibStubsPtr->xParseColor) /* 58 */ +#endif +#ifndef XCreateGC +#define XCreateGC \ + (tkIntXlibStubsPtr->xCreateGC) /* 59 */ +#endif +#ifndef XFreeGC +#define XFreeGC \ + (tkIntXlibStubsPtr->xFreeGC) /* 60 */ +#endif +#ifndef XInternAtom +#define XInternAtom \ + (tkIntXlibStubsPtr->xInternAtom) /* 61 */ +#endif +#ifndef XSetBackground +#define XSetBackground \ + (tkIntXlibStubsPtr->xSetBackground) /* 62 */ +#endif +#ifndef XSetForeground +#define XSetForeground \ + (tkIntXlibStubsPtr->xSetForeground) /* 63 */ +#endif +#ifndef XSetClipMask +#define XSetClipMask \ + (tkIntXlibStubsPtr->xSetClipMask) /* 64 */ +#endif +#ifndef XSetClipOrigin +#define XSetClipOrigin \ + (tkIntXlibStubsPtr->xSetClipOrigin) /* 65 */ +#endif +#ifndef XSetTSOrigin +#define XSetTSOrigin \ + (tkIntXlibStubsPtr->xSetTSOrigin) /* 66 */ +#endif +#ifndef XChangeGC +#define XChangeGC \ + (tkIntXlibStubsPtr->xChangeGC) /* 67 */ +#endif +#ifndef XSetFont +#define XSetFont \ + (tkIntXlibStubsPtr->xSetFont) /* 68 */ +#endif +#ifndef XSetArcMode +#define XSetArcMode \ + (tkIntXlibStubsPtr->xSetArcMode) /* 69 */ +#endif +#ifndef XSetStipple +#define XSetStipple \ + (tkIntXlibStubsPtr->xSetStipple) /* 70 */ +#endif +#ifndef XSetFillRule +#define XSetFillRule \ + (tkIntXlibStubsPtr->xSetFillRule) /* 71 */ +#endif +#ifndef XSetFillStyle +#define XSetFillStyle \ + (tkIntXlibStubsPtr->xSetFillStyle) /* 72 */ +#endif +#ifndef XSetFunction +#define XSetFunction \ + (tkIntXlibStubsPtr->xSetFunction) /* 73 */ +#endif +#ifndef XSetLineAttributes +#define XSetLineAttributes \ + (tkIntXlibStubsPtr->xSetLineAttributes) /* 74 */ +#endif +#ifndef _XInitImageFuncPtrs +#define _XInitImageFuncPtrs \ + (tkIntXlibStubsPtr->_XInitImageFuncPtrs) /* 75 */ +#endif +#ifndef XCreateIC +#define XCreateIC \ + (tkIntXlibStubsPtr->xCreateIC) /* 76 */ +#endif +#ifndef XGetVisualInfo +#define XGetVisualInfo \ + (tkIntXlibStubsPtr->xGetVisualInfo) /* 77 */ +#endif +#ifndef XSetWMClientMachine +#define XSetWMClientMachine \ + (tkIntXlibStubsPtr->xSetWMClientMachine) /* 78 */ +#endif +#ifndef XStringListToTextProperty +#define XStringListToTextProperty \ + (tkIntXlibStubsPtr->xStringListToTextProperty) /* 79 */ +#endif +#ifndef XDrawSegments +#define XDrawSegments \ + (tkIntXlibStubsPtr->xDrawSegments) /* 80 */ +#endif +#ifndef XForceScreenSaver +#define XForceScreenSaver \ + (tkIntXlibStubsPtr->xForceScreenSaver) /* 81 */ +#endif +#ifndef XDrawLine +#define XDrawLine \ + (tkIntXlibStubsPtr->xDrawLine) /* 82 */ +#endif +#ifndef XFillRectangle +#define XFillRectangle \ + (tkIntXlibStubsPtr->xFillRectangle) /* 83 */ +#endif +#ifndef XClearWindow +#define XClearWindow \ + (tkIntXlibStubsPtr->xClearWindow) /* 84 */ +#endif +#ifndef XDrawPoint +#define XDrawPoint \ + (tkIntXlibStubsPtr->xDrawPoint) /* 85 */ +#endif +#ifndef XDrawPoints +#define XDrawPoints \ + (tkIntXlibStubsPtr->xDrawPoints) /* 86 */ +#endif +#ifndef XWarpPointer +#define XWarpPointer \ + (tkIntXlibStubsPtr->xWarpPointer) /* 87 */ +#endif +#ifndef XQueryColor +#define XQueryColor \ + (tkIntXlibStubsPtr->xQueryColor) /* 88 */ +#endif +#ifndef XQueryColors +#define XQueryColors \ + (tkIntXlibStubsPtr->xQueryColors) /* 89 */ +#endif +#endif /* MAC_TCL */ + +#endif /* defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) */ + +/* !END!: Do not edit above this line. */ + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#endif /* _TKINTXLIBDECLS */ diff --git a/tk/generic/tkListbox.c b/tk/generic/tkListbox.c index 9e32979956c..f6b0f75f6ca 100644 --- a/tk/generic/tkListbox.c +++ b/tk/generic/tkListbox.c @@ -18,30 +18,13 @@ #include "default.h" #include "tkInt.h" -/* - * One record of the following type is kept for each element - * associated with a listbox widget: - */ - -typedef struct Element { - int textLength; /* # non-NULL characters in text. */ - int lBearing; /* Distance from first character's - * origin to left edge of character. */ - int pixelWidth; /* Total width of element in pixels (including - * left bearing and right bearing). */ - int selected; /* 1 means this item is selected, 0 means - * it isn't. */ - struct Element *nextPtr; /* Next in list of all elements of this - * listbox, or NULL for last element. */ - char text[4]; /* Characters of this element, NULL- - * terminated. The actual space allocated - * here will be as large as needed (> 4, - * most likely). Must be the last field - * of the record. */ -} Element; - -#define ElementSize(stringLength) \ - ((unsigned) (sizeof(Element) - 3 + stringLength)) +typedef struct { + Tk_OptionTable listboxOptionTable; /* Table defining configuration options + * available for the listbox */ + Tk_OptionTable itemAttrOptionTable; /* Table definining configuration + * options available for listbox + * items */ +} ListboxOptionTables; /* * A data structure of the following type is kept for each listbox @@ -58,11 +41,16 @@ typedef struct { * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with listbox. */ Tcl_Command widgetCmd; /* Token for listbox's widget command. */ - int numElements; /* Total number of elements in this listbox. */ - Element *firstPtr; /* First in list of elements (NULL if no - * elements). */ - Element *lastPtr; /* Last in list of elements (NULL if no - * elements). */ + Tk_OptionTable optionTable; /* Table that defines configuration options + * available for this widget. */ + Tk_OptionTable itemAttrOptionTable; /* Table that defines configuration + * options available for listbox + * items */ + char *listVarName; /* List variable name */ + Tcl_Obj *listObj; /* Pointer to the list object being used */ + int nElements; /* Holds the current count of elements */ + Tcl_HashTable *selection; /* Tracks selection */ + Tcl_HashTable *itemAttrTable; /* Tracks item attributes */ /* * Information used when displaying widget: @@ -172,6 +160,17 @@ typedef struct { } Listbox; /* + * ItemAttr structures are used to store item configuration information for + * the items in a listbox + */ +typedef struct { + Tk_3DBorder border; /* Used for drawing background around text */ + Tk_3DBorder selBorder; /* Used for selected text */ + XColor *fgColor; /* Text color in normal mode. */ + XColor *selFgColor; /* Text color in selected mode. */ +} ItemAttr; + +/* * Flag bits for listboxes: * * REDRAW_PENDING: Non-zero means a DoWhenIdle handler @@ -183,106 +182,184 @@ typedef struct { * to be updated. * GOT_FOCUS: Non-zero means this widget currently * has the input focus. + * MAXWIDTH_IS_STALE: Stored maxWidth may be out-of-date + * LISTBOX_DELETED: This listbox has been effectively destroyed. */ #define REDRAW_PENDING 1 #define UPDATE_V_SCROLLBAR 2 #define UPDATE_H_SCROLLBAR 4 #define GOT_FOCUS 8 +#define MAXWIDTH_IS_STALE 16 +#define LISTBOX_DELETED 32 /* - * Information used for argv parsing: + * The optionSpecs table defines the valid configuration options for the + * listbox widget */ +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_BORDER, "-background", "background", "Background", + DEF_LISTBOX_BG_COLOR, -1, Tk_Offset(Listbox, normalBorder), + 0, (ClientData) DEF_LISTBOX_BG_MONO, 0}, + {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + DEF_LISTBOX_BORDER_WIDTH, -1, Tk_Offset(Listbox, borderWidth), + 0, 0, 0}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + DEF_LISTBOX_CURSOR, -1, Tk_Offset(Listbox, cursor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BOOLEAN, "-exportselection", "exportSelection", + "ExportSelection", DEF_LISTBOX_EXPORT_SELECTION, -1, + Tk_Offset(Listbox, exportSelection), 0, 0, 0}, + {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + DEF_LISTBOX_FONT, -1, Tk_Offset(Listbox, tkfont), 0, 0, 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + DEF_LISTBOX_FG, -1, Tk_Offset(Listbox, fgColorPtr), 0, 0, 0}, + {TK_OPTION_INT, "-height", "height", "Height", + DEF_LISTBOX_HEIGHT, -1, Tk_Offset(Listbox, height), 0, 0, 0}, + {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground", + "HighlightBackground", DEF_LISTBOX_HIGHLIGHT_BG, -1, + Tk_Offset(Listbox, highlightBgColorPtr), 0, 0, 0}, + {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", + DEF_LISTBOX_HIGHLIGHT, -1, Tk_Offset(Listbox, highlightColorPtr), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", + "HighlightThickness", DEF_LISTBOX_HIGHLIGHT_WIDTH, -1, + Tk_Offset(Listbox, highlightWidth), 0, 0, 0}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + DEF_LISTBOX_RELIEF, -1, Tk_Offset(Listbox, relief), 0, 0, 0}, + {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground", + DEF_LISTBOX_SELECT_COLOR, -1, Tk_Offset(Listbox, selBorder), + 0, (ClientData) DEF_LISTBOX_SELECT_MONO, 0}, + {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth", + "BorderWidth", DEF_LISTBOX_SELECT_BD, -1, + Tk_Offset(Listbox, selBorderWidth), 0, 0, 0}, + {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background", + DEF_LISTBOX_SELECT_FG_COLOR, -1, Tk_Offset(Listbox, selFgColorPtr), + 0, (ClientData) DEF_LISTBOX_SELECT_FG_MONO, 0}, + {TK_OPTION_STRING, "-selectmode", "selectMode", "SelectMode", + DEF_LISTBOX_SELECT_MODE, -1, Tk_Offset(Listbox, selectMode), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BOOLEAN, "-setgrid", "setGrid", "SetGrid", + DEF_LISTBOX_SET_GRID, -1, Tk_Offset(Listbox, setGrid), 0, 0, 0}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + DEF_LISTBOX_TAKE_FOCUS, -1, Tk_Offset(Listbox, takeFocus), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_INT, "-width", "width", "Width", + DEF_LISTBOX_WIDTH, -1, Tk_Offset(Listbox, width), 0, 0, 0}, + {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", + DEF_LISTBOX_SCROLL_COMMAND, -1, Tk_Offset(Listbox, xScrollCmd), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", + DEF_LISTBOX_SCROLL_COMMAND, -1, Tk_Offset(Listbox, yScrollCmd), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-listvariable", "listVariable", "Variable", + DEF_LISTBOX_LIST_VARIABLE, -1, Tk_Offset(Listbox, listVarName), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, 0, 0} +}; -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_LISTBOX_BG_COLOR, Tk_Offset(Listbox, normalBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_LISTBOX_BG_MONO, Tk_Offset(Listbox, normalBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_LISTBOX_BORDER_WIDTH, Tk_Offset(Listbox, borderWidth), 0}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_LISTBOX_CURSOR, Tk_Offset(Listbox, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection", - "ExportSelection", DEF_LISTBOX_EXPORT_SELECTION, - Tk_Offset(Listbox, exportSelection), 0}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_LISTBOX_FONT, Tk_Offset(Listbox, tkfont), 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_LISTBOX_FG, Tk_Offset(Listbox, fgColorPtr), 0}, - {TK_CONFIG_INT, "-height", "height", "Height", - DEF_LISTBOX_HEIGHT, Tk_Offset(Listbox, height), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_LISTBOX_HIGHLIGHT_BG, - Tk_Offset(Listbox, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_LISTBOX_HIGHLIGHT, Tk_Offset(Listbox, highlightColorPtr), 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_LISTBOX_HIGHLIGHT_WIDTH, Tk_Offset(Listbox, highlightWidth), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_LISTBOX_RELIEF, Tk_Offset(Listbox, relief), 0}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_LISTBOX_SELECT_COLOR, Tk_Offset(Listbox, selBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_LISTBOX_SELECT_MONO, Tk_Offset(Listbox, selBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth", - DEF_LISTBOX_SELECT_BD, Tk_Offset(Listbox, selBorderWidth), 0}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_LISTBOX_SELECT_FG_COLOR, Tk_Offset(Listbox, selFgColorPtr), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background", - DEF_LISTBOX_SELECT_FG_MONO, Tk_Offset(Listbox, selFgColorPtr), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_UID, "-selectmode", "selectMode", "SelectMode", - DEF_LISTBOX_SELECT_MODE, Tk_Offset(Listbox, selectMode), 0}, - {TK_CONFIG_BOOLEAN, "-setgrid", "setGrid", "SetGrid", - DEF_LISTBOX_SET_GRID, Tk_Offset(Listbox, setGrid), 0}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_LISTBOX_TAKE_FOCUS, Tk_Offset(Listbox, takeFocus), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-width", "width", "Width", - DEF_LISTBOX_WIDTH, Tk_Offset(Listbox, width), 0}, - {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", - DEF_LISTBOX_SCROLL_COMMAND, Tk_Offset(Listbox, xScrollCmd), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", - DEF_LISTBOX_SCROLL_COMMAND, Tk_Offset(Listbox, yScrollCmd), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} +/* + * The itemAttrOptionSpecs table defines the valid configuration options for + * listbox items + */ +static Tk_OptionSpec itemAttrOptionSpecs[] = { + {TK_OPTION_BORDER, "-background", "background", "Background", + (char *)NULL, -1, Tk_Offset(ItemAttr, border), + TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, + (ClientData) DEF_LISTBOX_BG_MONO, 0}, + {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, + {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + (char *) NULL, -1, Tk_Offset(ItemAttr, fgColor), + TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, 0, 0}, + {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground", + (char *) NULL, -1, Tk_Offset(ItemAttr, selBorder), + TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, + (ClientData) DEF_LISTBOX_SELECT_MONO, 0}, + {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background", + (char *) NULL, -1, Tk_Offset(ItemAttr, selFgColor), + TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, + (ClientData) DEF_LISTBOX_SELECT_FG_MONO, 0}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, 0, 0} }; /* - * Forward declarations for procedures defined later in this file: + * The following tables define the listbox widget commands (and sub- + * commands) and map the indexes into the string tables into + * enumerated types used to dispatch the listbox widget command. */ +static char *commandNames[] = { + "activate", "bbox", "cget", "configure", "curselection", "delete", "get", + "index", "insert", "itemcget", "itemconfigure", "nearest", "scan", + "see", "selection", "size", "xview", "yview", + (char *) NULL +}; +enum command { + COMMAND_ACTIVATE, COMMAND_BBOX, COMMAND_CGET, COMMAND_CONFIGURE, + COMMAND_CURSELECTION, COMMAND_DELETE, COMMAND_GET, COMMAND_INDEX, + COMMAND_INSERT, COMMAND_ITEMCGET, COMMAND_ITEMCONFIGURE, + COMMAND_NEAREST, COMMAND_SCAN, COMMAND_SEE, COMMAND_SELECTION, + COMMAND_SIZE, COMMAND_XVIEW, COMMAND_YVIEW +}; + +static char *selCommandNames[] = { + "anchor", "clear", "includes", "set", (char *) NULL +}; + +enum selcommand { + SELECTION_ANCHOR, SELECTION_CLEAR, SELECTION_INCLUDES, SELECTION_SET +}; + +static char *scanCommandNames[] = { + "mark", "dragto", (char *) NULL +}; + +enum scancommand { + SCAN_MARK, SCAN_DRAGTO +}; + +static char *indexNames[] = { + "active", "anchor", "end", (char *)NULL +}; + +enum indices { + INDEX_ACTIVE, INDEX_ANCHOR, INDEX_END +}; + + +/* Declarations for procedures defined later in this file */ static void ChangeListboxOffset _ANSI_ARGS_((Listbox *listPtr, int offset)); static void ChangeListboxView _ANSI_ARGS_((Listbox *listPtr, int index)); static int ConfigureListbox _ANSI_ARGS_((Tcl_Interp *interp, - Listbox *listPtr, int argc, char **argv, + Listbox *listPtr, int objc, Tcl_Obj *CONST objv[], int flags)); -static void DeleteEls _ANSI_ARGS_((Listbox *listPtr, int first, - int last)); +static int ConfigureListboxItem _ANSI_ARGS_ ((Tcl_Interp *interp, + Listbox *listPtr, ItemAttr *attrs, int objc, + Tcl_Obj *CONST objv[])); +static int ListboxDeleteSubCmd _ANSI_ARGS_((Listbox *listPtr, + int first, int last)); static void DestroyListbox _ANSI_ARGS_((char *memPtr)); +static void DestroyListboxOptionTables _ANSI_ARGS_ ( + (ClientData clientData, Tcl_Interp *interp)); static void DisplayListbox _ANSI_ARGS_((ClientData clientData)); static int GetListboxIndex _ANSI_ARGS_((Tcl_Interp *interp, - Listbox *listPtr, char *string, int endIsSize, + Listbox *listPtr, Tcl_Obj *index, int endIsSize, int *indexPtr)); -static void InsertEls _ANSI_ARGS_((Listbox *listPtr, int index, - int argc, char **argv)); +static int ListboxInsertSubCmd _ANSI_ARGS_((Listbox *listPtr, + int index, int objc, Tcl_Obj *CONST objv[])); static void ListboxCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static void ListboxComputeGeometry _ANSI_ARGS_((Listbox *listPtr, @@ -294,21 +371,41 @@ static int ListboxFetchSelection _ANSI_ARGS_(( int maxBytes)); static void ListboxLostSelection _ANSI_ARGS_(( ClientData clientData)); -static void ListboxRedrawRange _ANSI_ARGS_((Listbox *listPtr, +static void EventuallyRedrawRange _ANSI_ARGS_((Listbox *listPtr, int first, int last)); static void ListboxScanTo _ANSI_ARGS_((Listbox *listPtr, int x, int y)); -static void ListboxSelect _ANSI_ARGS_((Listbox *listPtr, +static int ListboxSelect _ANSI_ARGS_((Listbox *listPtr, int first, int last, int select)); -static void ListboxUpdateHScrollbar _ANSI_ARGS_((Listbox *listPtr)); -static void ListboxUpdateVScrollbar _ANSI_ARGS_((Listbox *listPtr)); -static int ListboxWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); +static void ListboxUpdateHScrollbar _ANSI_ARGS_( + (Listbox *listPtr)); +static void ListboxUpdateVScrollbar _ANSI_ARGS_( + (Listbox *listPtr)); +static int ListboxWidgetObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +static int ListboxBboxSubCmd _ANSI_ARGS_ ((Tcl_Interp *interp, + Listbox *listPtr, int index)); +static int ListboxSelectionSubCmd _ANSI_ARGS_ ( + (Tcl_Interp *interp, Listbox *listPtr, int objc, + Tcl_Obj *CONST objv[])); +static int ListboxXviewSubCmd _ANSI_ARGS_ ((Tcl_Interp *interp, + Listbox *listPtr, int objc, + Tcl_Obj *CONST objv[])); +static int ListboxYviewSubCmd _ANSI_ARGS_ ((Tcl_Interp *interp, + Listbox *listPtr, int objc, + Tcl_Obj *CONST objv[])); +static ItemAttr * ListboxGetItemAttributes _ANSI_ARGS_ ( + (Tcl_Interp *interp, Listbox *listPtr, int index)); static void ListboxWorldChanged _ANSI_ARGS_(( ClientData instanceData)); static int NearestListboxElement _ANSI_ARGS_((Listbox *listPtr, int y)); - +static char * ListboxListVarProc _ANSI_ARGS_ ((ClientData clientData, + Tcl_Interp *interp, char *name1, char *name2, + int flags)); +static void MigrateHashEntries _ANSI_ARGS_ ((Tcl_HashTable *table, + int first, int last, int offset)); /* * The structure below defines button class behavior by means of procedures * that can be invoked from generic window code. @@ -324,7 +421,7 @@ static TkClassProcs listboxClass = { /* *-------------------------------------------------------------- * - * Tk_ListboxCmd -- + * Tk_ListboxObjCmd -- * * This procedure is invoked to process the "listbox" Tcl * command. See the user documentation for details on what @@ -340,25 +437,53 @@ static TkClassProcs listboxClass = { */ int -Tk_ListboxCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ +Tk_ListboxObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Either NULL or pointer to option table */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { register Listbox *listPtr; - Tk_Window new; - Tk_Window tkwin = (Tk_Window) clientData; + Tk_Window tkwin; + ListboxOptionTables *optionTables; + + optionTables = (ListboxOptionTables *)clientData; + if (optionTables == NULL) { + Tcl_CmdInfo info; + char *name; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); + /* + * We haven't created the option tables for this widget class yet. + * Do it now and save the a pointer to them as the ClientData for + * the command, so future invocations will have access to it. + */ + optionTables = + (ListboxOptionTables *) ckalloc(sizeof(ListboxOptionTables)); + /* Set up an exit handler to free the optionTables struct */ + Tcl_SetAssocData(interp, "ListboxOptionTables", + DestroyListboxOptionTables, (ClientData) optionTables); + + /* Create the listbox option table and the listbox item option table */ + optionTables->listboxOptionTable = + Tk_CreateOptionTable(interp, optionSpecs); + optionTables->itemAttrOptionTable = + Tk_CreateOptionTable(interp, itemAttrOptionSpecs); + + /* Store a pointer to the tables as the ClientData for the command */ + name = Tcl_GetString(objv[0]); + Tcl_GetCommandInfo(interp, name, &info); + info.objClientData = (ClientData) optionTables; + Tcl_SetCommandInfo(interp, name, &info); + } + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { + tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), + Tcl_GetString(objv[1]), (char *) NULL); + if (tkwin == NULL) { return TCL_ERROR; } @@ -367,55 +492,62 @@ Tk_ListboxCmd(clientData, interp, argc, argv) * by ConfigureListbox, or that ConfigureListbox requires to be * initialized already (e.g. resource pointers). */ - - listPtr = (Listbox *) ckalloc(sizeof(Listbox)); - listPtr->tkwin = new; - listPtr->display = Tk_Display(new); - listPtr->interp = interp; - listPtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(listPtr->tkwin), ListboxWidgetCmd, + listPtr = (Listbox *) ckalloc(sizeof(Listbox)); + listPtr->tkwin = tkwin; + listPtr->display = Tk_Display(tkwin); + listPtr->interp = interp; + listPtr->widgetCmd = Tcl_CreateObjCommand(interp, + Tk_PathName(listPtr->tkwin), ListboxWidgetObjCmd, (ClientData) listPtr, ListboxCmdDeletedProc); - listPtr->numElements = 0; - listPtr->firstPtr = NULL; - listPtr->lastPtr = NULL; - listPtr->normalBorder = NULL; - listPtr->borderWidth = 0; - listPtr->relief = TK_RELIEF_RAISED; - listPtr->highlightWidth = 0; - listPtr->highlightBgColorPtr = NULL; - listPtr->highlightColorPtr = NULL; - listPtr->inset = 0; - listPtr->tkfont = NULL; - listPtr->fgColorPtr = NULL; - listPtr->textGC = None; - listPtr->selBorder = NULL; - listPtr->selBorderWidth = 0; - listPtr->selFgColorPtr = None; - listPtr->selTextGC = None; - listPtr->width = 0; - listPtr->height = 0; - listPtr->lineHeight = 0; - listPtr->topIndex = 0; - listPtr->fullLines = 1; - listPtr->partialLine = 0; - listPtr->setGrid = 0; - listPtr->maxWidth = 0; - listPtr->xScrollUnit = 1; - listPtr->xOffset = 0; - listPtr->selectMode = NULL; - listPtr->numSelected = 0; - listPtr->selectAnchor = 0; - listPtr->exportSelection = 1; - listPtr->active = 0; - listPtr->scanMarkX = 0; - listPtr->scanMarkY = 0; - listPtr->scanMarkXOffset = 0; - listPtr->scanMarkYIndex = 0; - listPtr->cursor = None; - listPtr->takeFocus = NULL; - listPtr->xScrollCmd = NULL; - listPtr->yScrollCmd = NULL; - listPtr->flags = 0; + listPtr->optionTable = optionTables->listboxOptionTable; + listPtr->itemAttrOptionTable = optionTables->itemAttrOptionTable; + listPtr->listVarName = NULL; + listPtr->listObj = NULL; + listPtr->selection = + (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); + Tcl_InitHashTable(listPtr->selection, TCL_ONE_WORD_KEYS); + listPtr->itemAttrTable = + (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); + Tcl_InitHashTable(listPtr->itemAttrTable, TCL_ONE_WORD_KEYS); + listPtr->nElements = 0; + listPtr->normalBorder = NULL; + listPtr->borderWidth = 0; + listPtr->relief = TK_RELIEF_RAISED; + listPtr->highlightWidth = 0; + listPtr->highlightBgColorPtr = NULL; + listPtr->highlightColorPtr = NULL; + listPtr->inset = 0; + listPtr->tkfont = NULL; + listPtr->fgColorPtr = NULL; + listPtr->textGC = None; + listPtr->selBorder = NULL; + listPtr->selBorderWidth = 0; + listPtr->selFgColorPtr = None; + listPtr->selTextGC = None; + listPtr->width = 0; + listPtr->height = 0; + listPtr->lineHeight = 0; + listPtr->topIndex = 0; + listPtr->fullLines = 1; + listPtr->partialLine = 0; + listPtr->setGrid = 0; + listPtr->maxWidth = 0; + listPtr->xScrollUnit = 1; + listPtr->xOffset = 0; + listPtr->selectMode = NULL; + listPtr->numSelected = 0; + listPtr->selectAnchor = 0; + listPtr->exportSelection = 1; + listPtr->active = 0; + listPtr->scanMarkX = 0; + listPtr->scanMarkY = 0; + listPtr->scanMarkXOffset = 0; + listPtr->scanMarkYIndex = 0; + listPtr->cursor = None; + listPtr->takeFocus = NULL; + listPtr->xScrollCmd = NULL; + listPtr->yScrollCmd = NULL; + listPtr->flags = 0; Tk_SetClass(listPtr->tkwin, "Listbox"); TkSetClassProcs(listPtr->tkwin, &listboxClass, (ClientData) listPtr); @@ -424,26 +556,29 @@ Tk_ListboxCmd(clientData, interp, argc, argv) ListboxEventProc, (ClientData) listPtr); Tk_CreateSelHandler(listPtr->tkwin, XA_PRIMARY, XA_STRING, ListboxFetchSelection, (ClientData) listPtr, XA_STRING); - if (ConfigureListbox(interp, listPtr, argc-2, argv+2, 0) != TCL_OK) { - goto error; + if (Tk_InitOptions(interp, (char *)listPtr, + optionTables->listboxOptionTable, tkwin) != TCL_OK) { + Tk_DestroyWindow(listPtr->tkwin); + return TCL_ERROR; } - interp->result = Tk_PathName(listPtr->tkwin); - return TCL_OK; + if (ConfigureListbox(interp, listPtr, objc-2, objv+2, 0) != TCL_OK) { + Tk_DestroyWindow(listPtr->tkwin); + return TCL_ERROR; + } - error: - Tk_DestroyWindow(listPtr->tkwin); - return TCL_ERROR; + Tcl_SetResult(interp, Tk_PathName(listPtr->tkwin), TCL_STATIC); + return TCL_OK; } /* - *-------------------------------------------------------------- + *---------------------------------------------------------------------- * - * ListboxWidgetCmd -- + * ListboxWidgetObjCmd -- * - * This procedure is invoked to process the Tcl command - * that corresponds to a widget managed by this module. - * See the user documentation for details on what it does. + * This Tcl_Obj based procedure is invoked to process the Tcl command + * that corresponds to a widget managed by this module. See the user + * documentation for details on what it does. * * Results: * A standard Tcl result. @@ -451,477 +586,804 @@ Tk_ListboxCmd(clientData, interp, argc, argv) * Side effects: * See the user documentation. * - *-------------------------------------------------------------- + *---------------------------------------------------------------------- */ static int -ListboxWidgetCmd(clientData, interp, argc, argv) +ListboxWidgetObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about listbox widget. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Arguments as Tcl_Obj's. */ { register Listbox *listPtr = (Listbox *) clientData; + int cmdIndex, index; int result = TCL_OK; - size_t length; - int c; - Tk_FontMetrics fm; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } - Tcl_Preserve((ClientData) listPtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0)) { - int index; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " activate index\"", - (char *) NULL); - goto error; - } - ListboxRedrawRange(listPtr, listPtr->active, listPtr->active); - if (GetListboxIndex(interp, listPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index >= listPtr->numElements) { - index = listPtr->numElements-1; - } - if (index < 0) { - index = 0; - } - listPtr->active = index; - ListboxRedrawRange(listPtr, listPtr->active, listPtr->active); - } else if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) { - int index, x, y, i; - Element *elPtr; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " bbox index\"", (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if ((index >= listPtr->numElements) || (index < 0)) { - goto done; - } - for (i = 0, elPtr = listPtr->firstPtr; i < index; - i++, elPtr = elPtr->nextPtr) { - /* Empty loop body. */ - } - if ((index >= listPtr->topIndex) && (index < listPtr->numElements) - && (index < (listPtr->topIndex + listPtr->fullLines - + listPtr->partialLine))) { - x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset; - y = ((index - listPtr->topIndex)*listPtr->lineHeight) - + listPtr->inset + listPtr->selBorderWidth; - Tk_GetFontMetrics(listPtr->tkfont, &fm); - sprintf(interp->result, "%d %d %d %d", x, y, elPtr->pixelWidth, - fm.linespace); - } - } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, listPtr->tkwin, configSpecs, - (char *) listPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, listPtr->tkwin, configSpecs, - (char *) listPtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, listPtr->tkwin, configSpecs, - (char *) listPtr, argv[2], 0); - } else { - result = ConfigureListbox(interp, listPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'c') && (strncmp(argv[1], "curselection", length) == 0) - && (length >= 2)) { - int i, count; - char index[20]; - Element *elPtr; + Tcl_Preserve((ClientData)listPtr); - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " curselection\"", - (char *) NULL); - goto error; - } - count = 0; - for (i = 0, elPtr = listPtr->firstPtr; elPtr != NULL; - i++, elPtr = elPtr->nextPtr) { - if (elPtr->selected) { - sprintf(index, "%d", i); - Tcl_AppendElement(interp, index); - count++; + /* + * Parse the command by looking up the second argument in the list + * of valid subcommand names + */ + result = Tcl_GetIndexFromObj(interp, objv[1], commandNames, + "option", 0, &cmdIndex); + if (result != TCL_OK) { + Tcl_Release((ClientData)listPtr); + return result; + } + + /* The subcommand was valid, so continue processing */ + switch (cmdIndex) { + case COMMAND_ACTIVATE: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index"); + result = TCL_ERROR; + break; } + result = GetListboxIndex(interp, listPtr, objv[2], 0, &index); + if (result != TCL_OK) { + break; + } + if (index >= listPtr->nElements) { + index = listPtr->nElements-1; + } + if (index < 0) { + index = 0; + } + listPtr->active = index; + EventuallyRedrawRange(listPtr, listPtr->active, listPtr->active); + result = TCL_OK; + break; } - if (count != listPtr->numSelected) { - panic("ListboxWidgetCmd: selection count incorrect"); - } - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) { - int first, last; - if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " delete firstIndex ?lastIndex?\"", - (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 0, &first) != TCL_OK) { - goto error; + case COMMAND_BBOX: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index"); + result = TCL_ERROR; + break; + } + result = GetListboxIndex(interp, listPtr, objv[2], 0, &index); + if (result != TCL_OK) { + break; + } + + result = ListboxBboxSubCmd(interp, listPtr, index); + break; } - if (first < listPtr->numElements) { - if (argc == 3) { - last = first; + + case COMMAND_CGET: { + Tcl_Obj *objPtr; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); + result = TCL_ERROR; + break; + } + + objPtr = Tk_GetOptionValue(interp, (char *)listPtr, + listPtr->optionTable, objv[2], listPtr->tkwin); + if (objPtr == NULL) { + result = TCL_ERROR; + break; + } + Tcl_SetObjResult(interp, objPtr); + result = TCL_OK; + break; + } + + case COMMAND_CONFIGURE: { + Tcl_Obj *objPtr; + if (objc <= 3) { + objPtr = Tk_GetOptionInfo(interp, (char *) listPtr, + listPtr->optionTable, + (objc == 3) ? objv[2] : (Tcl_Obj *) NULL, + listPtr->tkwin); + if (objPtr == NULL) { + result = TCL_ERROR; + break; + } else { + Tcl_SetObjResult(interp, objPtr); + result = TCL_OK; + } } else { - if (GetListboxIndex(interp, listPtr, argv[3], 0, - &last) != TCL_OK) { - goto error; + result = ConfigureListbox(interp, listPtr, objc-2, objv+2, 0); + } + break; + } + + case COMMAND_CURSELECTION: { + char indexStringRep[TCL_INTEGER_SPACE]; + int i; + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + result = TCL_ERROR; + break; + } + /* + * Of course, it would be more efficient to use the Tcl_HashTable + * search functions (Tcl_FirstHashEntry, Tcl_NextHashEntry), but + * then the result wouldn't be in sorted order. So instead we + * loop through the indices in order, adding them to the result + * if they are selected + */ + for (i = 0; i < listPtr->nElements; i++) { + if (Tcl_FindHashEntry(listPtr->selection, (char *)i) != NULL) { + sprintf(indexStringRep, "%d", i); + Tcl_AppendElement(interp, indexStringRep); + } + } + result = TCL_OK; + break; + } + + case COMMAND_DELETE: { + int first, last; + if ((objc < 3) || (objc > 4)) { + Tcl_WrongNumArgs(interp, 2, objv, + "firstIndex ?lastIndex?"); + result = TCL_ERROR; + break; + } + + result = GetListboxIndex(interp, listPtr, objv[2], 0, &first); + if (result != TCL_OK) { + break; + } + if (first < listPtr->nElements) { + /* + * if a "last index" was given, get it now; otherwise, use the + * first index as the last index + */ + if (objc == 4) { + result = GetListboxIndex(interp, listPtr, + objv[3], 0, &last); + if (result != TCL_OK) { + break; + } + } else { + last = first; } - if (last >= listPtr->numElements) { - last = listPtr->numElements-1; + if (last >= listPtr->nElements) { + last = listPtr->nElements - 1; } + result = ListboxDeleteSubCmd(listPtr, first, last); + } else { + result = TCL_OK; } - DeleteEls(listPtr, first, last); + break; } - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - int first, last, i; - Element *elPtr; - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " get first ?last?\"", (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 0, &first) != TCL_OK) { - goto error; - } - if ((argc == 4) && (GetListboxIndex(interp, listPtr, argv[3], - 0, &last) != TCL_OK)) { - goto error; - } - if (first >= listPtr->numElements) { - goto done; - } - if (last >= listPtr->numElements) { - last = listPtr->numElements-1; + case COMMAND_GET: { + int first, last; + Tcl_Obj **elemPtrs; + int listLen; + if (objc != 3 && objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?"); + result = TCL_ERROR; + break; + } + result = GetListboxIndex(interp, listPtr, objv[2], 0, &first); + if (result != TCL_OK) { + break; + } + last = first; + if (objc == 4) { + result = GetListboxIndex(interp, listPtr, objv[3], 0, &last); + if (result != TCL_OK) { + break; + } + } + if (first >= listPtr->nElements) { + result = TCL_OK; + break; + } + if (last >= listPtr->nElements) { + last = listPtr->nElements - 1; + } + if (first < 0) { + first = 0; + } + if (first > last) { + result = TCL_OK; + break; + } + result = Tcl_ListObjGetElements(interp, listPtr->listObj, &listLen, + &elemPtrs); + if (result != TCL_OK) { + break; + } + if (objc == 3) { + /* + * One element request - we return a string + */ + Tcl_SetObjResult(interp, elemPtrs[first]); + } else { + Tcl_SetListObj(Tcl_GetObjResult(interp), (last - first + 1), + &(elemPtrs[first])); + } + result = TCL_OK; + break; } - for (elPtr = listPtr->firstPtr, i = 0; i < first; - i++, elPtr = elPtr->nextPtr) { - /* Empty loop body. */ + case COMMAND_INDEX:{ + char buf[TCL_INTEGER_SPACE]; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index"); + result = TCL_ERROR; + break; + } + result = GetListboxIndex(interp, listPtr, objv[2], 1, &index); + if (result != TCL_OK) { + break; + } + sprintf(buf, "%d", index); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + result = TCL_OK; + break; + } + + case COMMAND_INSERT: { + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, + "index ?element element ...?"); + result = TCL_ERROR; + break; + } + + result = GetListboxIndex(interp, listPtr, objv[2], 1, &index); + if (result != TCL_OK) { + break; + } + result = ListboxInsertSubCmd(listPtr, index, objc-3, objv+3); + break; } - if (elPtr != NULL) { - if (argc == 3) { - if (first >= 0) { - interp->result = elPtr->text; + + case COMMAND_ITEMCGET: { + Tcl_Obj *objPtr; + ItemAttr *attrPtr; + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "index option"); + result = TCL_ERROR; + break; + } + + result = GetListboxIndex(interp, listPtr, objv[2], 0, &index); + if (result != TCL_OK) { + break; + } + + if (index < 0 || index >= listPtr->nElements) { + Tcl_AppendResult(interp, "item number \"", + Tcl_GetString(objv[2]), "\" out of range", + (char *)NULL); + result = TCL_ERROR; + break; + } + + attrPtr = ListboxGetItemAttributes(interp, listPtr, index); + + objPtr = Tk_GetOptionValue(interp, (char *)attrPtr, + listPtr->itemAttrOptionTable, objv[3], listPtr->tkwin); + if (objPtr == NULL) { + result = TCL_ERROR; + break; + } + Tcl_SetObjResult(interp, objPtr); + result = TCL_OK; + break; + } + + case COMMAND_ITEMCONFIGURE: { + Tcl_Obj *objPtr; + ItemAttr *attrPtr; + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, + "index ?option? ?value? ?option value ...?"); + result = TCL_ERROR; + break; + } + + result = GetListboxIndex(interp, listPtr, objv[2], 0, &index); + if (result != TCL_OK) { + break; + } + + if (index < 0 || index >= listPtr->nElements) { + Tcl_AppendResult(interp, "item number \"", + Tcl_GetString(objv[2]), "\" out of range", + (char *)NULL); + result = TCL_ERROR; + break; + } + + attrPtr = ListboxGetItemAttributes(interp, listPtr, index); + if (objc <= 4) { + objPtr = Tk_GetOptionInfo(interp, (char *)attrPtr, + listPtr->itemAttrOptionTable, + (objc == 4) ? objv[3] : (Tcl_Obj *) NULL, + listPtr->tkwin); + if (objPtr == NULL) { + result = TCL_ERROR; + break; + } else { + Tcl_SetObjResult(interp, objPtr); + result = TCL_OK; } } else { - for ( ; i <= last; i++, elPtr = elPtr->nextPtr) { - Tcl_AppendElement(interp, elPtr->text); + result = ConfigureListboxItem(interp, listPtr, attrPtr, + objc-3, objv+3); + } + break; + } + + case COMMAND_NEAREST: { + char buf[TCL_INTEGER_SPACE]; + int y; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "y"); + result = TCL_ERROR; + break; + } + + result = Tcl_GetIntFromObj(interp, objv[2], &y); + if (result != TCL_OK) { + break; + } + index = NearestListboxElement(listPtr, y); + sprintf(buf, "%d", index); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + result = TCL_OK; + break; + } + + case COMMAND_SCAN: { + int x, y, scanCmdIndex; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y"); + result = TCL_ERROR; + break; + } + + if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK + || Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) { + result = TCL_ERROR; + break; + } + + result = Tcl_GetIndexFromObj(interp, objv[2], scanCommandNames, + "option", 0, &scanCmdIndex); + if (result != TCL_OK) { + break; + } + switch (scanCmdIndex) { + case SCAN_MARK: { + listPtr->scanMarkX = x; + listPtr->scanMarkY = y; + listPtr->scanMarkXOffset = listPtr->xOffset; + listPtr->scanMarkYIndex = listPtr->topIndex; + break; + } + case SCAN_DRAGTO: { + ListboxScanTo(listPtr, x, y); + break; } } + result = TCL_OK; + break; } - } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0) - && (length >= 3)) { - int index; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " index index\"", - (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 1, &index) - != TCL_OK) { - goto error; - } - sprintf(interp->result, "%d", index); - } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0) - && (length >= 3)) { - int index; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " insert index ?element element ...?\"", - (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 1, &index) - != TCL_OK) { - goto error; - } - InsertEls(listPtr, index, argc-3, argv+3); - } else if ((c == 'n') && (strncmp(argv[1], "nearest", length) == 0)) { - int index, y; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " nearest y\"", (char *) NULL); - goto error; - } - if (Tcl_GetInt(interp, argv[2], &y) != TCL_OK) { - goto error; - } - index = NearestListboxElement(listPtr, y); - sprintf(interp->result, "%d", index); - } else if ((c == 's') && (length >= 2) - && (strncmp(argv[1], "scan", length) == 0)) { - int x, y; - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scan mark|dragto x y\"", (char *) NULL); - goto error; - } - if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)) { - goto error; - } - if ((argv[2][0] == 'm') - && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) { - listPtr->scanMarkX = x; - listPtr->scanMarkY = y; - listPtr->scanMarkXOffset = listPtr->xOffset; - listPtr->scanMarkYIndex = listPtr->topIndex; - } else if ((argv[2][0] == 'd') - && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) { - ListboxScanTo(listPtr, x, y); - } else { - Tcl_AppendResult(interp, "bad scan option \"", argv[2], - "\": must be mark or dragto", (char *) NULL); - goto error; - } - } else if ((c == 's') && (strncmp(argv[1], "see", length) == 0) - && (length >= 3)) { - int index, diff; - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " see index\"", - (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index >= listPtr->numElements) { - index = listPtr->numElements-1; - } - if (index < 0) { - index = 0; - } - diff = listPtr->topIndex-index; - if (diff > 0) { - if (diff <= (listPtr->fullLines/3)) { - ChangeListboxView(listPtr, index); - } else { - ChangeListboxView(listPtr, index - (listPtr->fullLines-1)/2); + + case COMMAND_SEE: { + int diff; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index"); + result = TCL_ERROR; + break; } - } else { - diff = index - (listPtr->topIndex + listPtr->fullLines - 1); + result = GetListboxIndex(interp, listPtr, objv[2], 0, &index); + if (result != TCL_OK) { + break; + } + if (index >= listPtr->nElements) { + index = listPtr->nElements - 1; + } + if (index < 0) { + index = 0; + } + diff = listPtr->topIndex - index; if (diff > 0) { if (diff <= (listPtr->fullLines/3)) { - ChangeListboxView(listPtr, listPtr->topIndex + diff); + ChangeListboxView(listPtr, index); } else { ChangeListboxView(listPtr, index - (listPtr->fullLines-1)/2); } + } else { + diff = index - (listPtr->topIndex + listPtr->fullLines - 1); + if (diff > 0) { + if (diff <= (listPtr->fullLines/3)) { + ChangeListboxView(listPtr, listPtr->topIndex + diff); + } else { + ChangeListboxView(listPtr, + index - (listPtr->fullLines-1)/2); + } + } } + result = TCL_OK; + break; } - } else if ((c == 's') && (length >= 3) - && (strncmp(argv[1], "selection", length) == 0)) { - int first, last; - if ((argc != 4) && (argc != 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection option index ?index?\"", - (char *) NULL); - goto error; - } - if (GetListboxIndex(interp, listPtr, argv[3], 0, &first) != TCL_OK) { - goto error; + case COMMAND_SELECTION: { + result = ListboxSelectionSubCmd(interp, listPtr, objc, objv); + break; } - if (argc == 5) { - if (GetListboxIndex(interp, listPtr, argv[4], 0, &last) != TCL_OK) { - goto error; + + case COMMAND_SIZE: { + char buf[TCL_INTEGER_SPACE]; + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + result = TCL_ERROR; + break; } - } else { - last = first; + sprintf(buf, "%d", listPtr->nElements); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + result = TCL_OK; + break; } - length = strlen(argv[2]); - c = argv[2][0]; - if ((c == 'a') && (strncmp(argv[2], "anchor", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection anchor index\"", (char *) NULL); - goto error; + + case COMMAND_XVIEW: { + result = ListboxXviewSubCmd(interp, listPtr, objc, objv); + break; + } + + case COMMAND_YVIEW: { + result = ListboxYviewSubCmd(interp, listPtr, objc, objv); + break; + } + } + Tcl_Release((ClientData)listPtr); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * ListboxBboxSubCmd -- + * + * This procedure is invoked to process a listbox bbox request. + * See the user documentation for more information. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * For valid indices, places the bbox of the requested element in + * the interpreter's result. + * + *---------------------------------------------------------------------- + */ + +static int +ListboxBboxSubCmd(interp, listPtr, index) + Tcl_Interp *interp; /* Pointer to the calling Tcl interpreter */ + Listbox *listPtr; /* Information about the listbox */ + int index; /* Index of the element to get bbox info on */ +{ + int lastVisibleIndex; + /* Determine the index of the last visible item in the listbox */ + lastVisibleIndex = listPtr->topIndex + listPtr->fullLines + + listPtr->partialLine; + if (listPtr->nElements < lastVisibleIndex) { + lastVisibleIndex = listPtr->nElements; + } + + /* Only allow bbox requests for indices that are visible */ + if ((listPtr->topIndex <= index) && (index < lastVisibleIndex)) { + char buf[TCL_INTEGER_SPACE * 4]; + Tcl_Obj *el; + char *stringRep; + int pixelWidth, stringLen, x, y, result; + Tk_FontMetrics fm; + + /* Compute the pixel width of the requested element */ + result = Tcl_ListObjIndex(interp, listPtr->listObj, index, &el); + if (result != TCL_OK) { + return result; + } + + stringRep = Tcl_GetStringFromObj(el, &stringLen); + Tk_GetFontMetrics(listPtr->tkfont, &fm); + pixelWidth = Tk_TextWidth(listPtr->tkfont, stringRep, stringLen); + + x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset; + y = ((index - listPtr->topIndex)*listPtr->lineHeight) + + listPtr->inset + listPtr->selBorderWidth; + sprintf(buf, "%d %d %d %d", x, y, pixelWidth, fm.linespace); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ListboxSelectionSubCmd -- + * + * This procedure is invoked to process the selection sub command + * for listbox widgets. + * + * Results: + * Standard Tcl result. + * + * Side effects: + * May set the interpreter's result field. + * + *---------------------------------------------------------------------- + */ + +static int +ListboxSelectionSubCmd(interp, listPtr, objc, objv) + Tcl_Interp *interp; /* Pointer to the calling Tcl interpreter */ + Listbox *listPtr; /* Information about the listbox */ + int objc; /* Number of arguments in the objv array */ + Tcl_Obj *CONST objv[]; /* Array of arguments to the procedure */ +{ + int selCmdIndex, first, last; + int result = TCL_OK; + if (objc != 4 && objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "option index ?index?"); + return TCL_ERROR; + } + result = GetListboxIndex(interp, listPtr, objv[3], 0, &first); + if (result != TCL_OK) { + return result; + } + last = first; + if (objc == 5) { + result = GetListboxIndex(interp, listPtr, objv[4], 0, &last); + if (result != TCL_OK) { + return result; + } + } + result = Tcl_GetIndexFromObj(interp, objv[2], selCommandNames, + "option", 0, &selCmdIndex); + if (result != TCL_OK) { + return result; + } + switch (selCmdIndex) { + case SELECTION_ANCHOR: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "index"); + return TCL_ERROR; } - if (first >= listPtr->numElements) { - first = listPtr->numElements-1; + if (first >= listPtr->nElements) { + first = listPtr->nElements - 1; } if (first < 0) { first = 0; } listPtr->selectAnchor = first; - } else if ((c == 'c') && (strncmp(argv[2], "clear", length) == 0)) { - ListboxSelect(listPtr, first, last, 0); - } else if ((c == 'i') && (strncmp(argv[2], "includes", length) == 0)) { - int i; - Element *elPtr; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " selection includes index\"", (char *) NULL); - goto error; - } - if ((first < 0) || (first >= listPtr->numElements)) { - interp->result = "0"; - goto done; - } - for (elPtr = listPtr->firstPtr, i = 0; i < first; - i++, elPtr = elPtr->nextPtr) { - /* Empty loop body. */ + result = TCL_OK; + break; + } + case SELECTION_CLEAR: { + result = ListboxSelect(listPtr, first, last, 0); + break; + } + case SELECTION_INCLUDES: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "index"); + return TCL_ERROR; } - if (elPtr->selected) { - interp->result = "1"; + if (Tcl_FindHashEntry(listPtr->selection, (char *)first)) { + Tcl_SetResult(interp, "1", TCL_STATIC); } else { - interp->result = "0"; + Tcl_SetResult(interp, "0", TCL_STATIC); } - } else if ((c == 's') && (strncmp(argv[2], "set", length) == 0)) { - ListboxSelect(listPtr, first, last, 1); + result = TCL_OK; + break; + } + case SELECTION_SET: { + result = ListboxSelect(listPtr, first, last, 1); + break; + } + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * ListboxXviewSubCmd -- + * + * Process the listbox "xview" subcommand. + * + * Results: + * Standard Tcl result. + * + * Side effects: + * May change the listbox viewing area; may set the interpreter's result. + * + *---------------------------------------------------------------------- + */ + +static int +ListboxXviewSubCmd(interp, listPtr, objc, objv) + Tcl_Interp *interp; /* Pointer to the calling Tcl interpreter */ + Listbox *listPtr; /* Information about the listbox */ + int objc; /* Number of arguments in the objv array */ + Tcl_Obj *CONST objv[]; /* Array of arguments to the procedure */ +{ + + int index, count, type, windowWidth, windowUnits; + int offset = 0; /* Initialized to stop gcc warnings. */ + double fraction, fraction2; + + windowWidth = Tk_Width(listPtr->tkwin) + - 2*(listPtr->inset + listPtr->selBorderWidth); + if (objc == 2) { + if (listPtr->maxWidth == 0) { + Tcl_SetResult(interp, "0 1", TCL_STATIC); } else { - Tcl_AppendResult(interp, "bad selection option \"", argv[2], - "\": must be anchor, clear, includes, or set", - (char *) NULL); - goto error; - } - } else if ((c == 's') && (length >= 2) - && (strncmp(argv[1], "size", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " size\"", (char *) NULL); - goto error; - } - sprintf(interp->result, "%d", listPtr->numElements); - } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) { - int index, count, type, windowWidth, windowUnits; - int offset = 0; /* Initialized to stop gcc warnings. */ - double fraction, fraction2; - - windowWidth = Tk_Width(listPtr->tkwin) - - 2*(listPtr->inset + listPtr->selBorderWidth); - if (argc == 2) { - if (listPtr->maxWidth == 0) { - interp->result = "0 1"; - } else { - fraction = listPtr->xOffset/((double) listPtr->maxWidth); - fraction2 = (listPtr->xOffset + windowWidth) - /((double) listPtr->maxWidth); - if (fraction2 > 1.0) { - fraction2 = 1.0; - } - sprintf(interp->result, "%g %g", fraction, fraction2); - } - } else if (argc == 3) { - if (Tcl_GetInt(interp, argv[2], &index) != TCL_OK) { - goto error; + char buf[TCL_DOUBLE_SPACE * 2]; + + fraction = listPtr->xOffset/((double) listPtr->maxWidth); + fraction2 = (listPtr->xOffset + windowWidth) + /((double) listPtr->maxWidth); + if (fraction2 > 1.0) { + fraction2 = 1.0; } - ChangeListboxOffset(listPtr, index*listPtr->xScrollUnit); - } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); - switch (type) { - case TK_SCROLL_ERROR: - goto error; - case TK_SCROLL_MOVETO: - offset = (int) (fraction*listPtr->maxWidth + 0.5); - break; - case TK_SCROLL_PAGES: - windowUnits = windowWidth/listPtr->xScrollUnit; - if (windowUnits > 2) { - offset = listPtr->xOffset - + count*listPtr->xScrollUnit*(windowUnits-2); - } else { - offset = listPtr->xOffset + count*listPtr->xScrollUnit; - } - break; - case TK_SCROLL_UNITS: + sprintf(buf, "%g %g", fraction, fraction2); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + } + } else if (objc == 3) { + if (Tcl_GetIntFromObj(interp, objv[2], &index) != TCL_OK) { + return TCL_ERROR; + } + ChangeListboxOffset(listPtr, index*listPtr->xScrollUnit); + } else { + type = Tk_GetScrollInfoObj(interp, objc, objv, &fraction, &count); + switch (type) { + case TK_SCROLL_ERROR: + return TCL_ERROR; + case TK_SCROLL_MOVETO: + offset = (int) (fraction*listPtr->maxWidth + 0.5); + break; + case TK_SCROLL_PAGES: + windowUnits = windowWidth/listPtr->xScrollUnit; + if (windowUnits > 2) { + offset = listPtr->xOffset + + count*listPtr->xScrollUnit*(windowUnits-2); + } else { offset = listPtr->xOffset + count*listPtr->xScrollUnit; - break; - } - ChangeListboxOffset(listPtr, offset); + } + break; + case TK_SCROLL_UNITS: + offset = listPtr->xOffset + count*listPtr->xScrollUnit; + break; } - } else if ((c == 'y') && (strncmp(argv[1], "yview", length) == 0)) { - int index, count, type; - double fraction, fraction2; + ChangeListboxOffset(listPtr, offset); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ListboxYviewSubCmd -- + * + * Process the listbox "yview" subcommand. + * + * Results: + * Standard Tcl result. + * + * Side effects: + * May change the listbox viewing area; may set the interpreter's result. + * + *---------------------------------------------------------------------- + */ - if (argc == 2) { - if (listPtr->numElements == 0) { - interp->result = "0 1"; - } else { - fraction = listPtr->topIndex/((double) listPtr->numElements); - fraction2 = (listPtr->topIndex+listPtr->fullLines) - /((double) listPtr->numElements); - if (fraction2 > 1.0) { - fraction2 = 1.0; - } - sprintf(interp->result, "%g %g", fraction, fraction2); - } - } else if (argc == 3) { - if (GetListboxIndex(interp, listPtr, argv[2], 0, &index) - != TCL_OK) { - goto error; - } - ChangeListboxView(listPtr, index); +static int +ListboxYviewSubCmd(interp, listPtr, objc, objv) + Tcl_Interp *interp; /* Pointer to the calling Tcl interpreter */ + Listbox *listPtr; /* Information about the listbox */ + int objc; /* Number of arguments in the objv array */ + Tcl_Obj *CONST objv[]; /* Array of arguments to the procedure */ +{ + int index, count, type; + double fraction, fraction2; + + if (objc == 2) { + if (listPtr->nElements == 0) { + Tcl_SetResult(interp, "0 1", TCL_STATIC); } else { - type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); - switch (type) { - case TK_SCROLL_ERROR: - goto error; - case TK_SCROLL_MOVETO: - index = (int) (listPtr->numElements*fraction + 0.5); - break; - case TK_SCROLL_PAGES: - if (listPtr->fullLines > 2) { - index = listPtr->topIndex - + count*(listPtr->fullLines-2); - } else { - index = listPtr->topIndex + count; - } - break; - case TK_SCROLL_UNITS: - index = listPtr->topIndex + count; - break; + char buf[TCL_DOUBLE_SPACE * 2]; + + fraction = listPtr->topIndex/((double) listPtr->nElements); + fraction2 = (listPtr->topIndex+listPtr->fullLines) + /((double) listPtr->nElements); + if (fraction2 > 1.0) { + fraction2 = 1.0; } - ChangeListboxView(listPtr, index); + sprintf(buf, "%g %g", fraction, fraction2); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + } + } else if (objc == 3) { + if (GetListboxIndex(interp, listPtr, objv[2], 0, &index) != TCL_OK) { + return TCL_ERROR; } + ChangeListboxView(listPtr, index); } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be activate, bbox, cget, configure, ", - "curselection, delete, get, index, insert, nearest, ", - "scan, see, selection, size, ", - "xview, or yview", (char *) NULL); - goto error; - } - done: - Tcl_Release((ClientData) listPtr); - return result; + type = Tk_GetScrollInfoObj(interp, objc, objv, &fraction, &count); + switch (type) { + case TK_SCROLL_ERROR: + return TCL_ERROR; + case TK_SCROLL_MOVETO: + index = (int) (listPtr->nElements*fraction + 0.5); + break; + case TK_SCROLL_PAGES: + if (listPtr->fullLines > 2) { + index = listPtr->topIndex + + count*(listPtr->fullLines-2); + } else { + index = listPtr->topIndex + count; + } + break; + case TK_SCROLL_UNITS: + index = listPtr->topIndex + count; + break; + } + ChangeListboxView(listPtr, index); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ListboxGetItemAttributes -- + * + * Returns a pointer to the ItemAttr record for a given index, + * creating one if it does not already exist. + * + * Results: + * Pointer to an ItemAttr record. + * + * Side effects: + * Memory may be allocated for the ItemAttr record. + * + *---------------------------------------------------------------------- + */ - error: - Tcl_Release((ClientData) listPtr); - return TCL_ERROR; +static ItemAttr * +ListboxGetItemAttributes(interp, listPtr, index) + Tcl_Interp *interp; /* Pointer to the calling Tcl interpreter */ + Listbox *listPtr; /* Information about the listbox */ + int index; /* Index of the item to retrieve attributes + * for */ +{ + int new; + Tcl_HashEntry *entry; + ItemAttr *attrs; + + entry = Tcl_CreateHashEntry(listPtr->itemAttrTable, (char *)index, + &new); + if (new) { + attrs = (ItemAttr *) ckalloc(sizeof(ItemAttr)); + attrs->border = NULL; + attrs->selBorder = NULL; + attrs->fgColor = NULL; + attrs->selFgColor = NULL; + Tk_InitOptions(interp, (char *)attrs, listPtr->itemAttrOptionTable, + listPtr->tkwin); + Tcl_SetHashValue(entry, (ClientData) attrs); + } + attrs = (ItemAttr *)Tcl_GetHashValue(entry); + return attrs; } /* @@ -947,18 +1409,43 @@ DestroyListbox(memPtr) char *memPtr; /* Info about listbox widget. */ { register Listbox *listPtr = (Listbox *) memPtr; - register Element *elPtr, *nextPtr; + Tcl_HashEntry *entry; + Tcl_HashSearch search; - /* - * Free up all of the list elements. - */ + listPtr->flags |= LISTBOX_DELETED; - for (elPtr = listPtr->firstPtr; elPtr != NULL; ) { - nextPtr = elPtr->nextPtr; - ckfree((char *) elPtr); - elPtr = nextPtr; + Tcl_DeleteCommandFromToken(listPtr->interp, listPtr->widgetCmd); + if (listPtr->setGrid) { + Tk_UnsetGrid(listPtr->tkwin); + } + if (listPtr->flags & REDRAW_PENDING) { + Tcl_CancelIdleCall(DisplayListbox, (ClientData) listPtr); } + /* If we have an internal list object, free it */ + if (listPtr->listObj != NULL) { + Tcl_DecrRefCount(listPtr->listObj); + listPtr->listObj = NULL; + } + + if (listPtr->listVarName != NULL) { + Tcl_UntraceVar(listPtr->interp, listPtr->listVarName, + TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + ListboxListVarProc, (ClientData) listPtr); + } + + /* Free the selection hash table */ + Tcl_DeleteHashTable(listPtr->selection); + ckfree((char *)listPtr->selection); + + /* Free the item attribute hash table */ + for (entry = Tcl_FirstHashEntry(listPtr->itemAttrTable, &search); + entry != NULL; entry = Tcl_NextHashEntry(&search)) { + ckfree((char *)Tcl_GetHashValue(entry)); + } + Tcl_DeleteHashTable(listPtr->itemAttrTable); + ckfree((char *)listPtr->itemAttrTable); + /* * Free up all the stuff that requires special handling, then * let Tk_FreeOptions handle all the standard option-related @@ -971,22 +1458,51 @@ DestroyListbox(memPtr) if (listPtr->selTextGC != None) { Tk_FreeGC(listPtr->display, listPtr->selTextGC); } - Tk_FreeOptions(configSpecs, (char *) listPtr, listPtr->display, 0); + Tk_FreeConfigOptions((char *)listPtr, listPtr->optionTable, + listPtr->tkwin); + listPtr->tkwin = NULL; ckfree((char *) listPtr); } /* *---------------------------------------------------------------------- * + * DestroyListboxOptionTables -- + * + * This procedure is registered as an exit callback when the listbox + * command is first called. It cleans up the OptionTables structure + * allocated by that command. + * + * Results: + * None. + * + * Side effects: + * Frees memory. + * + *---------------------------------------------------------------------- + */ + +static void +DestroyListboxOptionTables(clientData, interp) + ClientData clientData; /* Pointer to the OptionTables struct */ + Tcl_Interp *interp; /* Pointer to the calling interp */ +{ + ckfree((char *)clientData); + return; +} + +/* + *---------------------------------------------------------------------- + * * ConfigureListbox -- * - * This procedure is called to process an argv/argc list, plus + * This procedure is called to process an objv/objc list, plus * the Tk option database, in order to configure (or reconfigure) * a listbox widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as colors, border width, @@ -997,22 +1513,32 @@ DestroyListbox(memPtr) */ static int -ConfigureListbox(interp, listPtr, argc, argv, flags) +ConfigureListbox(interp, listPtr, objc, objv, flags) Tcl_Interp *interp; /* Used for error reporting. */ register Listbox *listPtr; /* Information about widget; may or may * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ + int objc; /* Number of valid entries in argv. */ + Tcl_Obj *CONST objv[]; /* Arguments. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { + Tk_SavedOptions savedOptions; + Tcl_Obj *oldListObj = NULL; int oldExport; oldExport = listPtr->exportSelection; - if (Tk_ConfigureWidget(interp, listPtr->tkwin, configSpecs, - argc, argv, (char *) listPtr, flags) != TCL_OK) { + if (listPtr->listVarName != NULL) { + Tcl_UntraceVar(interp, listPtr->listVarName, + TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + ListboxListVarProc, (ClientData) listPtr); + } + + if (Tk_SetOptions(interp, (char *)listPtr, + listPtr->optionTable, objc, objv, listPtr->tkwin, + &savedOptions, (int *)NULL) != TCL_OK) { + Tk_RestoreSavedOptions(&savedOptions); return TCL_ERROR; } - + /* * A few options need special processing, such as setting the * background from a 3-D border. @@ -1036,6 +1562,109 @@ ConfigureListbox(interp, listPtr, argc, argv, flags) (ClientData) listPtr); } + + /* Verify the current status of the list var. + * PREVIOUS STATE | NEW STATE | ACTION + * ------------------+---------------+---------------------------------- + * no listvar | listvar | If listvar does not exist, create + * it and copy the internal list obj's + * content to the new var. If it does + * exist, toss the internal list obj. + * + * listvar | no listvar | Copy old listvar content to the + * internal list obj + * + * listvar | listvar | no special action + * + * no listvar | no listvar | no special action + */ + oldListObj = listPtr->listObj; + if (listPtr->listVarName != NULL) { + Tcl_Obj *listVarObj = Tcl_GetVar2Ex(interp, listPtr->listVarName, + (char *)NULL, TCL_GLOBAL_ONLY); + int dummy; + if (listVarObj == NULL) { + if (listPtr->listObj != NULL) { + listVarObj = listPtr->listObj; + } else { + listVarObj = Tcl_NewObj(); + } + if (Tcl_SetVar2Ex(interp, listPtr->listVarName, (char *)NULL, + listVarObj, TCL_GLOBAL_ONLY) == NULL) { + Tcl_DecrRefCount(listVarObj); + Tk_RestoreSavedOptions(&savedOptions); + return TCL_ERROR; + } + } + /* Make sure the object is a good list object */ + if (Tcl_ListObjLength(listPtr->interp, listVarObj, &dummy) != TCL_OK) { + Tk_RestoreSavedOptions(&savedOptions); + Tcl_AppendResult(listPtr->interp, ": invalid listvar value", + (char *)NULL); + return TCL_ERROR; + } + + listPtr->listObj = listVarObj; + Tcl_TraceVar(listPtr->interp, listPtr->listVarName, + TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + ListboxListVarProc, (ClientData) listPtr); + } else { + if (listPtr->listObj == NULL) { + listPtr->listObj = Tcl_NewObj(); + } + } + Tcl_IncrRefCount(listPtr->listObj); + if (oldListObj != NULL) { + Tcl_DecrRefCount(oldListObj); + } + + /* Make sure that the list length is correct */ + Tcl_ListObjLength(listPtr->interp, listPtr->listObj, &listPtr->nElements); + + Tk_FreeSavedOptions(&savedOptions); + ListboxWorldChanged((ClientData) listPtr); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ConfigureListboxItem -- + * + * This procedure is called to process an objv/objc list, plus + * the Tk option database, in order to configure (or reconfigure) + * a listbox item. + * + * Results: + * The return value is a standard Tcl result. If TCL_ERROR is + * returned, then the interp's result contains an error message. + * + * Side effects: + * Configuration information, such as colors, border width, + * etc. get set for a listbox item; old resources get freed, + * if there were any. + * + *---------------------------------------------------------------------- + */ + +static int +ConfigureListboxItem(interp, listPtr, attrs, objc, objv) + Tcl_Interp *interp; /* Used for error reporting. */ + register Listbox *listPtr; /* Information about widget; may or may + * not already have values for some fields. */ + ItemAttr *attrs; /* Information about the item to configure */ + int objc; /* Number of valid entries in argv. */ + Tcl_Obj *CONST objv[]; /* Arguments. */ +{ + Tk_SavedOptions savedOptions; + + if (Tk_SetOptions(interp, (char *)attrs, + listPtr->itemAttrOptionTable, objc, objv, listPtr->tkwin, + &savedOptions, (int *)NULL) != TCL_OK) { + Tk_RestoreSavedOptions(&savedOptions); + return TCL_ERROR; + } + Tk_FreeSavedOptions(&savedOptions); ListboxWorldChanged((ClientData) listPtr); return TCL_OK; } @@ -1066,15 +1695,14 @@ ListboxWorldChanged(instanceData) GC gc; unsigned long mask; Listbox *listPtr; - + listPtr = (Listbox *) instanceData; gcValues.foreground = listPtr->fgColorPtr->pixel; gcValues.font = Tk_FontId(listPtr->tkfont); gcValues.graphics_exposures = False; mask = GCForeground | GCFont | GCGraphicsExposures; - gc = Tk_GetGCColor(listPtr->tkwin, mask, &gcValues, listPtr->fgColorPtr, - NULL); + gc = Tk_GetGC(listPtr->tkwin, mask, &gcValues); if (listPtr->textGC != None) { Tk_FreeGC(listPtr->display, listPtr->textGC); } @@ -1083,8 +1711,7 @@ ListboxWorldChanged(instanceData) gcValues.foreground = listPtr->selFgColorPtr->pixel; gcValues.font = Tk_FontId(listPtr->tkfont); mask = GCForeground | GCFont; - gc = Tk_GetGCColor(listPtr->tkwin, mask, &gcValues, listPtr->selFgColorPtr, - NULL); + gc = Tk_GetGC(listPtr->tkwin, mask, &gcValues); if (listPtr->selTextGC != None) { Tk_FreeGC(listPtr->display, listPtr->selTextGC); } @@ -1097,7 +1724,7 @@ ListboxWorldChanged(instanceData) ListboxComputeGeometry(listPtr, 1, 1, 1); listPtr->flags |= UPDATE_V_SCROLLBAR|UPDATE_H_SCROLLBAR; - ListboxRedrawRange(listPtr, 0, listPtr->numElements-1); + EventuallyRedrawRange(listPtr, 0, listPtr->nElements-1); } /* @@ -1122,16 +1749,30 @@ DisplayListbox(clientData) { register Listbox *listPtr = (Listbox *) clientData; register Tk_Window tkwin = listPtr->tkwin; - register Element *elPtr; GC gc; int i, limit, x, y, width, prevSelected; Tk_FontMetrics fm; + Tcl_Obj *curElement; + Tcl_HashEntry *entry; + char *stringRep; + int stringLen; + ItemAttr *attrs; + Tk_3DBorder selectedBg; + XGCValues gcValues; + unsigned long mask; int left, right; /* Non-zero values here indicate * that the left or right edge of * the listbox is off-screen. */ Pixmap pixmap; listPtr->flags &= ~REDRAW_PENDING; + + if (listPtr->flags & MAXWIDTH_IS_STALE) { + ListboxComputeGeometry(listPtr, 0, 1, 0); + listPtr->flags &= ~MAXWIDTH_IS_STALE; + listPtr->flags |= UPDATE_H_SCROLLBAR; + } + if (listPtr->flags & UPDATE_V_SCROLLBAR) { ListboxUpdateVScrollbar(listPtr); } @@ -1156,15 +1797,10 @@ DisplayListbox(clientData) Tk_Fill3DRectangle(tkwin, pixmap, listPtr->normalBorder, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); - /* - * Iterate through all of the elements of the listbox, displaying each - * in turn. Selected elements use a different GC and have a raised - * background. - */ - + /* Display each item in the listbox */ limit = listPtr->topIndex + listPtr->fullLines + listPtr->partialLine - 1; - if (limit >= listPtr->numElements) { - limit = listPtr->numElements-1; + if (limit >= listPtr->nElements) { + limit = listPtr->nElements-1; } left = right = 0; if (listPtr->xOffset > 0) { @@ -1175,19 +1811,45 @@ DisplayListbox(clientData) right = listPtr->selBorderWidth+1; } prevSelected = 0; - for (elPtr = listPtr->firstPtr, i = 0; (elPtr != NULL) && (i <= limit); - prevSelected = elPtr->selected, elPtr = elPtr->nextPtr, i++) { - if (i < listPtr->topIndex) { - continue; - } + + for (i = listPtr->topIndex; i <= limit; i++) { x = listPtr->inset; y = ((i - listPtr->topIndex) * listPtr->lineHeight) + listPtr->inset; gc = listPtr->textGC; - if (elPtr->selected) { + /* + * Lookup this item in the item attributes table, to see if it has + * special foreground/background colors + */ + entry = Tcl_FindHashEntry(listPtr->itemAttrTable, (char *)i); + + /* If the item is selected, it is drawn differently */ + if (Tcl_FindHashEntry(listPtr->selection, (char *)i) != NULL) { gc = listPtr->selTextGC; width = Tk_Width(tkwin) - 2*listPtr->inset; - Tk_Fill3DRectangle(tkwin, pixmap, listPtr->selBorder, x, y, + selectedBg = listPtr->selBorder; + + /* If there is attribute information for this item, + * adjust the drawing accordingly */ + if (entry != NULL) { + attrs = (ItemAttr *)Tcl_GetHashValue(entry); + /* The default GC has the settings from the widget at large */ + gcValues.foreground = listPtr->selFgColorPtr->pixel; + gcValues.font = Tk_FontId(listPtr->tkfont); + gcValues.graphics_exposures = False; + mask = GCForeground | GCFont | GCGraphicsExposures; + + if (attrs->selBorder != NULL) { + selectedBg = attrs->selBorder; + } + + if (attrs->selFgColor != NULL) { + gcValues.foreground = attrs->selFgColor->pixel; + gc = Tk_GetGC(listPtr->tkwin, mask, &gcValues); + } + } + + Tk_Fill3DRectangle(tkwin, pixmap, selectedBg, x, y, width, listPtr->lineHeight, 0, TK_RELIEF_FLAT); /* @@ -1205,43 +1867,71 @@ DisplayListbox(clientData) * corners are off-screen. */ + /* Draw left bevel */ if (left == 0) { - Tk_3DVerticalBevel(tkwin, pixmap, listPtr->selBorder, + Tk_3DVerticalBevel(tkwin, pixmap, selectedBg, x, y, listPtr->selBorderWidth, listPtr->lineHeight, 1, TK_RELIEF_RAISED); } + /* Draw right bevel */ if (right == 0) { - Tk_3DVerticalBevel(tkwin, pixmap, listPtr->selBorder, + Tk_3DVerticalBevel(tkwin, pixmap, selectedBg, x + width - listPtr->selBorderWidth, y, listPtr->selBorderWidth, listPtr->lineHeight, 0, TK_RELIEF_RAISED); } + /* Draw top bevel */ if (!prevSelected) { - Tk_3DHorizontalBevel(tkwin, pixmap, listPtr->selBorder, + Tk_3DHorizontalBevel(tkwin, pixmap, selectedBg, x-left, y, width+left+right, listPtr->selBorderWidth, 1, 1, 1, TK_RELIEF_RAISED); } - if ((elPtr->nextPtr == NULL) || !elPtr->nextPtr->selected) { - Tk_3DHorizontalBevel(tkwin, pixmap, listPtr->selBorder, x-left, + /* Draw bottom bevel */ + if (i + 1 == listPtr->nElements || + Tcl_FindHashEntry(listPtr->selection, + (char *)(i + 1)) == NULL ) { + Tk_3DHorizontalBevel(tkwin, pixmap, selectedBg, x-left, y + listPtr->lineHeight - listPtr->selBorderWidth, width+left+right, listPtr->selBorderWidth, 0, 0, 0, TK_RELIEF_RAISED); } + prevSelected = 1; + } else { + /* If there is an item attributes record for this item, + * draw the background box and set the foreground color + * accordingly */ + if (entry != NULL) { + attrs = (ItemAttr *)Tcl_GetHashValue(entry); + gcValues.foreground = listPtr->fgColorPtr->pixel; + gcValues.font = Tk_FontId(listPtr->tkfont); + gcValues.graphics_exposures = False; + mask = GCForeground | GCFont | GCGraphicsExposures; + if (attrs->border != NULL) { + width = Tk_Width(tkwin) - 2*listPtr->inset; + Tk_Fill3DRectangle(tkwin, pixmap, attrs->border, x, y, + width, listPtr->lineHeight, 0, TK_RELIEF_FLAT); + } + if (attrs->fgColor != NULL) { + gcValues.foreground = attrs->fgColor->pixel; + gc = Tk_GetGC(listPtr->tkwin, mask, &gcValues); + } + } + prevSelected = 0; } + + /* Draw the actual text of this item */ Tk_GetFontMetrics(listPtr->tkfont, &fm); y += fm.ascent + listPtr->selBorderWidth; - x = listPtr->inset + listPtr->selBorderWidth - elPtr->lBearing - - listPtr->xOffset; + x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset; + Tcl_ListObjIndex(listPtr->interp, listPtr->listObj, i, &curElement); + stringRep = Tcl_GetStringFromObj(curElement, &stringLen); Tk_DrawChars(listPtr->display, pixmap, gc, listPtr->tkfont, - elPtr->text, elPtr->textLength, x, y); - - /* - * If this is the active element, underline it. - */ + stringRep, stringLen, x, y); + /* If this is the active element, underline it. */ if ((i == listPtr->active) && (listPtr->flags & GOT_FOCUS)) { Tk_UnderlineChars(listPtr->display, pixmap, gc, listPtr->tkfont, - elPtr->text, x, y, 0, elPtr->textLength); + stringRep, x, y, 0, stringLen); } } @@ -1256,14 +1946,17 @@ DisplayListbox(clientData) Tk_Height(tkwin) - 2*listPtr->highlightWidth, listPtr->borderWidth, listPtr->relief); if (listPtr->highlightWidth > 0) { - GC gc; + GC fgGC, bgGC; + bgGC = Tk_GCForColor(listPtr->highlightBgColorPtr, pixmap); if (listPtr->flags & GOT_FOCUS) { - gc = Tk_GCForColor(listPtr->highlightColorPtr, pixmap); + fgGC = Tk_GCForColor(listPtr->highlightColorPtr, pixmap); + TkpDrawHighlightBorder(tkwin, fgGC, bgGC, + listPtr->highlightWidth, pixmap); } else { - gc = Tk_GCForColor(listPtr->highlightBgColorPtr, pixmap); + TkpDrawHighlightBorder(tkwin, bgGC, bgGC, + listPtr->highlightWidth, pixmap); } - Tk_DrawFocusHighlight(tkwin, gc, listPtr->highlightWidth, pixmap); } XCopyArea(listPtr->display, pixmap, Tk_WindowId(tkwin), listPtr->textGC, 0, 0, (unsigned) Tk_Width(tkwin), @@ -1306,24 +1999,31 @@ ListboxComputeGeometry(listPtr, fontChanged, maxIsStale, updateGrid) * Tk_UnsetGrid to update gridding for * the window. */ { - register Element *elPtr; int width, height, pixelWidth, pixelHeight; Tk_FontMetrics fm; - + Tcl_Obj *element; + int textLength; + char *text; + int i, result; + if (fontChanged || maxIsStale) { listPtr->xScrollUnit = Tk_TextWidth(listPtr->tkfont, "0", 1); if (listPtr->xScrollUnit == 0) { listPtr->xScrollUnit = 1; } listPtr->maxWidth = 0; - for (elPtr = listPtr->firstPtr; elPtr != NULL; elPtr = elPtr->nextPtr) { - if (fontChanged) { - elPtr->pixelWidth = Tk_TextWidth(listPtr->tkfont, - elPtr->text, elPtr->textLength); - elPtr->lBearing = 0; + for (i = 0; i < listPtr->nElements; i++) { + /* Compute the pixel width of the current element */ + result = Tcl_ListObjIndex(listPtr->interp, listPtr->listObj, i, + &element); + if (result != TCL_OK) { + continue; } - if (elPtr->pixelWidth > listPtr->maxWidth) { - listPtr->maxWidth = elPtr->pixelWidth; + text = Tcl_GetStringFromObj(element, &textLength); + Tk_GetFontMetrics(listPtr->tkfont, &fm); + pixelWidth = Tk_TextWidth(listPtr->tkfont, text, textLength); + if (pixelWidth > listPtr->maxWidth) { + listPtr->maxWidth = pixelWidth; } } } @@ -1342,7 +2042,7 @@ ListboxComputeGeometry(listPtr, fontChanged, maxIsStale, updateGrid) + 2*listPtr->selBorderWidth; height = listPtr->height; if (listPtr->height <= 0) { - height = listPtr->numElements; + height = listPtr->nElements; if (height < 1) { height = 1; } @@ -1363,100 +2063,104 @@ ListboxComputeGeometry(listPtr, fontChanged, maxIsStale, updateGrid) /* *---------------------------------------------------------------------- * - * InsertEls -- + * ListboxInsertSubCmd -- * - * Add new elements to a listbox widget. + * This procedure is invoked to handle the listbox "insert" + * subcommand. * * Results: - * None. + * Standard Tcl result. * * Side effects: - * New information gets added to listPtr; it will be redisplayed - * soon, but not immediately. + * New elements are added to the listbox pointed to by listPtr; + * a refresh callback is registered for the listbox. * *---------------------------------------------------------------------- */ -static void -InsertEls(listPtr, index, argc, argv) +static int +ListboxInsertSubCmd(listPtr, index, objc, objv) register Listbox *listPtr; /* Listbox that is to get the new * elements. */ int index; /* Add the new elements before this * element. */ - int argc; /* Number of new elements to add. */ - char **argv; /* New elements (one per entry). */ + int objc; /* Number of new elements to add. */ + Tcl_Obj *CONST objv[]; /* New elements (one per entry). */ { - register Element *prevPtr, *newPtr; - int length, i, oldMaxWidth; - - /* - * Find the element before which the new ones will be inserted. - */ - - if (index <= 0) { - index = 0; - } - if (index > listPtr->numElements) { - index = listPtr->numElements; + int i, oldMaxWidth; + Tcl_Obj *newListObj; + int pixelWidth; + int result; + char *stringRep; + int length; + + oldMaxWidth = listPtr->maxWidth; + for (i = 0; i < objc; i++) { + /* + * Check if any of the new elements are wider than the current widest; + * if so, update our notion of "widest." + */ + stringRep = Tcl_GetStringFromObj(objv[i], &length); + pixelWidth = Tk_TextWidth(listPtr->tkfont, stringRep, length); + if (pixelWidth > listPtr->maxWidth) { + listPtr->maxWidth = pixelWidth; + } } - if (index == 0) { - prevPtr = NULL; - } else if (index == listPtr->numElements) { - prevPtr = listPtr->lastPtr; + + /* Adjust selection and attribute information for every index after + * the first index */ + MigrateHashEntries(listPtr->selection, index, listPtr->nElements-1, objc); + MigrateHashEntries(listPtr->itemAttrTable, index, listPtr->nElements-1, + objc); + + /* If the object is shared, duplicate it before writing to it */ + if (Tcl_IsShared(listPtr->listObj)) { + newListObj = Tcl_DuplicateObj(listPtr->listObj); } else { - for (prevPtr = listPtr->firstPtr, i = index - 1; i > 0; i--) { - prevPtr = prevPtr->nextPtr; - } + newListObj = listPtr->listObj; + } + result = + Tcl_ListObjReplace(listPtr->interp, newListObj, index, 0, objc, objv); + if (result != TCL_OK) { + return result; } - /* - * For each new element, create a record, initialize it, and link - * it into the list of elements. - */ + Tcl_IncrRefCount(newListObj); + /* Clean up the old reference */ + Tcl_DecrRefCount(listPtr->listObj); - oldMaxWidth = listPtr->maxWidth; - for (i = argc ; i > 0; i--, argv++, prevPtr = newPtr) { - length = strlen(*argv); - newPtr = (Element *) ckalloc(ElementSize(length)); - newPtr->textLength = length; - strcpy(newPtr->text, *argv); - newPtr->pixelWidth = Tk_TextWidth(listPtr->tkfont, newPtr->text, - newPtr->textLength); - newPtr->lBearing = 0; - if (newPtr->pixelWidth > listPtr->maxWidth) { - listPtr->maxWidth = newPtr->pixelWidth; - } - newPtr->selected = 0; - if (prevPtr == NULL) { - newPtr->nextPtr = listPtr->firstPtr; - listPtr->firstPtr = newPtr; - } else { - newPtr->nextPtr = prevPtr->nextPtr; - prevPtr->nextPtr = newPtr; + /* Set the internal pointer to the new obj */ + listPtr->listObj = newListObj; + + /* If there is a listvar, make sure it points at the new object */ + if (listPtr->listVarName != NULL) { + if (Tcl_SetVar2Ex(listPtr->interp, listPtr->listVarName, + (char *)NULL, newListObj, TCL_GLOBAL_ONLY) == NULL) { + Tcl_DecrRefCount(newListObj); + return TCL_ERROR; } } - if ((prevPtr != NULL) && (prevPtr->nextPtr == NULL)) { - listPtr->lastPtr = prevPtr; - } - listPtr->numElements += argc; + /* Get the new list length */ + Tcl_ListObjLength(listPtr->interp, listPtr->listObj, &listPtr->nElements); + /* - * Update the selection and other indexes to account for the - * renumbering that has just occurred. Then arrange for the new + * Update the "special" indices (anchor, topIndex, active) to account + * for the renumbering that just occurred. Then arrange for the new * information to be displayed. */ if (index <= listPtr->selectAnchor) { - listPtr->selectAnchor += argc; + listPtr->selectAnchor += objc; } if (index < listPtr->topIndex) { - listPtr->topIndex += argc; + listPtr->topIndex += objc; } if (index <= listPtr->active) { - listPtr->active += argc; - if ((listPtr->active >= listPtr->numElements) - && (listPtr->numElements > 0)) { - listPtr->active = listPtr->numElements-1; + listPtr->active += objc; + if ((listPtr->active >= listPtr->nElements) && + (listPtr->nElements > 0)) { + listPtr->active = listPtr->nElements-1; } } listPtr->flags |= UPDATE_V_SCROLLBAR; @@ -1464,35 +2168,42 @@ InsertEls(listPtr, index, argc, argv) listPtr->flags |= UPDATE_H_SCROLLBAR; } ListboxComputeGeometry(listPtr, 0, 0, 0); - ListboxRedrawRange(listPtr, index, listPtr->numElements-1); + EventuallyRedrawRange(listPtr, index, listPtr->nElements-1); + return TCL_OK; } /* *---------------------------------------------------------------------- * - * DeleteEls -- + * ListboxDeleteSubCmd -- * - * Remove one or more elements from a listbox widget. + * Process a listbox "delete" subcommand by removing one or more + * elements from a listbox widget. * * Results: - * None. + * Standard Tcl result. * * Side effects: - * Memory gets freed, the listbox gets modified and (eventually) - * redisplayed. + * The listbox will be modified and (eventually) redisplayed. * *---------------------------------------------------------------------- */ -static void -DeleteEls(listPtr, first, last) +static int +ListboxDeleteSubCmd(listPtr, first, last) register Listbox *listPtr; /* Listbox widget to modify. */ int first; /* Index of first element to delete. */ int last; /* Index of last element to delete. */ { - register Element *prevPtr, *elPtr; int count, i, widthChanged; - + Tcl_Obj *newListObj; + Tcl_Obj *element; + int length; + char *stringRep; + int result; + int pixelWidth; + Tcl_HashEntry *entry; + /* * Adjust the range to fit within the existing elements of the * listbox, and make sure there's something to delete. @@ -1501,54 +2212,85 @@ DeleteEls(listPtr, first, last) if (first < 0) { first = 0; } - if (last >= listPtr->numElements) { - last = listPtr->numElements-1; + if (last >= listPtr->nElements) { + last = listPtr->nElements-1; } count = last + 1 - first; if (count <= 0) { - return; + return TCL_OK; } /* - * Find the element just before the ones to delete. + * Foreach deleted index we must: + * a) remove selection information + * b) check the width of the element; if it is equal to the max, set + * widthChanged to 1, because it may be the only element with that + * width */ + widthChanged = 0; + for (i = first; i <= last; i++) { + /* Remove selection information */ + entry = Tcl_FindHashEntry(listPtr->selection, (char *)i); + if (entry != NULL) { + listPtr->numSelected--; + Tcl_DeleteHashEntry(entry); + } + + entry = Tcl_FindHashEntry(listPtr->itemAttrTable, (char *)i); + if (entry != NULL) { + Tcl_DeleteHashEntry(entry); + } + + /* Check width of the element. We only have to check if widthChanged + * has not already been set to 1, because we only need one maxWidth + * element to disappear for us to have to recompute the width + */ + if (widthChanged == 0) { + Tcl_ListObjIndex(listPtr->interp, listPtr->listObj, i, &element); + stringRep = Tcl_GetStringFromObj(element, &length); + pixelWidth = Tk_TextWidth(listPtr->tkfont, stringRep, length); + if (pixelWidth == listPtr->maxWidth) { + widthChanged = 1; + } + } + } + + /* Adjust selection and attribute info for indices after lastIndex */ + MigrateHashEntries(listPtr->selection, last+1, + listPtr->nElements-1, count*-1); + MigrateHashEntries(listPtr->itemAttrTable, last+1, + listPtr->nElements-1, count*-1); - if (first == 0) { - prevPtr = NULL; + /* Delete the requested elements */ + if (Tcl_IsShared(listPtr->listObj)) { + newListObj = Tcl_DuplicateObj(listPtr->listObj); } else { - for (i = first-1, prevPtr = listPtr->firstPtr; i > 0; i--) { - prevPtr = prevPtr->nextPtr; - } + newListObj = listPtr->listObj; + } + result = Tcl_ListObjReplace(listPtr->interp, + newListObj, first, count, 0, NULL); + if (result != TCL_OK) { + return result; } - /* - * Delete the requested number of elements. - */ + Tcl_IncrRefCount(newListObj); + /* Clean up the old reference */ + Tcl_DecrRefCount(listPtr->listObj); - widthChanged = 0; - for (i = count; i > 0; i--) { - if (prevPtr == NULL) { - elPtr = listPtr->firstPtr; - listPtr->firstPtr = elPtr->nextPtr; - if (listPtr->firstPtr == NULL) { - listPtr->lastPtr = NULL; - } - } else { - elPtr = prevPtr->nextPtr; - prevPtr->nextPtr = elPtr->nextPtr; - if (prevPtr->nextPtr == NULL) { - listPtr->lastPtr = prevPtr; - } - } - if (elPtr->pixelWidth == listPtr->maxWidth) { - widthChanged = 1; - } - if (elPtr->selected) { - listPtr->numSelected -= 1; + /* Set the internal pointer to the new obj */ + listPtr->listObj = newListObj; + + /* Get the new list length */ + Tcl_ListObjLength(listPtr->interp, listPtr->listObj, &listPtr->nElements); + + /* If there is a listvar, make sure it points at the new object */ + if (listPtr->listVarName != NULL) { + if (Tcl_SetVar2Ex(listPtr->interp, listPtr->listVarName, + (char *)NULL, newListObj, TCL_GLOBAL_ONLY) == NULL) { + Tcl_DecrRefCount(newListObj); + return TCL_ERROR; } - ckfree((char *) elPtr); } - listPtr->numElements -= count; /* * Update the selection and viewing information to reflect the change @@ -1568,8 +2310,8 @@ DeleteEls(listPtr, first, last) listPtr->topIndex = first; } } - if (listPtr->topIndex > (listPtr->numElements - listPtr->fullLines)) { - listPtr->topIndex = listPtr->numElements - listPtr->fullLines; + if (listPtr->topIndex > (listPtr->nElements - listPtr->fullLines)) { + listPtr->topIndex = listPtr->nElements - listPtr->fullLines; if (listPtr->topIndex < 0) { listPtr->topIndex = 0; } @@ -1578,9 +2320,9 @@ DeleteEls(listPtr, first, last) listPtr->active -= count; } else if (listPtr->active >= first) { listPtr->active = first; - if ((listPtr->active >= listPtr->numElements) - && (listPtr->numElements > 0)) { - listPtr->active = listPtr->numElements-1; + if ((listPtr->active >= listPtr->nElements) && + (listPtr->nElements > 0)) { + listPtr->active = listPtr->nElements-1; } } listPtr->flags |= UPDATE_V_SCROLLBAR; @@ -1588,7 +2330,8 @@ DeleteEls(listPtr, first, last) if (widthChanged) { listPtr->flags |= UPDATE_H_SCROLLBAR; } - ListboxRedrawRange(listPtr, first, listPtr->numElements-1); + EventuallyRedrawRange(listPtr, first, listPtr->nElements-1); + return TCL_OK; } /* @@ -1615,24 +2358,14 @@ ListboxEventProc(clientData, eventPtr) XEvent *eventPtr; /* Information about event. */ { Listbox *listPtr = (Listbox *) clientData; - + if (eventPtr->type == Expose) { - ListboxRedrawRange(listPtr, + EventuallyRedrawRange(listPtr, NearestListboxElement(listPtr, eventPtr->xexpose.y), NearestListboxElement(listPtr, eventPtr->xexpose.y + eventPtr->xexpose.height)); } else if (eventPtr->type == DestroyNotify) { - if (listPtr->tkwin != NULL) { - if (listPtr->setGrid) { - Tk_UnsetGrid(listPtr->tkwin); - } - listPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(listPtr->interp, listPtr->widgetCmd); - } - if (listPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayListbox, (ClientData) listPtr); - } - Tcl_EventuallyFree((ClientData) listPtr, DestroyListbox); + DestroyListbox((char *) clientData); } else if (eventPtr->type == ConfigureNotify) { int vertSpace; @@ -1654,16 +2387,16 @@ ListboxEventProc(clientData, eventPtr) * everything for safety. */ - ListboxRedrawRange(listPtr, 0, listPtr->numElements-1); + EventuallyRedrawRange(listPtr, 0, listPtr->nElements-1); } else if (eventPtr->type == FocusIn) { if (eventPtr->xfocus.detail != NotifyInferior) { listPtr->flags |= GOT_FOCUS; - ListboxRedrawRange(listPtr, 0, listPtr->numElements-1); + EventuallyRedrawRange(listPtr, 0, listPtr->nElements-1); } } else if (eventPtr->type == FocusOut) { if (eventPtr->xfocus.detail != NotifyInferior) { listPtr->flags &= ~GOT_FOCUS; - ListboxRedrawRange(listPtr, 0, listPtr->numElements-1); + EventuallyRedrawRange(listPtr, 0, listPtr->nElements-1); } } } @@ -1691,7 +2424,6 @@ ListboxCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Listbox *listPtr = (Listbox *) clientData; - Tk_Window tkwin = listPtr->tkwin; /* * This procedure could be invoked either because the window was @@ -1700,12 +2432,8 @@ ListboxCmdDeletedProc(clientData) * destroys the widget. */ - if (tkwin != NULL) { - if (listPtr->setGrid) { - Tk_UnsetGrid(listPtr->tkwin); - } - listPtr->tkwin = NULL; - Tk_DestroyWindow(tkwin); + if (!(listPtr->flags & LISTBOX_DELETED)) { + Tk_DestroyWindow(listPtr->tkwin); } } @@ -1720,7 +2448,7 @@ ListboxCmdDeletedProc(clientData) * Results: * A standard Tcl result. If all went well, then *indexPtr is * filled in with the index (into listPtr) corresponding to - * string. Otherwise an error message is left in interp->result. + * string. Otherwise an error message is left in the interp's result. * * Side effects: * None. @@ -1729,61 +2457,86 @@ ListboxCmdDeletedProc(clientData) */ static int -GetListboxIndex(interp, listPtr, string, endIsSize, indexPtr) +GetListboxIndex(interp, listPtr, indexObj, endIsSize, indexPtr) Tcl_Interp *interp; /* For error messages. */ Listbox *listPtr; /* Listbox for which the index is being * specified. */ - char *string; /* Specifies an element in the listbox. */ + Tcl_Obj *indexObj; /* Specifies an element in the listbox. */ int endIsSize; /* If 1, "end" refers to the number of * entries in the listbox. If 0, "end" * refers to 1 less than the number of * entries. */ int *indexPtr; /* Where to store converted index. */ { - int c; - size_t length; - - length = strlen(string); - c = string[0]; - if ((c == 'a') && (strncmp(string, "active", length) == 0) - && (length >= 2)) { - *indexPtr = listPtr->active; - } else if ((c == 'a') && (strncmp(string, "anchor", length) == 0) - && (length >= 2)) { - *indexPtr = listPtr->selectAnchor; - } else if ((c == 'e') && (strncmp(string, "end", length) == 0)) { - if (endIsSize) { - *indexPtr = listPtr->numElements; - } else { - *indexPtr = listPtr->numElements - 1; - } - } else if (c == '@') { - int y; - char *p, *end; + int result; + int index; + char *stringRep; + + /* First see if the index is one of the named indices */ + result = Tcl_GetIndexFromObj(NULL, indexObj, indexNames, "", 0, &index); + if (result == TCL_OK) { + switch (index) { + case INDEX_ACTIVE: { + /* "active" index */ + *indexPtr = listPtr->active; + break; + } - p = string+1; - strtol(p, &end, 0); - if ((end == p) || (*end != ',')) { - goto badIndex; + case INDEX_ANCHOR: { + /* "anchor" index */ + *indexPtr = listPtr->selectAnchor; + break; + } + + case INDEX_END: { + /* "end" index */ + if (endIsSize) { + *indexPtr = listPtr->nElements; + } else { + *indexPtr = listPtr->nElements - 1; + } + break; + } } - p = end+1; - y = strtol(p, &end, 0); - if ((end == p) || (*end != 0)) { - goto badIndex; + return TCL_OK; + } + + /* The index didn't match any of the named indices; maybe it's an @x,y */ + stringRep = Tcl_GetString(indexObj); + if (stringRep[0] == '@') { + /* @x,y index */ + int y; + char *start, *end; + start = stringRep + 1; + strtol(start, &end, 0); + if ((start == end) || (*end != ',')) { + Tcl_AppendResult(interp, "bad listbox index \"", stringRep, + "\": must be active, anchor, end, @x,y, or a number", + (char *)NULL); + return TCL_ERROR; + } + start = end+1; + y = strtol(start, &end, 0); + if ((start == end) || (*end != '\0')) { + Tcl_AppendResult(interp, "bad listbox index \"", stringRep, + "\": must be active, anchor, end, @x,y, or a number", + (char *)NULL); + return TCL_ERROR; } *indexPtr = NearestListboxElement(listPtr, y); - } else { - if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) { - Tcl_ResetResult(interp); - goto badIndex; - } + return TCL_OK; + } + + /* Maybe the index is just an integer */ + if (Tcl_GetIntFromObj(interp, indexObj, indexPtr) == TCL_OK) { + return TCL_OK; } - return TCL_OK; - badIndex: - Tcl_AppendResult(interp, "bad listbox index \"", string, - "\": must be active, anchor, end, @x,y, or a number", - (char *) NULL); + /* Everything failed, nothing matched. Throw up an error message */ + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "bad listbox index \"", + Tcl_GetString(indexObj), "\": must be active, anchor, ", + "end, @x,y, or a number", (char *) NULL); return TCL_ERROR; } @@ -1813,18 +2566,15 @@ ChangeListboxView(listPtr, index) * that should now appear at the * top of the listbox. */ { - if (index >= (listPtr->numElements - listPtr->fullLines)) { - index = listPtr->numElements - listPtr->fullLines; + if (index >= (listPtr->nElements - listPtr->fullLines)) { + index = listPtr->nElements - listPtr->fullLines; } if (index < 0) { index = 0; } if (listPtr->topIndex != index) { listPtr->topIndex = index; - if (!(listPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayListbox, (ClientData) listPtr); - listPtr->flags |= REDRAW_PENDING; - } + EventuallyRedrawRange(listPtr, 0, listPtr->nElements-1); listPtr->flags |= UPDATE_V_SCROLLBAR; } } @@ -1853,7 +2603,7 @@ ChangeListboxOffset(listPtr, offset) * listbox. */ { int maxOffset; - + /* * Make sure that the new offset is within the allowable range, and * round it off to an even multiple of xScrollUnit. @@ -1872,7 +2622,7 @@ ChangeListboxOffset(listPtr, offset) if (offset != listPtr->xOffset) { listPtr->xOffset = offset; listPtr->flags |= UPDATE_H_SCROLLBAR; - ListboxRedrawRange(listPtr, 0, listPtr->numElements); + EventuallyRedrawRange(listPtr, 0, listPtr->nElements-1); } } @@ -1902,8 +2652,8 @@ ListboxScanTo(listPtr, x, y) * operation. */ { int newTopIndex, newOffset, maxIndex, maxOffset; - - maxIndex = listPtr->numElements - listPtr->fullLines; + + maxIndex = listPtr->nElements - listPtr->fullLines; maxOffset = listPtr->maxWidth + (listPtr->xScrollUnit - 1) - (Tk_Width(listPtr->tkwin) - 2*listPtr->inset - 2*listPtr->selBorderWidth - listPtr->xScrollUnit); @@ -1981,8 +2731,8 @@ NearestListboxElement(listPtr, y) index = 0; } index += listPtr->topIndex; - if (index >= listPtr->numElements) { - index = listPtr->numElements-1; + if (index >= listPtr->nElements) { + index = listPtr->nElements-1; } return index; } @@ -1995,7 +2745,7 @@ NearestListboxElement(listPtr, y) * Select or deselect one or more elements in a listbox.. * * Results: - * None. + * Standard Tcl result. * * Side effects: * All of the elements in the range between first and last are @@ -2007,7 +2757,7 @@ NearestListboxElement(listPtr, y) *---------------------------------------------------------------------- */ -static void +static int ListboxSelect(listPtr, first, last, select) register Listbox *listPtr; /* Information about widget. */ int first; /* Index of first element to @@ -2018,47 +2768,64 @@ ListboxSelect(listPtr, first, last, select) * deselect them. */ { int i, firstRedisplay, increment, oldCount; - Element *elPtr; - + Tcl_HashEntry *entry; + int new; + if (last < first) { i = first; first = last; last = i; } - if ((last < 0) || (first >= listPtr->numElements)) { - return; + if ((last < 0) || (first >= listPtr->nElements)) { + return TCL_OK; } if (first < 0) { first = 0; } - if (last >= listPtr->numElements) { - last = listPtr->numElements - 1; + if (last >= listPtr->nElements) { + last = listPtr->nElements - 1; } oldCount = listPtr->numSelected; firstRedisplay = -1; increment = select ? 1 : -1; - for (i = 0, elPtr = listPtr->firstPtr; i < first; - i++, elPtr = elPtr->nextPtr) { - /* Empty loop body. */ - } - for ( ; i <= last; i++, elPtr = elPtr->nextPtr) { - if (elPtr->selected == select) { - continue; - } - listPtr->numSelected += increment; - elPtr->selected = select; - if (firstRedisplay < 0) { - firstRedisplay = i; + + /* + * For each index in the range, find it in our selection hash table. + * If it's not there but should be, add it. If it's there but shouldn't + * be, remove it. + */ + for (i = first; i <= last; i++) { + entry = Tcl_FindHashEntry(listPtr->selection, (char *)i); + if (entry != NULL) { + if (!select) { + Tcl_DeleteHashEntry(entry); + listPtr->numSelected--; + if (firstRedisplay < 0) { + firstRedisplay = i; + } + } + } else { + if (select) { + entry = Tcl_CreateHashEntry(listPtr->selection, + (char *)i, &new); + Tcl_SetHashValue(entry, (ClientData) NULL); + listPtr->numSelected++; + if (firstRedisplay < 0) { + firstRedisplay = i; + } + } } } + if (firstRedisplay >= 0) { - ListboxRedrawRange(listPtr, first, last); + EventuallyRedrawRange(listPtr, first, last); } if ((oldCount == 0) && (listPtr->numSelected > 0) && (listPtr->exportSelection)) { Tk_OwnSelection(listPtr->tkwin, XA_PRIMARY, ListboxLostSelection, (ClientData) listPtr); } + return TCL_OK; } /* @@ -2096,10 +2863,14 @@ ListboxFetchSelection(clientData, offset, buffer, maxBytes) * NULL character. */ { register Listbox *listPtr = (Listbox *) clientData; - register Element *elPtr; Tcl_DString selection; int length, count, needNewline; - + Tcl_Obj *curElement; + char *stringRep; + int stringLen; + Tcl_HashEntry *entry; + int i; + if (!listPtr->exportSelection) { return -1; } @@ -2110,12 +2881,16 @@ ListboxFetchSelection(clientData, offset, buffer, maxBytes) needNewline = 0; Tcl_DStringInit(&selection); - for (elPtr = listPtr->firstPtr; elPtr != NULL; elPtr = elPtr->nextPtr) { - if (elPtr->selected) { + for (i = 0; i < listPtr->nElements; i++) { + entry = Tcl_FindHashEntry(listPtr->selection, (char *)i); + if (entry != NULL) { if (needNewline) { Tcl_DStringAppend(&selection, "\n", 1); } - Tcl_DStringAppend(&selection, elPtr->text, elPtr->textLength); + Tcl_ListObjIndex(listPtr->interp, listPtr->listObj, i, + &curElement); + stringRep = Tcl_GetStringFromObj(curElement, &stringLen); + Tcl_DStringAppend(&selection, stringRep, stringLen); needNewline = 1; } } @@ -2168,16 +2943,16 @@ ListboxLostSelection(clientData) ClientData clientData; /* Information about listbox widget. */ { register Listbox *listPtr = (Listbox *) clientData; - - if ((listPtr->exportSelection) && (listPtr->numElements > 0)) { - ListboxSelect(listPtr, 0, listPtr->numElements-1, 0); + + if ((listPtr->exportSelection) && (listPtr->nElements > 0)) { + ListboxSelect(listPtr, 0, listPtr->nElements-1, 0); } } /* *---------------------------------------------------------------------- * - * ListboxRedrawRange -- + * EventuallyRedrawRange -- * * Ensure that a given range of elements is eventually redrawn on * the display (if those elements in fact appear on the display). @@ -2191,9 +2966,8 @@ ListboxLostSelection(clientData) *---------------------------------------------------------------------- */ - /* ARGSUSED */ static void -ListboxRedrawRange(listPtr, first, last) +EventuallyRedrawRange(listPtr, first, last) register Listbox *listPtr; /* Information about widget. */ int first; /* Index of first element in list * that needs to be redrawn. */ @@ -2202,12 +2976,15 @@ ListboxRedrawRange(listPtr, first, last) * be less than first; * these just bracket a range. */ { - if ((listPtr->tkwin == NULL) || !Tk_IsMapped(listPtr->tkwin) - || (listPtr->flags & REDRAW_PENDING)) { + /* We don't have to register a redraw callback if one is already pending, + * or if the window doesn't exist, or if the window isn't mapped */ + if ((listPtr->flags & REDRAW_PENDING) + || (listPtr->tkwin == NULL) + || !Tk_IsMapped(listPtr->tkwin)) { return; } - Tcl_DoWhenIdle(DisplayListbox, (ClientData) listPtr); listPtr->flags |= REDRAW_PENDING; + Tcl_DoWhenIdle(DisplayListbox, (ClientData) listPtr); } /* @@ -2234,21 +3011,21 @@ static void ListboxUpdateVScrollbar(listPtr) register Listbox *listPtr; /* Information about widget. */ { - char string[100]; + char string[TCL_DOUBLE_SPACE * 2]; double first, last; int result; Tcl_Interp *interp; - + if (listPtr->yScrollCmd == NULL) { return; } - if (listPtr->numElements == 0) { + if (listPtr->nElements == 0) { first = 0.0; last = 1.0; } else { - first = listPtr->topIndex/((double) listPtr->numElements); + first = listPtr->topIndex/((double) listPtr->nElements); last = (listPtr->topIndex+listPtr->fullLines) - /((double) listPtr->numElements); + /((double) listPtr->nElements); if (last > 1.0) { last = 1.0; } @@ -2296,7 +3073,7 @@ static void ListboxUpdateHScrollbar(listPtr) register Listbox *listPtr; /* Information about widget. */ { - char string[60]; + char string[TCL_DOUBLE_SPACE * 2]; int result, windowWidth; double first, last; Tcl_Interp *interp; @@ -2335,3 +3112,174 @@ ListboxUpdateHScrollbar(listPtr) } Tcl_Release((ClientData) interp); } + +/* + *---------------------------------------------------------------------- + * + * ListboxListVarProc -- + * + * Called whenever the trace on the listbox list var fires. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static char * +ListboxListVarProc(clientData, interp, name1, name2, flags) + ClientData clientData; /* Information about button. */ + Tcl_Interp *interp; /* Interpreter containing variable. */ + char *name1; /* Not used. */ + char *name2; /* Not used. */ + int flags; /* Information about what happened. */ +{ + Listbox *listPtr = (Listbox *)clientData; + Tcl_Obj *oldListObj, *varListObj; + int oldLength; + int i; + Tcl_HashEntry *entry; + + /* Bwah hahahaha -- puny mortal, you can't unset a -listvar'd variable! */ + if (flags & TCL_TRACE_UNSETS) { + if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { + Tcl_SetVar2Ex(interp, listPtr->listVarName, + (char *)NULL, listPtr->listObj, TCL_GLOBAL_ONLY); + Tcl_TraceVar(interp, listPtr->listVarName, + TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + ListboxListVarProc, clientData); + return (char *)NULL; + } + } else { + oldListObj = listPtr->listObj; + varListObj = Tcl_GetVar2Ex(listPtr->interp, listPtr->listVarName, + (char *)NULL, TCL_GLOBAL_ONLY); + /* + * Make sure the new value is a good list; if it's not, disallow + * the change -- the fact that it is a listvar means that it must + * always be a valid list -- and return an error message. + */ + if (Tcl_ListObjLength(listPtr->interp, varListObj, &i) != TCL_OK) { + Tcl_SetVar2Ex(interp, listPtr->listVarName, (char *)NULL, + oldListObj, TCL_GLOBAL_ONLY); + return("invalid listvar value"); + } + + listPtr->listObj = varListObj; + /* Incr the obj ref count so it doesn't vanish if the var is unset */ + Tcl_IncrRefCount(listPtr->listObj); + /* Clean up the ref to our old list obj */ + Tcl_DecrRefCount(oldListObj); + } + + /* + * If the list length has decreased, then we should clean up selection and + * attributes information for elements past the end of the new list + */ + oldLength = listPtr->nElements; + Tcl_ListObjLength(listPtr->interp, listPtr->listObj, &listPtr->nElements); + if (listPtr->nElements < oldLength) { + for (i = listPtr->nElements; i < oldLength; i++) { + /* Clean up selection */ + entry = Tcl_FindHashEntry(listPtr->selection, (char *)i); + if (entry != NULL) { + listPtr->numSelected--; + Tcl_DeleteHashEntry(entry); + } + + /* Clean up attributes */ + entry = Tcl_FindHashEntry(listPtr->itemAttrTable, (char *)i); + if (entry != NULL) { + Tcl_DeleteHashEntry(entry); + } + } + } + + if (oldLength != listPtr->nElements) { + listPtr->flags |= UPDATE_V_SCROLLBAR; + if (listPtr->topIndex > (listPtr->nElements - listPtr->fullLines)) { + listPtr->topIndex = listPtr->nElements - listPtr->fullLines; + if (listPtr->topIndex < 0) { + listPtr->topIndex = 0; + } + } + } + + /* + * The computed maxWidth may have changed as a result of this operation. + * However, we don't want to recompute it every time this trace fires + * (imagine the user doing 1000 lappends to the listvar). Therefore, set + * the MAXWIDTH_IS_STALE flag, which will cause the width to be recomputed + * next time the list is redrawn. + */ + listPtr->flags |= MAXWIDTH_IS_STALE; + + EventuallyRedrawRange(listPtr, 0, listPtr->nElements-1); + return (char*)NULL; +} + +/* + *---------------------------------------------------------------------- + * + * MigrateHashEntries -- + * + * Given a hash table with entries keyed by a single integer value, + * move all entries in a given range by a fixed amount, so that + * if in the original table there was an entry with key n and + * the offset was i, in the new table that entry would have key n + i. + * + * Results: + * None. + * + * Side effects: + * Rekeys some hash table entries. + * + *---------------------------------------------------------------------- + */ + +static void +MigrateHashEntries(table, first, last, offset) + Tcl_HashTable *table; + int first; + int last; + int offset; +{ + int i, new; + Tcl_HashEntry *entry; + ClientData clientData; + + if (offset == 0) { + return; + } + /* It's more efficient to do one if/else and nest the for loops inside, + * although we could avoid some code duplication if we nested the if/else + * inside the for loops */ + if (offset > 0) { + for (i = last; i >= first; i--) { + entry = Tcl_FindHashEntry(table, (char *)i); + if (entry != NULL) { + clientData = Tcl_GetHashValue(entry); + Tcl_DeleteHashEntry(entry); + entry = Tcl_CreateHashEntry(table, (char *)(i + offset), &new); + Tcl_SetHashValue(entry, clientData); + } + } + } else { + for (i = first; i <= last; i++) { + entry = Tcl_FindHashEntry(table, (char *)i); + if (entry != NULL) { + clientData = Tcl_GetHashValue(entry); + Tcl_DeleteHashEntry(entry); + entry = Tcl_CreateHashEntry(table, (char *)(i + offset), &new); + Tcl_SetHashValue(entry, clientData); + } + } + } + return; +} + + + diff --git a/tk/generic/tkMacWinMenu.c b/tk/generic/tkMacWinMenu.c index ed9a3b1f42d..066b96eedce 100644 --- a/tk/generic/tkMacWinMenu.c +++ b/tk/generic/tkMacWinMenu.c @@ -14,7 +14,11 @@ #include "tkMenu.h" -static int postCommandGeneration; +typedef struct ThreadSpecificData { + int postCommandGeneration; +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; + static int PreprocessMenu _ANSI_ARGS_((TkMenu *menuPtr)); @@ -43,6 +47,8 @@ PreprocessMenu(menuPtr) { int index, result, finished; TkMenu *cascadeMenuPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); Tcl_Preserve((ClientData) menuPtr); @@ -67,16 +73,16 @@ PreprocessMenu(menuPtr) finished = 1; for (index = 0; index < menuPtr->numEntries; index++) { if ((menuPtr->entries[index]->type == CASCADE_ENTRY) - && (menuPtr->entries[index]->name != NULL)) { + && (menuPtr->entries[index]->namePtr != NULL)) { if ((menuPtr->entries[index]->childMenuRefPtr != NULL) && (menuPtr->entries[index]->childMenuRefPtr->menuPtr != NULL)) { cascadeMenuPtr = menuPtr->entries[index]->childMenuRefPtr->menuPtr; if (cascadeMenuPtr->postCommandGeneration != - postCommandGeneration) { + tsdPtr->postCommandGeneration) { cascadeMenuPtr->postCommandGeneration = - postCommandGeneration; + tsdPtr->postCommandGeneration; result = PreprocessMenu(cascadeMenuPtr); if (result != TCL_OK) { goto done; @@ -128,7 +134,11 @@ int TkPreprocessMenu(menuPtr) TkMenu *menuPtr; { - postCommandGeneration++; - menuPtr->postCommandGeneration = postCommandGeneration; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + tsdPtr->postCommandGeneration++; + menuPtr->postCommandGeneration = tsdPtr->postCommandGeneration; return PreprocessMenu(menuPtr); } + diff --git a/tk/generic/tkMain.c b/tk/generic/tkMain.c index 02ef0afd422..9f31a9860a2 100644 --- a/tk/generic/tkMain.c +++ b/tk/generic/tkMain.c @@ -16,16 +16,37 @@ * RCS: @(#) $Id$ */ +#ifdef _WIN32 +# include <windows.h> +#endif #include <ctype.h> #include <stdio.h> #include <string.h> #include <tcl.h> +#include <tclInt.h> #include <tk.h> +#include "tkInt.h" #ifdef NO_STDLIB_H # include "../compat/stdlib.h" #else # include <stdlib.h> #endif +#ifdef __WIN32__ +#include "tkWinInt.h" +#endif + + +typedef struct ThreadSpecificData { + Tcl_Interp *interp; /* Interpreter for this thread. */ + Tcl_DString command; /* Used to assemble lines of terminal input + * into Tcl commands. */ + Tcl_DString line; /* Used to read the next line from the + * terminal input. */ + int tty; /* Non-zero means standard input is a + * terminal-like device. Zero means it's + * a file. */ +} ThreadSpecificData; +Tcl_ThreadDataKey dataKey; /* * Declarations for various library procedures and variables (don't want @@ -36,27 +57,14 @@ * some systems. */ -extern int isatty _ANSI_ARGS_((int fd)); #if !defined(__WIN32__) && !defined(_WIN32) +extern int isatty _ANSI_ARGS_((int fd)); extern char * strrchr _ANSI_ARGS_((CONST char *string, int c)); #endif extern void TkpDisplayWarning _ANSI_ARGS_((char *msg, char *title)); /* - * Global variables used by the main program: - */ - -static Tcl_Interp *interp; /* Interpreter for this application. */ -static Tcl_DString command; /* Used to assemble lines of terminal input - * into Tcl commands. */ -static Tcl_DString line; /* Used to read the next line from the - * terminal input. */ -static int tty; /* Non-zero means standard input is a - * terminal-like device. Zero means it's - * a file. */ - -/* * Forward declarations for procedures defined later in this file. */ @@ -67,7 +75,7 @@ static void StdinProc _ANSI_ARGS_((ClientData clientData, /* *---------------------------------------------------------------------- * - * Tk_Main -- + * Tk_MainEx -- * * Main program for Wish and most other Tk-based applications. * @@ -82,24 +90,46 @@ static void StdinProc _ANSI_ARGS_((ClientData clientData, * *---------------------------------------------------------------------- */ - void -Tk_Main(argc, argv, appInitProc) +Tk_MainEx(argc, argv, appInitProc, interp) int argc; /* Number of arguments. */ char **argv; /* Array of argument strings. */ Tcl_AppInitProc *appInitProc; /* Application-specific initialization * procedure to call after most * initialization but before starting * to execute commands. */ + Tcl_Interp *interp; { char *args, *fileName; - char buf[20]; + char buf[TCL_INTEGER_SPACE]; int code; size_t length; Tcl_Channel inChannel, outChannel; + Tcl_DString argString; + ThreadSpecificData *tsdPtr; +#ifdef __WIN32__ + HANDLE handle; +#endif + /* + * Ensure that we are getting the matching version of Tcl. This is + * really only an issue when Tk is loaded dynamically. + */ + + if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { + abort(); + } + + tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + Tcl_FindExecutable(argv[0]); - interp = Tcl_CreateInterp(); + tsdPtr->interp = interp; + +#if (defined(__WIN32__) || defined(MAC_TCL)) + Tk_InitConsoleChannels(interp); +#endif + #ifdef TCL_MEM_DEBUG Tcl_InitMemory(interp); #endif @@ -111,7 +141,8 @@ Tk_Main(argc, argv, appInitProc) * use it as the name of a script file to process. */ - fileName = NULL; + fileName = TclGetStartupScriptFileName(); + if (argc > 1) { length = strlen(argv[1]); if ((length >= 2) && (strncmp(argv[1], "-file", length) == 0)) { @@ -119,24 +150,33 @@ Tk_Main(argc, argv, appInitProc) argv++; } } - if ((argc > 1) && (argv[1][0] != '-')) { - fileName = argv[1]; - argc--; - argv++; + if (fileName == NULL) { + if ((argc > 1) && (argv[1][0] != '-')) { + fileName = argv[1]; + argc--; + argv++; + } } - + /* * Make command-line arguments available in the Tcl variables "argc" * and "argv". */ args = Tcl_Merge(argc-1, argv+1); - Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY); + Tcl_ExternalToUtfDString(NULL, args, -1, &argString); + Tcl_SetVar(interp, "argv", Tcl_DStringValue(&argString), TCL_GLOBAL_ONLY); + Tcl_DStringFree(&argString); ckfree(args); sprintf(buf, "%d", argc-1); + if (fileName == NULL) { + Tcl_ExternalToUtfDString(NULL, argv[0], -1, &argString); + } else { + fileName = Tcl_ExternalToUtfDString(NULL, fileName, -1, &argString); + } + Tcl_SetVar(interp, "argc", buf, TCL_GLOBAL_ONLY); - Tcl_SetVar(interp, "argv0", (fileName != NULL) ? fileName : argv[0], - TCL_GLOBAL_ONLY); + Tcl_SetVar(interp, "argv0", Tcl_DStringValue(&argString), TCL_GLOBAL_ONLY); /* * Set the "tcl_interactive" variable. @@ -150,12 +190,31 @@ Tk_Main(argc, argv, appInitProc) */ #ifdef __WIN32__ - tty = 1; + handle = GetStdHandle(STD_INPUT_HANDLE); + + if ((handle == INVALID_HANDLE_VALUE) || (handle == 0) + || (GetFileType(handle) == FILE_TYPE_UNKNOWN)) { + /* + * If it's a bad or closed handle, then it's been connected + * to a wish console window. + */ + + tsdPtr->tty = 1; + } else if (GetFileType(handle) == FILE_TYPE_CHAR) { + /* + * A character file handle is a tty by definition. + */ + + tsdPtr->tty = 1; + } else { + tsdPtr->tty = 0; + } + #else - tty = isatty(0); + tsdPtr->tty = isatty(0); #endif Tcl_SetVar(interp, "tcl_interactive", - ((fileName == NULL) && tty) ? "1" : "0", TCL_GLOBAL_ONLY); + ((fileName == NULL) && tsdPtr->tty) ? "1" : "0", TCL_GLOBAL_ONLY); /* * Invoke application-specific initialization. @@ -170,6 +229,7 @@ Tk_Main(argc, argv, appInitProc) */ if (fileName != NULL) { + Tcl_ResetResult(interp); code = Tcl_EvalFile(interp, fileName); if (code != TCL_OK) { /* @@ -183,7 +243,7 @@ Tk_Main(argc, argv, appInitProc) Tcl_DeleteInterp(interp); Tcl_Exit(1); } - tty = 0; + tsdPtr->tty = 0; } else { /* @@ -201,17 +261,18 @@ Tk_Main(argc, argv, appInitProc) Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc, (ClientData) inChannel); } - if (tty) { + if (tsdPtr->tty) { Prompt(interp, 0); } } + Tcl_DStringFree(&argString); outChannel = Tcl_GetStdChannel(TCL_STDOUT); if (outChannel) { Tcl_Flush(outChannel); } - Tcl_DStringInit(&command); - Tcl_DStringInit(&line); + Tcl_DStringInit(&tsdPtr->command); + Tcl_DStringInit(&tsdPtr->line); Tcl_ResetResult(interp); /* @@ -254,12 +315,15 @@ StdinProc(clientData, mask) char *cmd; int code, count; Tcl_Channel chan = (Tcl_Channel) clientData; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + Tcl_Interp *interp = tsdPtr->interp; - count = Tcl_Gets(chan, &line); + count = Tcl_Gets(chan, &tsdPtr->line); if (count < 0) { if (!gotPartial) { - if (tty) { + if (tsdPtr->tty) { Tcl_Exit(0); } else { Tcl_DeleteChannelHandler(chan, StdinProc, (ClientData) chan); @@ -268,9 +332,10 @@ StdinProc(clientData, mask) } } - (void) Tcl_DStringAppend(&command, Tcl_DStringValue(&line), -1); - cmd = Tcl_DStringAppend(&command, "\n", -1); - Tcl_DStringFree(&line); + (void) Tcl_DStringAppend(&tsdPtr->command, Tcl_DStringValue( + &tsdPtr->line), -1); + cmd = Tcl_DStringAppend(&tsdPtr->command, "\n", -1); + Tcl_DStringFree(&tsdPtr->line); if (!Tcl_CommandComplete(cmd)) { gotPartial = 1; goto prompt; @@ -293,17 +358,14 @@ StdinProc(clientData, mask) Tcl_CreateChannelHandler(chan, TCL_READABLE, StdinProc, (ClientData) chan); } - Tcl_DStringFree(&command); - if (*interp->result != 0) { - if ((code != TCL_OK) || (tty)) { - /* - * The statement below used to call "printf", but that resulted - * in core dumps under Solaris 2.3 if the result was very long. - * - * NOTE: This probably will not work under Windows either. - */ - - puts(interp->result); + Tcl_DStringFree(&tsdPtr->command); + if (Tcl_GetStringResult(interp)[0] != '\0') { + if ((code != TCL_OK) || (tsdPtr->tty)) { + chan = Tcl_GetStdChannel(TCL_STDOUT); + if (chan) { + Tcl_WriteObj(chan, Tcl_GetObjResult(interp)); + Tcl_WriteChars(chan, "\n", 1); + } } } @@ -312,7 +374,7 @@ StdinProc(clientData, mask) */ prompt: - if (tty) { + if (tsdPtr->tty) { Prompt(interp, gotPartial); } Tcl_ResetResult(interp); @@ -361,7 +423,7 @@ defaultPrompt: outChannel = Tcl_GetChannel(interp, "stdout", NULL); if (outChannel != (Tcl_Channel) NULL) { - Tcl_Write(outChannel, "% ", 2); + Tcl_WriteChars(outChannel, "% ", 2); } } } else { @@ -377,8 +439,8 @@ defaultPrompt: errChannel = Tcl_GetChannel(interp, "stderr", NULL); if (errChannel != (Tcl_Channel) NULL) { - Tcl_Write(errChannel, interp->result, -1); - Tcl_Write(errChannel, "\n", 1); + Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); + Tcl_WriteChars(errChannel, "\n", 1); } goto defaultPrompt; } @@ -388,3 +450,5 @@ defaultPrompt: Tcl_Flush(outChannel); } } + + diff --git a/tk/generic/tkMenu.c b/tk/generic/tkMenu.c index 3663d40ecbc..2e84ebb59eb 100644 --- a/tk/generic/tkMenu.c +++ b/tk/generic/tkMenu.c @@ -7,7 +7,7 @@ * and drawing code for menus is in the file tkMenuDraw.c * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -68,174 +68,247 @@ * */ +#if 0 + +/* + * used only to test for old config code + */ + +#define __NO_OLD_CONFIG +#endif + #include "tkPort.h" #include "tkMenu.h" #define MENU_HASH_KEY "tkMenus" -static int menusInitialized; /* Whether or not the hash tables, etc., have - * been setup */ +typedef struct ThreadSpecificData { + int menusInitialized; /* Flag indicates whether thread-specific + * elements of the Windows Menu module + * have been initialized. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; + +/* + * The following flag indicates whether the process-wide state for + * the Menu module has been intialized. The Mutex protects access to + * that flag. + */ + +static int menusInitialized; +TCL_DECLARE_MUTEX(menuMutex) /* * Configuration specs for individual menu entries. If this changes, be sure * to update code in TkpMenuInit that changes the font string entry. */ -Tk_ConfigSpec tkMenuEntryConfigSpecs[] = { - {TK_CONFIG_BORDER, "-activebackground", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_ACTIVE_BG, Tk_Offset(TkMenuEntry, activeBorder), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-activeforeground", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_ACTIVE_FG, Tk_Offset(TkMenuEntry, activeFg), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-accelerator", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_ACCELERATOR, Tk_Offset(TkMenuEntry, accel), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_BORDER, "-background", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_BG, Tk_Offset(TkMenuEntry, border), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |SEPARATOR_MASK|TEAROFF_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_BITMAP, "-bitmap", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_BITMAP, Tk_Offset(TkMenuEntry, bitmap), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-columnbreak", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_COLUMN_BREAK, Tk_Offset(TkMenuEntry, columnBreak), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK}, - {TK_CONFIG_STRING, "-command", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_COMMAND, Tk_Offset(TkMenuEntry, command), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_FONT, Tk_Offset(TkMenuEntry, tkfont), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-foreground", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_FG, Tk_Offset(TkMenuEntry, fg), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-hidemargin", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_HIDE_MARGIN, Tk_Offset(TkMenuEntry, hideMargin), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |SEPARATOR_MASK|TEAROFF_MASK}, - {TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_IMAGE, Tk_Offset(TkMenuEntry, imageString), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-indicatoron", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_INDICATOR, Tk_Offset(TkMenuEntry, indicatorOn), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_STRING, "-label", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_LABEL, Tk_Offset(TkMenuEntry, label), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK}, - {TK_CONFIG_STRING, "-menu", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_MENU, Tk_Offset(TkMenuEntry, name), - CASCADE_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-offvalue", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_OFF_VALUE, Tk_Offset(TkMenuEntry, offValue), - CHECK_BUTTON_MASK}, - {TK_CONFIG_STRING, "-onvalue", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_ON_VALUE, Tk_Offset(TkMenuEntry, onValue), - CHECK_BUTTON_MASK}, - {TK_CONFIG_COLOR, "-selectcolor", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_SELECT, Tk_Offset(TkMenuEntry, indicatorFg), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-selectimage", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_SELECT_IMAGE, Tk_Offset(TkMenuEntry, selectImageString), - CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-state", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_STATE, Tk_Offset(TkMenuEntry, state), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TEAROFF_MASK|TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_STRING, "-value", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_VALUE, Tk_Offset(TkMenuEntry, onValue), - RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-variable", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_CHECK_VARIABLE, Tk_Offset(TkMenuEntry, name), - CHECK_BUTTON_MASK|TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-variable", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_RADIO_VARIABLE, Tk_Offset(TkMenuEntry, name), - RADIO_BUTTON_MASK}, - {TK_CONFIG_INT, "-underline", (char *) NULL, (char *) NULL, - DEF_MENU_ENTRY_UNDERLINE, Tk_Offset(TkMenuEntry, underline), - COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK - |TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} +char *tkMenuStateStrings[] = {"active", "normal", "disabled", (char *) NULL}; + +static char *menuEntryTypeStrings[] = {"cascade", "checkbutton", "command", + "radiobutton", "separator", (char *) NULL}; + +Tk_OptionSpec tkBasicMenuEntryConfigSpecs[] = { + {TK_OPTION_BORDER, "-activebackground", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_ACTIVE_BG, Tk_Offset(TkMenuEntry, activeBorderPtr), -1, + TK_OPTION_NULL_OK}, + {TK_OPTION_COLOR, "-activeforeground", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_ACTIVE_FG, + Tk_Offset(TkMenuEntry, activeFgPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_STRING, "-accelerator", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_ACCELERATOR, + Tk_Offset(TkMenuEntry, accelPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_BORDER, "-background", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_BG, + Tk_Offset(TkMenuEntry, borderPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_BITMAP, "-bitmap", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_BITMAP, + Tk_Offset(TkMenuEntry, bitmapPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_BOOLEAN, "-columnbreak", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_COLUMN_BREAK, + -1, Tk_Offset(TkMenuEntry, columnBreak)}, + {TK_OPTION_STRING, "-command", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_COMMAND, + Tk_Offset(TkMenuEntry, commandPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_FONT, "-font", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_FONT, + Tk_Offset(TkMenuEntry, fontPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_COLOR, "-foreground", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_FG, + Tk_Offset(TkMenuEntry, fgPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_BOOLEAN, "-hidemargin", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_HIDE_MARGIN, + -1, Tk_Offset(TkMenuEntry, hideMargin)}, + {TK_OPTION_STRING, "-image", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_IMAGE, + Tk_Offset(TkMenuEntry, imagePtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_STRING, "-label", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_LABEL, + Tk_Offset(TkMenuEntry, labelPtr), -1, 0}, + {TK_OPTION_STRING_TABLE, "-state", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_STATE, + -1, Tk_Offset(TkMenuEntry, state), 0, + (ClientData) tkMenuStateStrings}, + {TK_OPTION_INT, "-underline", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_UNDERLINE, -1, Tk_Offset(TkMenuEntry, underline)}, + {TK_OPTION_END} +}; + +Tk_OptionSpec tkSeparatorEntryConfigSpecs[] = { + {TK_OPTION_BORDER, "-background", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_BG, + Tk_Offset(TkMenuEntry, borderPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_END} +}; + +Tk_OptionSpec tkCheckButtonEntryConfigSpecs[] = { + {TK_OPTION_BOOLEAN, "-indicatoron", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_INDICATOR, + -1, Tk_Offset(TkMenuEntry, indicatorOn)}, + {TK_OPTION_STRING, "-offvalue", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_OFF_VALUE, + Tk_Offset(TkMenuEntry, offValuePtr), -1}, + {TK_OPTION_STRING, "-onvalue", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_ON_VALUE, + Tk_Offset(TkMenuEntry, onValuePtr), -1}, + {TK_OPTION_COLOR, "-selectcolor", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_SELECT, + Tk_Offset(TkMenuEntry, indicatorFgPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_STRING, "-selectimage", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_SELECT_IMAGE, + Tk_Offset(TkMenuEntry, selectImagePtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_STRING, "-variable", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_CHECK_VARIABLE, + Tk_Offset(TkMenuEntry, namePtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) tkBasicMenuEntryConfigSpecs} +}; + +Tk_OptionSpec tkRadioButtonEntryConfigSpecs[] = { + {TK_OPTION_BOOLEAN, "-indicatoron", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_INDICATOR, + -1, Tk_Offset(TkMenuEntry, indicatorOn)}, + {TK_OPTION_COLOR, "-selectcolor", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_SELECT, + Tk_Offset(TkMenuEntry, indicatorFgPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_STRING, "-selectimage", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_SELECT_IMAGE, + Tk_Offset(TkMenuEntry, selectImagePtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_STRING, "-value", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_VALUE, + Tk_Offset(TkMenuEntry, onValuePtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_STRING, "-variable", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_RADIO_VARIABLE, + Tk_Offset(TkMenuEntry, namePtr), -1, 0}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) tkBasicMenuEntryConfigSpecs} }; +Tk_OptionSpec tkCascadeEntryConfigSpecs[] = { + {TK_OPTION_STRING, "-menu", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_MENU, + Tk_Offset(TkMenuEntry, namePtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) tkBasicMenuEntryConfigSpecs} +}; + +Tk_OptionSpec tkTearoffEntryConfigSpecs[] = { + {TK_OPTION_BORDER, "-background", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_BG, + Tk_Offset(TkMenuEntry, borderPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_STRING_TABLE, "-state", (char *) NULL, (char *) NULL, + DEF_MENU_ENTRY_STATE, -1, Tk_Offset(TkMenuEntry, state), 0, + (ClientData) tkMenuStateStrings}, + {TK_OPTION_END} +}; + +static Tk_OptionSpec *specsArray[] = { + tkCascadeEntryConfigSpecs, tkCheckButtonEntryConfigSpecs, + tkBasicMenuEntryConfigSpecs, tkRadioButtonEntryConfigSpecs, + tkSeparatorEntryConfigSpecs, tkTearoffEntryConfigSpecs}; + /* - * Configuration specs valid for the menu as a whole. If this changes, be sure - * to update code in TkpMenuInit that changes the font string entry. + * Menu type strings for use with Tcl_GetIndexFromObj. */ -Tk_ConfigSpec tkMenuConfigSpecs[] = { - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_MENU_ACTIVE_BG_COLOR, Tk_Offset(TkMenu, activeBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_MENU_ACTIVE_BG_MONO, Tk_Offset(TkMenu, activeBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_PIXELS, "-activeborderwidth", "activeBorderWidth", +static char *menuTypeStrings[] = {"normal", "tearoff", "menubar", + (char *) NULL}; + +Tk_OptionSpec tkMenuConfigSpecs[] = { + {TK_OPTION_BORDER, "-activebackground", "activeBackground", + "Foreground", DEF_MENU_ACTIVE_BG_COLOR, + Tk_Offset(TkMenu, activeBorderPtr), -1, 0, + (ClientData) DEF_MENU_ACTIVE_BG_MONO}, + {TK_OPTION_PIXELS, "-activeborderwidth", "activeBorderWidth", "BorderWidth", DEF_MENU_ACTIVE_BORDER_WIDTH, - Tk_Offset(TkMenu, activeBorderWidth), 0}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_MENU_ACTIVE_FG_COLOR, Tk_Offset(TkMenu, activeFg), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_MENU_ACTIVE_FG_MONO, Tk_Offset(TkMenu, activeFg), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_MENU_BG_COLOR, Tk_Offset(TkMenu, border), TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_MENU_BG_MONO, Tk_Offset(TkMenu, border), TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_MENU_BORDER_WIDTH, Tk_Offset(TkMenu, borderWidth), 0}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_MENU_CURSOR, Tk_Offset(TkMenu, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", + Tk_Offset(TkMenu, activeBorderWidthPtr), -1}, + {TK_OPTION_COLOR, "-activeforeground", "activeForeground", + "Background", DEF_MENU_ACTIVE_FG_COLOR, + Tk_Offset(TkMenu, activeFgPtr), -1, 0, + (ClientData) DEF_MENU_ACTIVE_FG_MONO}, + {TK_OPTION_BORDER, "-background", "background", "Background", + DEF_MENU_BG_COLOR, Tk_Offset(TkMenu, borderPtr), -1, 0, + (ClientData) DEF_MENU_BG_MONO}, + {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth"}, + {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-background"}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + DEF_MENU_BORDER_WIDTH, + Tk_Offset(TkMenu, borderWidthPtr), -1, 0}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + DEF_MENU_CURSOR, + Tk_Offset(TkMenu, cursorPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground", "DisabledForeground", DEF_MENU_DISABLED_FG_COLOR, - Tk_Offset(TkMenu, disabledFg), TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", - "DisabledForeground", DEF_MENU_DISABLED_FG_MONO, - Tk_Offset(TkMenu, disabledFg), TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_MENU_FONT, Tk_Offset(TkMenu, tkfont), 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_MENU_FG, Tk_Offset(TkMenu, fg), 0}, - {TK_CONFIG_STRING, "-postcommand", "postCommand", "Command", - DEF_MENU_POST_COMMAND, Tk_Offset(TkMenu, postCommand), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_MENU_RELIEF, Tk_Offset(TkMenu, relief), 0}, - {TK_CONFIG_COLOR, "-selectcolor", "selectColor", "Background", - DEF_MENU_SELECT_COLOR, Tk_Offset(TkMenu, indicatorFg), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-selectcolor", "selectColor", "Background", - DEF_MENU_SELECT_MONO, Tk_Offset(TkMenu, indicatorFg), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_MENU_TAKE_FOCUS, Tk_Offset(TkMenu, takeFocus), TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-tearoff", "tearOff", "TearOff", - DEF_MENU_TEAROFF, Tk_Offset(TkMenu, tearOff), 0}, - {TK_CONFIG_STRING, "-tearoffcommand", "tearOffCommand", "TearOffCommand", - DEF_MENU_TEAROFF_CMD, Tk_Offset(TkMenu, tearOffCommand), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-title", "title", "Title", - DEF_MENU_TITLE, Tk_Offset(TkMenu, title), TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-type", "type", "Type", - DEF_MENU_TYPE, Tk_Offset(TkMenu, menuTypeName), TK_CONFIG_NULL_OK}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} + Tk_Offset(TkMenu, disabledFgPtr), -1, TK_OPTION_NULL_OK, + (ClientData) DEF_MENU_DISABLED_FG_MONO}, + {TK_OPTION_SYNONYM, "-fg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground"}, + {TK_OPTION_FONT, "-font", "font", "Font", + DEF_MENU_FONT, Tk_Offset(TkMenu, fontPtr), -1}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + DEF_MENU_FG, Tk_Offset(TkMenu, fgPtr), -1}, + {TK_OPTION_STRING, "-postcommand", "postCommand", "Command", + DEF_MENU_POST_COMMAND, + Tk_Offset(TkMenu, postCommandPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + DEF_MENU_RELIEF, Tk_Offset(TkMenu, reliefPtr), -1}, + {TK_OPTION_COLOR, "-selectcolor", "selectColor", "Background", + DEF_MENU_SELECT_COLOR, Tk_Offset(TkMenu, indicatorFgPtr), -1, 0, + (ClientData) DEF_MENU_SELECT_MONO}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + DEF_MENU_TAKE_FOCUS, + Tk_Offset(TkMenu, takeFocusPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_BOOLEAN, "-tearoff", "tearOff", "TearOff", + DEF_MENU_TEAROFF, -1, Tk_Offset(TkMenu, tearoff)}, + {TK_OPTION_STRING, "-tearoffcommand", "tearOffCommand", + "TearOffCommand", DEF_MENU_TEAROFF_CMD, + Tk_Offset(TkMenu, tearoffCommandPtr), -1, TK_OPTION_NULL_OK}, + {TK_OPTION_STRING, "-title", "title", "Title", + DEF_MENU_TITLE, Tk_Offset(TkMenu, titlePtr), -1, + TK_OPTION_NULL_OK}, + {TK_OPTION_STRING_TABLE, "-type", "type", "Type", + DEF_MENU_TYPE, Tk_Offset(TkMenu, menuTypePtr), -1, TK_OPTION_NULL_OK, + (ClientData) menuTypeStrings}, + {TK_OPTION_END} +}; + +/* + * Command line options. Put here because MenuCmd has to look at them + * along with MenuWidgetObjCmd. + */ + +static char *menuOptions[] = { + "activate", "add", "cget", "clone", "configure", "delete", "entrycget", + "entryconfigure", "index", "insert", "invoke", "post", "postcascade", + "type", "unpost", "yposition", (char *) NULL +}; +enum options { + MENU_ACTIVATE, MENU_ADD, MENU_CGET, MENU_CLONE, MENU_CONFIGURE, + MENU_DELETE, MENU_ENTRYCGET, MENU_ENTRYCONFIGURE, MENU_INDEX, + MENU_INSERT, MENU_INVOKE, MENU_POST, MENU_POSTCASCADE, MENU_TYPE, + MENU_UNPOST, MENU_YPOSITION }; /* @@ -243,15 +316,14 @@ Tk_ConfigSpec tkMenuConfigSpecs[] = { */ static int CloneMenu _ANSI_ARGS_((TkMenu *menuPtr, - char *newMenuName, char *newMenuTypeString)); + Tcl_Obj *newMenuName, Tcl_Obj *newMenuTypeString)); static int ConfigureMenu _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, int argc, char **argv, - int flags)); + TkMenu *menuPtr, int objc, Tcl_Obj *CONST objv[])); static int ConfigureMenuCloneEntries _ANSI_ARGS_(( Tcl_Interp *interp, TkMenu *menuPtr, int index, - int argc, char **argv, int flags)); + int objc, Tcl_Obj *CONST objv[])); static int ConfigureMenuEntry _ANSI_ARGS_((TkMenuEntry *mePtr, - int argc, char **argv, int flags)); + int objc, Tcl_Obj *CONST objv[])); static void DeleteMenuCloneEntries _ANSI_ARGS_((TkMenu *menuPtr, int first, int last)); static void DestroyMenuHashTable _ANSI_ARGS_(( @@ -262,10 +334,13 @@ static int GetIndexFromCoords _ANSI_ARGS_((Tcl_Interp *interp, TkMenu *menuPtr, char *string, int *indexPtr)); static int MenuDoYPosition _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, char *arg)); + TkMenu *menuPtr, Tcl_Obj *objPtr)); static int MenuAddOrInsert _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, char *indexString, int argc, - char **argv)); + TkMenu *menuPtr, Tcl_Obj *indexPtr, int objc, + Tcl_Obj *CONST objv[])); +static int MenuCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); static void MenuCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); static TkMenuEntry * MenuNewEntry _ANSI_ARGS_((TkMenu *menuPtr, int index, @@ -273,10 +348,12 @@ static TkMenuEntry * MenuNewEntry _ANSI_ARGS_((TkMenu *menuPtr, int index, static char * MenuVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)); -static int MenuWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); +static int MenuWidgetObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); static void MenuWorldChanged _ANSI_ARGS_(( ClientData instanceData)); +static int PostProcessEntry _ANSI_ARGS_((TkMenuEntry *mePtr)); static void RecursivelyDeleteMenu _ANSI_ARGS_((TkMenu *menuPtr)); static void UnhookCascadeEntry _ANSI_ARGS_((TkMenuEntry *mePtr)); @@ -290,13 +367,61 @@ static TkClassProcs menuClass = { NULL, /* createProc. */ MenuWorldChanged /* geometryProc. */ }; + +/* + *-------------------------------------------------------------- + * + * Tk_CreateMenuCmd -- + * + * Called by Tk at initialization time to create the menu + * command. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +TkCreateMenuCmd(interp) + Tcl_Interp *interp; /* Interpreter we are creating the + * command in. */ +{ + TkMenuOptionTables *optionTablesPtr = + (TkMenuOptionTables *) ckalloc(sizeof(TkMenuOptionTables)); + + optionTablesPtr->menuOptionTable = + Tk_CreateOptionTable(interp, tkMenuConfigSpecs); + optionTablesPtr->entryOptionTables[TEAROFF_ENTRY] = + Tk_CreateOptionTable(interp, specsArray[TEAROFF_ENTRY]); + optionTablesPtr->entryOptionTables[COMMAND_ENTRY] = + Tk_CreateOptionTable(interp, specsArray[COMMAND_ENTRY]); + optionTablesPtr->entryOptionTables[CASCADE_ENTRY] = + Tk_CreateOptionTable(interp, specsArray[CASCADE_ENTRY]); + optionTablesPtr->entryOptionTables[SEPARATOR_ENTRY] = + Tk_CreateOptionTable(interp, specsArray[SEPARATOR_ENTRY]); + optionTablesPtr->entryOptionTables[RADIO_BUTTON_ENTRY] = + Tk_CreateOptionTable(interp, specsArray[RADIO_BUTTON_ENTRY]); + optionTablesPtr->entryOptionTables[CHECK_BUTTON_ENTRY] = + Tk_CreateOptionTable(interp, specsArray[CHECK_BUTTON_ENTRY]); + + Tcl_CreateObjCommand(interp, "menu", MenuCmd, + (ClientData) optionTablesPtr, NULL); + + if (Tcl_IsSafe(interp)) { + Tcl_HideCommand(interp, "menu", "menu"); + } + return TCL_OK; +} /* *-------------------------------------------------------------- * - * Tk_MenuCmd -- + * MenuCmd -- * * This procedure is invoked to process the "menu" Tcl * command. See the user documentation for details on @@ -311,48 +436,45 @@ static TkClassProcs menuClass = { *-------------------------------------------------------------- */ -int -Tk_MenuCmd(clientData, interp, argc, argv) +static int +MenuCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument strings. */ { - Tk_Window tkwin = (Tk_Window) clientData; + Tk_Window tkwin = Tk_MainWindow(interp); Tk_Window new; register TkMenu *menuPtr; TkMenuReferences *menuRefPtr; - int i, len; - char *arg, c; + int i, index; int toplevel; + char *windowName; + static char *typeStringList[] = {"-type", (char *) NULL}; + TkMenuOptionTables *optionTablesPtr = (TkMenuOptionTables *) clientData; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } TkMenuInit(); toplevel = 1; - for (i = 2; i < argc; i += 2) { - arg = argv[i]; - len = strlen(arg); - if (len < 2) { - continue; - } - c = arg[1]; - if ((c == 't') && (strncmp(arg, "-type", strlen(arg)) == 0) - && (len >= 3)) { - if (strcmp(argv[i + 1], "menubar") == 0) { + for (i = 2; i < (objc - 1); i++) { + if (Tcl_GetIndexFromObj(NULL, objv[i], typeStringList, NULL, 0, &index) + != TCL_ERROR) { + if ((Tcl_GetIndexFromObj(NULL, objv[i + 1], menuTypeStrings, NULL, + 0, &index) == TCL_OK) && (index == MENUBAR)) { toplevel = 0; } break; } } - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], toplevel ? "" + windowName = Tcl_GetStringFromObj(objv[1], NULL); + new = Tk_CreateWindowFromPath(interp, tkwin, windowName, toplevel ? "" : NULL); if (new == NULL) { return TCL_ERROR; @@ -366,27 +488,27 @@ Tk_MenuCmd(clientData, interp, argc, argv) menuPtr->tkwin = new; menuPtr->display = Tk_Display(new); menuPtr->interp = interp; - menuPtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(menuPtr->tkwin), MenuWidgetCmd, + menuPtr->widgetCmd = Tcl_CreateObjCommand(interp, + Tk_PathName(menuPtr->tkwin), MenuWidgetObjCmd, (ClientData) menuPtr, MenuCmdDeletedProc); menuPtr->entries = NULL; menuPtr->numEntries = 0; menuPtr->active = -1; - menuPtr->border = NULL; - menuPtr->borderWidth = 0; - menuPtr->relief = TK_RELIEF_FLAT; - menuPtr->activeBorder = NULL; - menuPtr->activeBorderWidth = 0; - menuPtr->tkfont = NULL; - menuPtr->fg = NULL; - menuPtr->disabledFg = NULL; - menuPtr->activeFg = NULL; - menuPtr->indicatorFg = NULL; - menuPtr->tearOff = 1; - menuPtr->tearOffCommand = NULL; - menuPtr->cursor = None; - menuPtr->takeFocus = NULL; - menuPtr->postCommand = NULL; + menuPtr->borderPtr = NULL; + menuPtr->borderWidthPtr = NULL; + menuPtr->reliefPtr = NULL; + menuPtr->activeBorderPtr = NULL; + menuPtr->activeBorderWidthPtr = NULL; + menuPtr->fontPtr = NULL; + menuPtr->fgPtr = NULL; + menuPtr->disabledFgPtr = NULL; + menuPtr->activeFgPtr = NULL; + menuPtr->indicatorFgPtr = NULL; + menuPtr->tearoff = 0; + menuPtr->tearoffCommandPtr = NULL; + menuPtr->cursorPtr = None; + menuPtr->takeFocusPtr = NULL; + menuPtr->postCommandPtr = NULL; menuPtr->postCommandGeneration = 0; menuPtr->postedCascade = NULL; menuPtr->nextInstancePtr = NULL; @@ -394,24 +516,38 @@ Tk_MenuCmd(clientData, interp, argc, argv) menuPtr->menuType = UNKNOWN_TYPE; menuPtr->menuFlags = 0; menuPtr->parentTopLevelPtr = NULL; - menuPtr->menuTypeName = NULL; - menuPtr->title = NULL; + menuPtr->menuTypePtr = NULL; + menuPtr->titlePtr = NULL; + menuPtr->errorStructPtr = NULL; + menuPtr->optionTablesPtr = optionTablesPtr; TkMenuInitializeDrawingFields(menuPtr); + Tk_SetClass(menuPtr->tkwin, "Menu"); + TkSetClassProcs(menuPtr->tkwin, &menuClass, (ClientData) menuPtr); + if (Tk_InitOptions(interp, (char *) menuPtr, + menuPtr->optionTablesPtr->menuOptionTable, menuPtr->tkwin) + != TCL_OK) { + Tk_DestroyWindow(menuPtr->tkwin); + ckfree((char *) menuPtr); + return TCL_ERROR; + } + + menuRefPtr = TkCreateMenuReferences(menuPtr->interp, Tk_PathName(menuPtr->tkwin)); menuRefPtr->menuPtr = menuPtr; menuPtr->menuRefPtr = menuRefPtr; if (TCL_OK != TkpNewMenu(menuPtr)) { - goto error; + Tk_DestroyWindow(menuPtr->tkwin); + ckfree((char *) menuPtr); + return TCL_ERROR; } - Tk_SetClass(menuPtr->tkwin, "Menu"); - TkSetClassProcs(menuPtr->tkwin, &menuClass, (ClientData) menuPtr); Tk_CreateEventHandler(new, ExposureMask|StructureNotifyMask|ActivateMask, TkMenuEventProc, (ClientData) menuPtr); - if (ConfigureMenu(interp, menuPtr, argc-2, argv+2, 0) != TCL_OK) { - goto error; + if (ConfigureMenu(interp, menuPtr, objc - 2, objv + 2) != TCL_OK) { + Tk_DestroyWindow(menuPtr->tkwin); + return TCL_ERROR; } /* @@ -434,8 +570,8 @@ Tk_MenuCmd(clientData, interp, argc, argv) if (menuRefPtr->parentEntryPtr != NULL) { TkMenuEntry *cascadeListPtr = menuRefPtr->parentEntryPtr; TkMenuEntry *nextCascadePtr; - char *newMenuName; - char *newArgv[2]; + Tcl_Obj *newMenuName; + Tcl_Obj *newObjv[2]; while (cascadeListPtr != NULL) { @@ -454,28 +590,38 @@ Tk_MenuCmd(clientData, interp, argc, argv) || ((menuPtr->masterMenuPtr == menuPtr) && ((cascadeListPtr->menuPtr->masterMenuPtr == cascadeListPtr->menuPtr)))) { - newArgv[0] = "-menu"; - newArgv[1] = Tk_PathName(menuPtr->tkwin); - ConfigureMenuEntry(cascadeListPtr, 2, newArgv, - TK_CONFIG_ARGV_ONLY); + newObjv[0] = Tcl_NewStringObj("-menu", -1); + newObjv[1] = Tcl_NewStringObj(Tk_PathName(menuPtr->tkwin), -1); + Tcl_IncrRefCount(newObjv[0]); + Tcl_IncrRefCount(newObjv[1]); + ConfigureMenuEntry(cascadeListPtr, 2, newObjv); + Tcl_DecrRefCount(newObjv[0]); + Tcl_DecrRefCount(newObjv[1]); } else { + Tcl_Obj *normalPtr = Tcl_NewStringObj("normal", -1); + Tcl_Obj *windowNamePtr = Tcl_NewStringObj( + Tk_PathName(cascadeListPtr->menuPtr->tkwin), -1); + + Tcl_IncrRefCount(normalPtr); + Tcl_IncrRefCount(windowNamePtr); newMenuName = TkNewMenuName(menuPtr->interp, - Tk_PathName(cascadeListPtr->menuPtr->tkwin), - menuPtr); - CloneMenu(menuPtr, newMenuName, "normal"); + windowNamePtr, menuPtr); + Tcl_IncrRefCount(newMenuName); + CloneMenu(menuPtr, newMenuName, normalPtr); /* * Now we can set the new menu instance to be the cascade entry * of the parent's instance. */ - newArgv[0] = "-menu"; - newArgv[1] = newMenuName; - ConfigureMenuEntry(cascadeListPtr, 2, newArgv, - TK_CONFIG_ARGV_ONLY); - if (newMenuName != NULL) { - ckfree(newMenuName); - } + newObjv[0] = Tcl_NewStringObj("-menu", -1); + newObjv[1] = newMenuName; + Tcl_IncrRefCount(newObjv[0]); + ConfigureMenuEntry(cascadeListPtr, 2, newObjv); + Tcl_DecrRefCount(normalPtr); + Tcl_DecrRefCount(newObjv[0]); + Tcl_DecrRefCount(newObjv[1]); + Tcl_DecrRefCount(windowNamePtr); } cascadeListPtr = nextCascadePtr; } @@ -507,18 +653,14 @@ Tk_MenuCmd(clientData, interp, argc, argv) } } - interp->result = Tk_PathName(menuPtr->tkwin); + Tcl_SetResult(interp, Tk_PathName(menuPtr->tkwin), TCL_STATIC); return TCL_OK; - - error: - Tk_DestroyWindow(menuPtr->tkwin); - return TCL_ERROR; } /* *-------------------------------------------------------------- * - * MenuWidgetCmd -- + * MenuWidgetObjCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a widget managed by this module. @@ -534,317 +676,353 @@ Tk_MenuCmd(clientData, interp, argc, argv) */ static int -MenuWidgetCmd(clientData, interp, argc, argv) +MenuWidgetObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about menu widget. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument strings. */ { register TkMenu *menuPtr = (TkMenu *) clientData; register TkMenuEntry *mePtr; int result = TCL_OK; - size_t length; - int c; + int option; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], menuOptions, "option", 0, + &option) != TCL_OK) { return TCL_ERROR; } Tcl_Preserve((ClientData) menuPtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0) - && (length >= 2)) { - int index; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " activate index\"", (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (menuPtr->active == index) { - goto done; - } - if (index >= 0) { - if ((menuPtr->entries[index]->type == SEPARATOR_ENTRY) - || (menuPtr->entries[index]->state == tkDisabledUid)) { + + switch ((enum options) option) { + case MENU_ACTIVATE: { + int index; + /* patch for menu selection */ + int state; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "activate index"); + goto error; + } + if (TkGetMenuIndex(interp, menuPtr, objv[2], 0, &index) + != TCL_OK) { + goto error; + } + if (menuPtr->active == index) { + goto done; + } + if ((index >= 0) + && ((menuPtr->entries[index]->type == SEPARATOR_ENTRY) + || (menuPtr->entries[index]->state + == ENTRY_DISABLED))) { index = -1; } + result = TkActivateMenuEntry(menuPtr, index); + break; } - result = TkActivateMenuEntry(menuPtr, index); - } else if ((c == 'a') && (strncmp(argv[1], "add", length) == 0) - && (length >= 2)) { - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " add type ?options?\"", (char *) NULL); - goto error; + case MENU_ADD: + if (objc < 3) { + Tcl_WrongNumArgs(interp, 1, objv, "add type ?options?"); + goto error; + } + + if (MenuAddOrInsert(interp, menuPtr, (Tcl_Obj *) NULL, + objc - 2, objv + 2) != TCL_OK) { + goto error; + } + break; + case MENU_CGET: { + Tcl_Obj *resultPtr; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "cget option"); + goto error; + } + resultPtr = Tk_GetOptionValue(interp, (char *) menuPtr, + menuPtr->optionTablesPtr->menuOptionTable, objv[2], + menuPtr->tkwin); + if (resultPtr == NULL) { + goto error; + } + Tcl_SetObjResult(interp, resultPtr); + break; } - if (MenuAddOrInsert(interp, menuPtr, (char *) NULL, - argc-2, argv+2) != TCL_OK) { - goto error; + case MENU_CLONE: + if ((objc < 3) || (objc > 4)) { + Tcl_WrongNumArgs(interp, 1, objv, + "clone newMenuName ?menuType?"); + goto error; + } + result = CloneMenu(menuPtr, objv[2], (objc == 3) ? NULL : objv[3]); + break; + case MENU_CONFIGURE: { + Tcl_Obj *resultPtr; + + if (objc == 2) { + resultPtr = Tk_GetOptionInfo(interp, (char *) menuPtr, + menuPtr->optionTablesPtr->menuOptionTable, + (Tcl_Obj *) NULL, menuPtr->tkwin); + if (resultPtr == NULL) { + result = TCL_ERROR; + } else { + result = TCL_OK; + Tcl_SetObjResult(interp, resultPtr); + } + } else if (objc == 3) { + resultPtr = Tk_GetOptionInfo(interp, (char *) menuPtr, + menuPtr->optionTablesPtr->menuOptionTable, + objv[2], menuPtr->tkwin); + if (resultPtr == NULL) { + result = TCL_ERROR; + } else { + result = TCL_OK; + Tcl_SetObjResult(interp, resultPtr); + } + } else { + result = ConfigureMenu(interp, menuPtr, objc - 2, objv + 2); + } + if (result != TCL_OK) { + goto error; + } + break; } - } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; + case MENU_DELETE: { + int first, last; + + if ((objc != 3) && (objc != 4)) { + Tcl_WrongNumArgs(interp, 1, objv, "delete first ?last?"); + goto error; + } + if (TkGetMenuIndex(interp, menuPtr, objv[2], 0, &first) + != TCL_OK) { + goto error; + } + if (objc == 3) { + last = first; + } else { + if (TkGetMenuIndex(interp, menuPtr, objv[3], 0, &last) + != TCL_OK) { + goto error; + } + } + if (menuPtr->tearoff && (first == 0)) { + + /* + * Sorry, can't delete the tearoff entry; must reconfigure + * the menu. + */ + + first = 1; + } + if ((first < 0) || (last < first)) { + goto done; + } + DeleteMenuCloneEntries(menuPtr, first, last); + break; } - result = Tk_ConfigureValue(interp, menuPtr->tkwin, tkMenuConfigSpecs, - (char *) menuPtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "clone", length) == 0) - && (length >=2)) { - if ((argc < 3) || (argc > 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " clone newMenuName ?menuType?\"", - (char *) NULL); - goto error; - } - result = CloneMenu(menuPtr, argv[2], (argc == 3) ? NULL : argv[3]); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, menuPtr->tkwin, - tkMenuConfigSpecs, (char *) menuPtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, menuPtr->tkwin, - tkMenuConfigSpecs, (char *) menuPtr, argv[2], 0); - } else { - result = ConfigureMenu(interp, menuPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); + case MENU_ENTRYCGET: { + int index; + Tcl_Obj *resultPtr; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, "entrycget index option"); + goto error; + } + if (TkGetMenuIndex(interp, menuPtr, objv[2], 0, &index) + != TCL_OK) { + goto error; + } + if (index < 0) { + goto done; + } + mePtr = menuPtr->entries[index]; + Tcl_Preserve((ClientData) mePtr); + resultPtr = Tk_GetOptionValue(interp, (char *) mePtr, + mePtr->optionTable, objv[3], menuPtr->tkwin); + Tcl_Release((ClientData) mePtr); + if (resultPtr == NULL) { + goto error; + } + Tcl_SetObjResult(interp, resultPtr); + break; } - } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) { - int first, last; + case MENU_ENTRYCONFIGURE: { + int index; + Tcl_Obj *resultPtr; - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " delete first ?last?\"", (char *) NULL); - goto error; + if (objc < 3) { + Tcl_WrongNumArgs(interp, 1, objv, + "entryconfigure index ?option value ...?"); + goto error; + } + if (TkGetMenuIndex(interp, menuPtr, objv[2], 0, &index) + != TCL_OK) { + goto error; + } + if (index < 0) { + goto done; + } + mePtr = menuPtr->entries[index]; + Tcl_Preserve((ClientData) mePtr); + if (objc == 3) { + resultPtr = Tk_GetOptionInfo(interp, (char *) mePtr, + mePtr->optionTable, (Tcl_Obj *) NULL, menuPtr->tkwin); + if (resultPtr == NULL) { + result = TCL_ERROR; + } else { + result = TCL_OK; + Tcl_SetObjResult(interp, resultPtr); + } + } else if (objc == 4) { + resultPtr = Tk_GetOptionInfo(interp, (char *) mePtr, + mePtr->optionTable, objv[3], menuPtr->tkwin); + if (resultPtr == NULL) { + result = TCL_ERROR; + } else { + result = TCL_OK; + Tcl_SetObjResult(interp, resultPtr); + } + } else { + result = ConfigureMenuCloneEntries(interp, menuPtr, index, + objc - 3, objv + 3); + } + Tcl_Release((ClientData) mePtr); + break; } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &first) != TCL_OK) { - goto error; + case MENU_INDEX: { + int index; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "index string"); + goto error; + } + if (TkGetMenuIndex(interp, menuPtr, objv[2], 0, &index) + != TCL_OK) { + goto error; + } + if (index < 0) { + Tcl_SetResult(interp, "none", TCL_STATIC); + } else { + Tcl_SetIntObj(Tcl_GetObjResult(interp), index); + } + break; } - if (argc == 3) { - last = first; - } else { - if (TkGetMenuIndex(interp, menuPtr, argv[3], 0, &last) != TCL_OK) { - goto error; + case MENU_INSERT: + if (objc < 4) { + Tcl_WrongNumArgs(interp, 1, objv, + "insert index type ?options?"); + goto error; } + if (MenuAddOrInsert(interp, menuPtr, objv[2], objc - 3, + objv + 3) != TCL_OK) { + goto error; + } + break; + case MENU_INVOKE: { + int index; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "invoke index"); + goto error; + } + if (TkGetMenuIndex(interp, menuPtr, objv[2], 0, &index) + != TCL_OK) { + goto error; + } + if (index < 0) { + goto done; + } + result = TkInvokeMenu(interp, menuPtr, index); + break; } - if (menuPtr->tearOff && (first == 0)) { + case MENU_POST: { + int x, y; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, "post x y"); + goto error; + } + if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) + || (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) { + goto error; + } /* - * Sorry, can't delete the tearoff entry; must reconfigure - * the menu. + * Tearoff menus are posted differently on Mac and Windows than + * non-tearoffs. TkpPostMenu does not actually map the menu's + * window on those platforms, and popup menus have to be + * handled specially. */ - first = 1; - } - if ((first < 0) || (last < first)) { - goto done; - } - DeleteMenuCloneEntries(menuPtr, first, last); - } else if ((c == 'e') && (length >= 7) - && (strncmp(argv[1], "entrycget", length) == 0)) { - int index; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " entrycget index option\"", - (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index < 0) { - goto done; - } - mePtr = menuPtr->entries[index]; - Tcl_Preserve((ClientData) mePtr); - result = Tk_ConfigureValue(interp, menuPtr->tkwin, - tkMenuEntryConfigSpecs, (char *) mePtr, argv[3], - COMMAND_MASK << mePtr->type); - Tcl_Release((ClientData) mePtr); - } else if ((c == 'e') && (length >= 7) - && (strncmp(argv[1], "entryconfigure", length) == 0)) { - int index; - - if (argc < 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " entryconfigure index ?option value ...?\"", - (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index < 0) { - goto done; - } - mePtr = menuPtr->entries[index]; - Tcl_Preserve((ClientData) mePtr); - if (argc == 3) { - result = Tk_ConfigureInfo(interp, menuPtr->tkwin, - tkMenuEntryConfigSpecs, (char *) mePtr, (char *) NULL, - COMMAND_MASK << mePtr->type); - } else if (argc == 4) { - result = Tk_ConfigureInfo(interp, menuPtr->tkwin, - tkMenuEntryConfigSpecs, (char *) mePtr, argv[3], - COMMAND_MASK << mePtr->type); - } else { - result = ConfigureMenuCloneEntries(interp, menuPtr, index, - argc-3, argv+3, - TK_CONFIG_ARGV_ONLY | COMMAND_MASK << mePtr->type); - } - Tcl_Release((ClientData) mePtr); - } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0) - && (length >= 3)) { - int index; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " index string\"", (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index < 0) { - interp->result = "none"; - } else { - sprintf(interp->result, "%d", index); - } - } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0) - && (length >= 3)) { - if (argc < 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " insert index type ?options?\"", (char *) NULL); - goto error; - } - if (MenuAddOrInsert(interp, menuPtr, argv[2], - argc-3, argv+3) != TCL_OK) { - goto error; + if (menuPtr->menuType != TEAROFF_MENU) { + result = TkpPostMenu(interp, menuPtr, x, y); + } else { + result = TkPostTearoffMenu(interp, menuPtr, x, y); + } + break; } - } else if ((c == 'i') && (strncmp(argv[1], "invoke", length) == 0) - && (length >= 3)) { - int index; + case MENU_POSTCASCADE: { + int index; - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " invoke index\"", (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index < 0) { - goto done; - } - result = TkInvokeMenu(interp, menuPtr, index); - } else if ((c == 'p') && (strncmp(argv[1], "post", length) == 0) - && (length == 4)) { - int x, y; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " post x y\"", (char *) NULL); - goto error; - } - if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { - goto error; - } + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "postcascade index"); + goto error; + } - /* - * Tearoff menus are posted differently on Mac and Windows than - * non-tearoffs. TkpPostMenu does not actually map the menu's - * window on those platforms, and popup menus have to be - * handled specially. - */ - - if (menuPtr->menuType != TEAROFF_MENU) { - result = TkpPostMenu(interp, menuPtr, x, y); - } else { - result = TkPostTearoffMenu(interp, menuPtr, x, y); - } - } else if ((c == 'p') && (strncmp(argv[1], "postcascade", length) == 0) - && (length > 4)) { - int index; - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " postcascade index\"", (char *) NULL); - goto error; + if (TkGetMenuIndex(interp, menuPtr, objv[2], 0, &index) + != TCL_OK) { + goto error; + } + if ((index < 0) || (menuPtr->entries[index]->type + != CASCADE_ENTRY)) { + result = TkPostSubmenu(interp, menuPtr, (TkMenuEntry *) NULL); + } else { + result = TkPostSubmenu(interp, menuPtr, + menuPtr->entries[index]); + } + break; } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; + case MENU_TYPE: { + int index; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "type index"); + goto error; + } + if (TkGetMenuIndex(interp, menuPtr, objv[2], 0, &index) + != TCL_OK) { + goto error; + } + if (index < 0) { + goto done; + } + if (menuPtr->entries[index]->type == TEAROFF_ENTRY) { + Tcl_SetResult(interp, "tearoff", TCL_STATIC); + } else { + Tcl_SetResult(interp, + menuEntryTypeStrings[menuPtr->entries[index]->type], + TCL_STATIC); + } + break; } - if ((index < 0) || (menuPtr->entries[index]->type != CASCADE_ENTRY)) { + case MENU_UNPOST: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "unpost"); + goto error; + } + Tk_UnmapWindow(menuPtr->tkwin); result = TkPostSubmenu(interp, menuPtr, (TkMenuEntry *) NULL); - } else { - result = TkPostSubmenu(interp, menuPtr, menuPtr->entries[index]); - } - } else if ((c == 't') && (strncmp(argv[1], "type", length) == 0)) { - int index; - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " type index\"", (char *) NULL); - goto error; - } - if (TkGetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) { - goto error; - } - if (index < 0) { - goto done; - } - mePtr = menuPtr->entries[index]; - switch (mePtr->type) { - case COMMAND_ENTRY: - interp->result = "command"; - break; - case SEPARATOR_ENTRY: - interp->result = "separator"; - break; - case CHECK_BUTTON_ENTRY: - interp->result = "checkbutton"; - break; - case RADIO_BUTTON_ENTRY: - interp->result = "radiobutton"; - break; - case CASCADE_ENTRY: - interp->result = "cascade"; - break; - case TEAROFF_ENTRY: - interp->result = "tearoff"; - break; - } - } else if ((c == 'u') && (strncmp(argv[1], "unpost", length) == 0)) { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " unpost\"", (char *) NULL); - goto error; - } - Tk_UnmapWindow(menuPtr->tkwin); - result = TkPostSubmenu(interp, menuPtr, (TkMenuEntry *) NULL); - } else if ((c == 'y') && (strncmp(argv[1], "yposition", length) == 0)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " yposition index\"", (char *) NULL); - goto error; - } - result = MenuDoYPosition(interp, menuPtr, argv[2]); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be activate, add, cget, clone, configure, delete, ", - "entrycget, entryconfigure, index, insert, invoke, ", - "post, postcascade, type, unpost, or yposition", - (char *) NULL); - goto error; + break; + case MENU_YPOSITION: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "yposition index"); + goto error; + } + result = MenuDoYPosition(interp, menuPtr, objv[2]); + break; } done: Tcl_Release((ClientData) menuPtr); @@ -854,7 +1032,6 @@ MenuWidgetCmd(clientData, interp, argc, argv) Tcl_Release((ClientData) menuPtr); return TCL_ERROR; } - /* *---------------------------------------------------------------------- @@ -888,45 +1065,60 @@ TkInvokeMenu(interp, menuPtr, index) goto done; } mePtr = menuPtr->entries[index]; - if (mePtr->state == tkDisabledUid) { + if (mePtr->state == ENTRY_DISABLED) { goto done; } Tcl_Preserve((ClientData) mePtr); if (mePtr->type == TEAROFF_ENTRY) { - Tcl_DString commandDString; - - Tcl_DStringInit(&commandDString); - Tcl_DStringAppendElement(&commandDString, "tkTearOffMenu"); - Tcl_DStringAppendElement(&commandDString, Tk_PathName(menuPtr->tkwin)); - result = Tcl_Eval(interp, Tcl_DStringValue(&commandDString)); - Tcl_DStringFree(&commandDString); - } else if (mePtr->type == CHECK_BUTTON_ENTRY) { + Tcl_DString ds; + Tcl_DStringInit(&ds); + Tcl_DStringAppend(&ds, "tkTearOffMenu ", -1); + Tcl_DStringAppend(&ds, Tk_PathName(menuPtr->tkwin), -1); + result = Tcl_Eval(interp, Tcl_DStringValue(&ds)); + Tcl_DStringFree(&ds); + } else if ((mePtr->type == CHECK_BUTTON_ENTRY) + && (mePtr->namePtr != NULL)) { + Tcl_Obj *valuePtr; + if (mePtr->entryFlags & ENTRY_SELECTED) { - if (Tcl_SetVar(interp, mePtr->name, mePtr->offValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - } + valuePtr = mePtr->offValuePtr; } else { - if (Tcl_SetVar(interp, mePtr->name, mePtr->onValue, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - } + valuePtr = mePtr->onValuePtr; + } + if (valuePtr == NULL) { + valuePtr = Tcl_NewObj(); + } + Tcl_IncrRefCount(valuePtr); + if (Tcl_ObjSetVar2(interp, mePtr->namePtr, NULL, valuePtr, + TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { + result = TCL_ERROR; + } + Tcl_DecrRefCount(valuePtr); + } else if ((mePtr->type == RADIO_BUTTON_ENTRY) + && (mePtr->namePtr != NULL)) { + Tcl_Obj *valuePtr = mePtr->onValuePtr; + + if (valuePtr == NULL) { + valuePtr = Tcl_NewObj(); } - } else if (mePtr->type == RADIO_BUTTON_ENTRY) { - if (Tcl_SetVar(interp, mePtr->name, mePtr->onValue, + Tcl_IncrRefCount(valuePtr); + if (Tcl_ObjSetVar2(interp, mePtr->namePtr, NULL, valuePtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; } + Tcl_DecrRefCount(valuePtr); } - if ((result == TCL_OK) && (mePtr->command != NULL)) { - result = TkCopyAndGlobalEval(interp, mePtr->command); + if ((result == TCL_OK) && (mePtr->commandPtr != NULL)) { + Tcl_Obj *commandPtr = mePtr->commandPtr; + + Tcl_IncrRefCount(commandPtr); + result = Tcl_EvalObjEx(interp, commandPtr, TCL_EVAL_GLOBAL); + Tcl_DecrRefCount(commandPtr); } Tcl_Release((ClientData) mePtr); done: return result; } - - /* *---------------------------------------------------------------------- @@ -951,13 +1143,12 @@ static void DestroyMenuInstance(menuPtr) TkMenu *menuPtr; /* Info about menu widget. */ { - int i, numEntries = menuPtr->numEntries; + int i; TkMenu *menuInstancePtr; TkMenuEntry *cascadePtr, *nextCascadePtr; - char *newArgv[2]; + Tcl_Obj *newObjv[2]; TkMenu *parentMasterMenuPtr; TkMenuEntry *parentMasterEntryPtr; - TkMenu *parentMenuPtr; /* * If the menu has any cascade menu entries pointing to it, the cascade @@ -979,18 +1170,29 @@ DestroyMenuInstance(menuPtr) TkFreeMenuReferences(menuPtr->menuRefPtr); for (; cascadePtr != NULL; cascadePtr = nextCascadePtr) { - parentMenuPtr = cascadePtr->menuPtr; nextCascadePtr = cascadePtr->nextCascadePtr; if (menuPtr->masterMenuPtr != menuPtr) { + Tcl_Obj *menuNamePtr = Tcl_NewStringObj("-menu", -1); + parentMasterMenuPtr = cascadePtr->menuPtr->masterMenuPtr; parentMasterEntryPtr = parentMasterMenuPtr->entries[cascadePtr->index]; - newArgv[0] = "-menu"; - newArgv[1] = parentMasterEntryPtr->name; - ConfigureMenuEntry(cascadePtr, 2, newArgv, TK_CONFIG_ARGV_ONLY); + newObjv[0] = menuNamePtr; + newObjv[1] = parentMasterEntryPtr->namePtr; + /* + * It is possible that the menu info is out of sync, and + * these things point to NULL, so verify existence [Bug: 3402] + */ + if (newObjv[0] && newObjv[1]) { + Tcl_IncrRefCount(newObjv[0]); + Tcl_IncrRefCount(newObjv[1]); + ConfigureMenuEntry(cascadePtr, 2, newObjv); + Tcl_DecrRefCount(newObjv[0]); + Tcl_DecrRefCount(newObjv[1]); + } } else { - ConfigureMenuEntry(cascadePtr, 0, (char **) NULL, 0); + ConfigureMenuEntry(cascadePtr, 0, (Tcl_Obj **) NULL); } } @@ -1010,20 +1212,27 @@ DestroyMenuInstance(menuPtr) /* * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related + * let Tk_FreeConfigOptions handle all the standard option-related * stuff. */ - for (i = numEntries - 1; i >= 0; i--) { + for (i = menuPtr->numEntries; --i >= 0; ) { + /* + * As each menu entry is deleted from the end of the array of + * entries, decrement menuPtr->numEntries. Otherwise, the act of + * deleting menu entry i will dereference freed memory attempting + * to queue a redraw for menu entries (i+1)...numEntries. + */ + DestroyMenuEntry((char *) menuPtr->entries[i]); + menuPtr->numEntries = i; } if (menuPtr->entries != NULL) { ckfree((char *) menuPtr->entries); } TkMenuFreeDrawOptions(menuPtr); - Tk_FreeOptions(tkMenuConfigSpecs, (char *) menuPtr, menuPtr->display, 0); - - Tcl_EventuallyFree((ClientData) menuPtr, TCL_DYNAMIC); + Tk_FreeConfigOptions((char *) menuPtr, + menuPtr->optionTablesPtr->menuOptionTable, menuPtr->tkwin); } /* @@ -1202,7 +1411,7 @@ DestroyMenuEntry(memPtr) /* * Free up all the stuff that requires special handling, then - * let Tk_FreeOptions handle all the standard option-related + * let Tk_FreeConfigOptions handle all the standard option-related * stuff. */ @@ -1215,15 +1424,17 @@ DestroyMenuEntry(memPtr) if (mePtr->selectImage != NULL) { Tk_FreeImage(mePtr->selectImage); } - if (mePtr->name != NULL) { - Tcl_UntraceVar(menuPtr->interp, mePtr->name, + if (((mePtr->type == CHECK_BUTTON_ENTRY) + || (mePtr->type == RADIO_BUTTON_ENTRY)) + && (mePtr->namePtr != NULL)) { + char *varName = Tcl_GetStringFromObj(mePtr->namePtr, NULL); + Tcl_UntraceVar(menuPtr->interp, varName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuVarProc, (ClientData) mePtr); } TkpDestroyMenuEntry(mePtr); TkMenuEntryFreeDrawOptions(mePtr); - Tk_FreeOptions(tkMenuEntryConfigSpecs, (char *) mePtr, menuPtr->display, - (COMMAND_MASK << mePtr->type)); + Tk_FreeConfigOptions((char *) mePtr, mePtr->optionTable, menuPtr->tkwin); ckfree((char *) mePtr); } @@ -1259,7 +1470,6 @@ MenuWorldChanged(instanceData) TkpConfigureMenuEntry(menuPtr->entries[i]); } } - /* *---------------------------------------------------------------------- @@ -1272,7 +1482,7 @@ MenuWorldChanged(instanceData) * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as colors, font, etc. get set @@ -1282,23 +1492,32 @@ MenuWorldChanged(instanceData) */ static int -ConfigureMenu(interp, menuPtr, argc, argv, flags) +ConfigureMenu(interp, menuPtr, objc, objv) Tcl_Interp *interp; /* Used for error reporting. */ register TkMenu *menuPtr; /* Information about widget; may or may * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ + int objc; /* Number of valid entries in argv. */ + Tcl_Obj *CONST objv[]; /* Arguments. */ { int i; - TkMenu* menuListPtr; + TkMenu *menuListPtr, *cleanupPtr; + int result; for (menuListPtr = menuPtr->masterMenuPtr; menuListPtr != NULL; menuListPtr = menuListPtr->nextInstancePtr) { - - if (Tk_ConfigureWidget(interp, menuListPtr->tkwin, - tkMenuConfigSpecs, argc, argv, (char *) menuListPtr, - flags) != TCL_OK) { + menuListPtr->errorStructPtr = (Tk_SavedOptions *) + ckalloc(sizeof(Tk_SavedOptions)); + result = Tk_SetOptions(interp, (char *) menuListPtr, + menuListPtr->optionTablesPtr->menuOptionTable, objc, objv, + menuListPtr->tkwin, menuListPtr->errorStructPtr, (int *) NULL); + if (result != TCL_OK) { + for (cleanupPtr = menuPtr->masterMenuPtr; + cleanupPtr != menuListPtr; + cleanupPtr = cleanupPtr->nextInstancePtr) { + Tk_RestoreSavedOptions(cleanupPtr->errorStructPtr); + ckfree((char *) cleanupPtr->errorStructPtr); + cleanupPtr->errorStructPtr = NULL; + } return TCL_ERROR; } @@ -1310,33 +1529,57 @@ ConfigureMenu(interp, menuPtr, argc, argv, flags) */ if (menuListPtr->menuType == UNKNOWN_TYPE) { - if (strcmp(menuListPtr->menuTypeName, "menubar") == 0) { - menuListPtr->menuType = MENUBAR; - } else if (strcmp(menuListPtr->menuTypeName, "tearoff") == 0) { - menuListPtr->menuType = TEAROFF_MENU; - } else { - menuListPtr->menuType = MASTER_MENU; + Tcl_GetIndexFromObj(NULL, menuListPtr->menuTypePtr, + menuTypeStrings, NULL, 0, &menuListPtr->menuType); + + /* + * Configure the new window to be either a pop-up menu + * or a tear-off menu. + * We don't do this for menubars since they are not toplevel + * windows. Also, since this gets called before CloneMenu has + * a chance to set the menuType field, we have to look at the + * menuTypeName field to tell that this is a menu bar. + */ + + if (menuListPtr->menuType == MASTER_MENU) { + TkpMakeMenuWindow(menuListPtr->tkwin, 1); + } else if (menuListPtr->menuType == TEAROFF_MENU) { + TkpMakeMenuWindow(menuListPtr->tkwin, 0); } } - + + /* * Depending on the -tearOff option, make sure that there is or * isn't an initial tear-off entry at the beginning of the menu. */ - if (menuListPtr->tearOff) { + if (menuListPtr->tearoff) { if ((menuListPtr->numEntries == 0) || (menuListPtr->entries[0]->type != TEAROFF_ENTRY)) { if (MenuNewEntry(menuListPtr, 0, TEAROFF_ENTRY) == NULL) { + if (menuListPtr->errorStructPtr != NULL) { + for (cleanupPtr = menuPtr->masterMenuPtr; + cleanupPtr != menuListPtr; + cleanupPtr = cleanupPtr->nextInstancePtr) { + Tk_RestoreSavedOptions(cleanupPtr->errorStructPtr); + ckfree((char *) cleanupPtr->errorStructPtr); + cleanupPtr->errorStructPtr = NULL; + } + Tk_RestoreSavedOptions(cleanupPtr->errorStructPtr); + ckfree((char *) cleanupPtr->errorStructPtr); + cleanupPtr->errorStructPtr = NULL; + } return TCL_ERROR; } } } else if ((menuListPtr->numEntries > 0) && (menuListPtr->entries[0]->type == TEAROFF_ENTRY)) { int i; - + Tcl_EventuallyFree((ClientData) menuListPtr->entries[0], DestroyMenuEntry); + for (i = 0; i < menuListPtr->numEntries - 1; i++) { menuListPtr->entries[i] = menuListPtr->entries[i + 1]; menuListPtr->entries[i]->index = i; @@ -1349,21 +1592,6 @@ ConfigureMenu(interp, menuPtr, argc, argv, flags) } TkMenuConfigureDrawOptions(menuListPtr); - - /* - * Configure the new window to be either a pop-up menu - * or a tear-off menu. - * We don't do this for menubars since they are not toplevel - * windows. Also, since this gets called before CloneMenu has - * a chance to set the menuType field, we have to look at the - * menuTypeName field to tell that this is a menu bar. - */ - - if (strcmp(menuListPtr->menuTypeName, "normal") == 0) { - TkpMakeMenuWindow(menuListPtr->tkwin, 1); - } else if (strcmp(menuListPtr->menuTypeName, "tearoff") == 0) { - TkpMakeMenuWindow(menuListPtr->tkwin, 0); - } /* * After reconfiguring a menu, we need to reconfigure all of the @@ -1376,28 +1604,35 @@ ConfigureMenu(interp, menuPtr, argc, argv, flags) TkMenuEntry *mePtr; mePtr = menuListPtr->entries[i]; - ConfigureMenuEntry(mePtr, 0, - (char **) NULL, TK_CONFIG_ARGV_ONLY - | COMMAND_MASK << mePtr->type); + ConfigureMenuEntry(mePtr, 0, (Tcl_Obj **) NULL); } TkEventuallyRecomputeMenu(menuListPtr); } + for (cleanupPtr = menuPtr->masterMenuPtr; cleanupPtr != NULL; + cleanupPtr = cleanupPtr->nextInstancePtr) { + Tk_FreeSavedOptions(cleanupPtr->errorStructPtr); + ckfree((char *) cleanupPtr->errorStructPtr); + cleanupPtr->errorStructPtr = NULL; + } + return TCL_OK; } + /* *---------------------------------------------------------------------- * - * ConfigureMenuEntry -- + * PostProcessEntry -- * - * This procedure is called to process an argv/argc list in order - * to configure (or reconfigure) one entry in a menu. + * This is called by ConfigureMenuEntry to do all of the configuration + * after Tk_SetOptions is called. This is separate + * so that error handling is easier. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information such as label and accelerator get @@ -1407,55 +1642,29 @@ ConfigureMenu(interp, menuPtr, argc, argv, flags) */ static int -ConfigureMenuEntry(mePtr, argc, argv, flags) - register TkMenuEntry *mePtr; /* Information about menu entry; may - * or may not already have values for - * some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Additional flags to pass to - * Tk_ConfigureWidget. */ +PostProcessEntry(mePtr) + TkMenuEntry *mePtr; /* The entry we are configuring. */ { TkMenu *menuPtr = mePtr->menuPtr; int index = mePtr->index; + char *name; Tk_Image image; /* - * If this entry is a check button or radio button, then remove - * its old trace procedure. - */ - - if ((mePtr->name != NULL) - && ((mePtr->type == CHECK_BUTTON_ENTRY) - || (mePtr->type == RADIO_BUTTON_ENTRY))) { - Tcl_UntraceVar(menuPtr->interp, mePtr->name, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MenuVarProc, (ClientData) mePtr); - } - - if (menuPtr->tkwin != NULL) { - if (Tk_ConfigureWidget(menuPtr->interp, menuPtr->tkwin, - tkMenuEntryConfigSpecs, argc, argv, (char *) mePtr, - flags | (COMMAND_MASK << mePtr->type)) != TCL_OK) { - return TCL_ERROR; - } - } - - /* * The code below handles special configuration stuff not taken * care of by Tk_ConfigureWidget, such as special processing for * defaults, sizing strings, graphics contexts, etc. */ - if (mePtr->label == NULL) { + if (mePtr->labelPtr == NULL) { mePtr->labelLength = 0; } else { - mePtr->labelLength = strlen(mePtr->label); + Tcl_GetStringFromObj(mePtr->labelPtr, &mePtr->labelLength); } - if (mePtr->accel == NULL) { + if (mePtr->accelPtr == NULL) { mePtr->accelLength = 0; } else { - mePtr->accelLength = strlen(mePtr->accel); + Tcl_GetStringFromObj(mePtr->accelPtr, &mePtr->accelLength); } /* @@ -1464,9 +1673,8 @@ ConfigureMenuEntry(mePtr, argc, argv, flags) * cascades have to be updated. */ - if ((mePtr->type == CASCADE_ENTRY) && (mePtr->name != NULL)) { + if ((mePtr->type == CASCADE_ENTRY) && (mePtr->namePtr != NULL)) { TkMenuEntry *cascadeEntryPtr; - TkMenu *cascadeMenuPtr; int alreadyThere; TkMenuReferences *menuRefPtr; char *oldHashKey = NULL; /* Initialization only needed to @@ -1482,19 +1690,18 @@ ConfigureMenuEntry(mePtr, argc, argv, flags) * BUG: We are not recloning for special case #3 yet. */ + name = Tcl_GetStringFromObj(mePtr->namePtr, NULL); if (mePtr->childMenuRefPtr != NULL) { oldHashKey = Tcl_GetHashKey(TkGetMenuHashTable(menuPtr->interp), mePtr->childMenuRefPtr->hashEntryPtr); - if (strcmp(oldHashKey, mePtr->name) != 0) { + if (strcmp(oldHashKey, name) != 0) { UnhookCascadeEntry(mePtr); } } if ((mePtr->childMenuRefPtr == NULL) - || (strcmp(oldHashKey, mePtr->name) != 0)) { - menuRefPtr = TkCreateMenuReferences(menuPtr->interp, - mePtr->name); - cascadeMenuPtr = menuRefPtr->menuPtr; + || (strcmp(oldHashKey, name) != 0)) { + menuRefPtr = TkCreateMenuReferences(menuPtr->interp, name); mePtr->childMenuRefPtr = menuRefPtr; if (menuRefPtr->parentEntryPtr == NULL) { @@ -1531,52 +1738,15 @@ ConfigureMenuEntry(mePtr, argc, argv, flags) return TCL_ERROR; } - if ((mePtr->type == CHECK_BUTTON_ENTRY) - || (mePtr->type == RADIO_BUTTON_ENTRY)) { - char *value; - - if (mePtr->name == NULL) { - mePtr->name = - (char *) ckalloc((unsigned) (mePtr->labelLength + 1)); - strcpy(mePtr->name, (mePtr->label == NULL) ? "" : mePtr->label); - } - if (mePtr->onValue == NULL) { - mePtr->onValue = (char *) ckalloc((unsigned) - (mePtr->labelLength + 1)); - strcpy(mePtr->onValue, (mePtr->label == NULL) ? "" : mePtr->label); - } - - /* - * Select the entry if the associated variable has the - * appropriate value, initialize the variable if it doesn't - * exist, then set a trace on the variable to monitor future - * changes to its value. - */ - - value = Tcl_GetVar(menuPtr->interp, mePtr->name, TCL_GLOBAL_ONLY); - mePtr->entryFlags &= ~ENTRY_SELECTED; - if (value != NULL) { - if (strcmp(value, mePtr->onValue) == 0) { - mePtr->entryFlags |= ENTRY_SELECTED; - } - } else { - Tcl_SetVar(menuPtr->interp, mePtr->name, - (mePtr->type == CHECK_BUTTON_ENTRY) ? mePtr->offValue : "", - TCL_GLOBAL_ONLY); - } - Tcl_TraceVar(menuPtr->interp, mePtr->name, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MenuVarProc, (ClientData) mePtr); - } - /* * Get the images for the entry, if there are any. Allocate the * new images before freeing the old ones, so that the reference * counts don't go to zero and cause image data to be discarded. */ - if (mePtr->imageString != NULL) { - image = Tk_GetImage(menuPtr->interp, menuPtr->tkwin, mePtr->imageString, + if (mePtr->imagePtr != NULL) { + char *imageString = Tcl_GetStringFromObj(mePtr->imagePtr, NULL); + image = Tk_GetImage(menuPtr->interp, menuPtr->tkwin, imageString, TkMenuImageProc, (ClientData) mePtr); if (image == NULL) { return TCL_ERROR; @@ -1588,8 +1758,10 @@ ConfigureMenuEntry(mePtr, argc, argv, flags) Tk_FreeImage(mePtr->image); } mePtr->image = image; - if (mePtr->selectImageString != NULL) { - image = Tk_GetImage(menuPtr->interp, menuPtr->tkwin, mePtr->selectImageString, + if (mePtr->selectImagePtr != NULL) { + char *selectImageString = Tcl_GetStringFromObj( + mePtr->selectImagePtr, NULL); + image = Tk_GetImage(menuPtr->interp, menuPtr->tkwin, selectImageString, TkMenuSelectImageProc, (ClientData) mePtr); if (image == NULL) { return TCL_ERROR; @@ -1602,7 +1774,69 @@ ConfigureMenuEntry(mePtr, argc, argv, flags) } mePtr->selectImage = image; - TkEventuallyRecomputeMenu(menuPtr); + if ((mePtr->type == CHECK_BUTTON_ENTRY) + || (mePtr->type == RADIO_BUTTON_ENTRY)) { + Tcl_Obj *valuePtr; + char *name; + + if (mePtr->namePtr == NULL) { + if (mePtr->labelPtr == NULL) { + mePtr->namePtr = NULL; + } else { + mePtr->namePtr = Tcl_DuplicateObj(mePtr->labelPtr); + Tcl_IncrRefCount(mePtr->namePtr); + } + } + if (mePtr->onValuePtr == NULL) { + if (mePtr->labelPtr == NULL) { + mePtr->onValuePtr = NULL; + } else { + mePtr->onValuePtr = Tcl_DuplicateObj(mePtr->labelPtr); + Tcl_IncrRefCount(mePtr->onValuePtr); + } + } + + /* + * Select the entry if the associated variable has the + * appropriate value, initialize the variable if it doesn't + * exist, then set a trace on the variable to monitor future + * changes to its value. + */ + + if (mePtr->namePtr != NULL) { + valuePtr = Tcl_ObjGetVar2(menuPtr->interp, mePtr->namePtr, NULL, + TCL_GLOBAL_ONLY); + } else { + valuePtr = NULL; + } + mePtr->entryFlags &= ~ENTRY_SELECTED; + if (valuePtr != NULL) { + if (mePtr->onValuePtr != NULL) { + char *value = Tcl_GetStringFromObj(valuePtr, NULL); + char *onValue = Tcl_GetStringFromObj(mePtr->onValuePtr, + NULL); + + + if (strcmp(value, onValue) == 0) { + mePtr->entryFlags |= ENTRY_SELECTED; + } + } + } else { + if (mePtr->namePtr != NULL) { + Tcl_ObjSetVar2(menuPtr->interp, mePtr->namePtr, NULL, + (mePtr->type == CHECK_BUTTON_ENTRY) + ? mePtr->offValuePtr + : Tcl_NewObj(), + TCL_GLOBAL_ONLY); + } + } + if (mePtr->namePtr != NULL) { + name = Tcl_GetStringFromObj(mePtr->namePtr, NULL); + Tcl_TraceVar(menuPtr->interp, name, + TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + MenuVarProc, (ClientData) mePtr); + } + } return TCL_OK; } @@ -1610,13 +1844,78 @@ ConfigureMenuEntry(mePtr, argc, argv, flags) /* *---------------------------------------------------------------------- * + * ConfigureMenuEntry -- + * + * This procedure is called to process an argv/argc list in order + * to configure (or reconfigure) one entry in a menu. + * + * Results: + * The return value is a standard Tcl result. If TCL_ERROR is + * returned, then the interp's result contains an error message. + * + * Side effects: + * Configuration information such as label and accelerator get + * set for mePtr; old resources get freed, if there were any. + * + *---------------------------------------------------------------------- + */ + +static int +ConfigureMenuEntry(mePtr, objc, objv) + register TkMenuEntry *mePtr; /* Information about menu entry; may + * or may not already have values for + * some fields. */ + int objc; /* Number of valid entries in argv. */ + Tcl_Obj *CONST objv[]; /* Arguments. */ +{ + TkMenu *menuPtr = mePtr->menuPtr; + Tk_SavedOptions errorStruct; + int result; + + /* + * If this entry is a check button or radio button, then remove + * its old trace procedure. + */ + + if ((mePtr->namePtr != NULL) + && ((mePtr->type == CHECK_BUTTON_ENTRY) + || (mePtr->type == RADIO_BUTTON_ENTRY))) { + char *name = Tcl_GetStringFromObj(mePtr->namePtr, NULL); + Tcl_UntraceVar(menuPtr->interp, name, + TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + MenuVarProc, (ClientData) mePtr); + } + + result = TCL_OK; + if (menuPtr->tkwin != NULL) { + if (Tk_SetOptions(menuPtr->interp, (char *) mePtr, + mePtr->optionTable, objc, objv, menuPtr->tkwin, + &errorStruct, (int *) NULL) != TCL_OK) { + return TCL_ERROR; + } + result = PostProcessEntry(mePtr); + if (result != TCL_OK) { + Tk_RestoreSavedOptions(&errorStruct); + PostProcessEntry(mePtr); + } + Tk_FreeSavedOptions(&errorStruct); + } + + TkEventuallyRecomputeMenu(menuPtr); + + return result; +} + +/* + *---------------------------------------------------------------------- + * * ConfigureMenuCloneEntries -- * * Calls ConfigureMenuEntry for each menu in the clone chain. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information such as label and accelerator get @@ -1626,22 +1925,21 @@ ConfigureMenuEntry(mePtr, argc, argv, flags) */ static int -ConfigureMenuCloneEntries(interp, menuPtr, index, argc, argv, flags) +ConfigureMenuCloneEntries(interp, menuPtr, index, objc, objv) Tcl_Interp *interp; /* Used for error reporting. */ TkMenu *menuPtr; /* Information about whole menu. */ int index; /* Index of mePtr within menuPtr's * entries. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Additional flags to pass to - * Tk_ConfigureWidget. */ + int objc; /* Number of valid entries in argv. */ + Tcl_Obj *CONST objv[]; /* Arguments. */ { TkMenuEntry *mePtr; TkMenu *menuListPtr; - char *oldCascadeName = NULL, *newMenuName = NULL; - int cascadeEntryChanged; + int cascadeEntryChanged = 0; TkMenuReferences *oldCascadeMenuRefPtr, *cascadeMenuRefPtr = NULL; - + Tcl_Obj *oldCascadePtr = NULL; + char *newCascadeName; + /* * Cascades are kind of tricky here. This is special case #3 in the comment * at the top of this file. Basically, if a menu is the master menu of a @@ -1653,21 +1951,47 @@ ConfigureMenuCloneEntries(interp, menuPtr, index, argc, argv, flags) mePtr = menuPtr->masterMenuPtr->entries[index]; if (mePtr->type == CASCADE_ENTRY) { - oldCascadeName = mePtr->name; + oldCascadePtr = mePtr->namePtr; + if (oldCascadePtr != NULL) { + Tcl_IncrRefCount(oldCascadePtr); + } } - if (ConfigureMenuEntry(mePtr, argc, argv, flags) != TCL_OK) { + if (ConfigureMenuEntry(mePtr, objc, objv) != TCL_OK) { return TCL_ERROR; } - cascadeEntryChanged = (mePtr->type == CASCADE_ENTRY) - && (oldCascadeName != mePtr->name); + if (mePtr->type == CASCADE_ENTRY) { + char *oldCascadeName; + + if (mePtr->namePtr != NULL) { + newCascadeName = Tcl_GetStringFromObj(mePtr->namePtr, NULL); + } else { + newCascadeName = NULL; + } + + if ((oldCascadePtr == NULL) && (mePtr->namePtr == NULL)) { + cascadeEntryChanged = 0; + } else if (((oldCascadePtr == NULL) && (mePtr->namePtr != NULL)) + || ((oldCascadePtr != NULL) + && (mePtr->namePtr == NULL))) { + cascadeEntryChanged = 1; + } else { + oldCascadeName = Tcl_GetStringFromObj(oldCascadePtr, + NULL); + cascadeEntryChanged = (strcmp(oldCascadeName, newCascadeName) + == 0); + } + if (oldCascadePtr != NULL) { + Tcl_DecrRefCount(oldCascadePtr); + } + } if (cascadeEntryChanged) { - newMenuName = mePtr->name; - if (newMenuName != NULL) { + if (mePtr->namePtr != NULL) { + newCascadeName = Tcl_GetStringFromObj(mePtr->namePtr, NULL); cascadeMenuRefPtr = TkFindMenuReferences(menuPtr->interp, - mePtr->name); + newCascadeName); } } @@ -1677,9 +2001,9 @@ ConfigureMenuCloneEntries(interp, menuPtr, index, argc, argv, flags) mePtr = menuListPtr->entries[index]; - if (cascadeEntryChanged && (mePtr->name != NULL)) { - oldCascadeMenuRefPtr = TkFindMenuReferences(menuPtr->interp, - mePtr->name); + if (cascadeEntryChanged && (mePtr->namePtr != NULL)) { + oldCascadeMenuRefPtr = TkFindMenuReferencesObj(menuPtr->interp, + mePtr->namePtr); if ((oldCascadeMenuRefPtr != NULL) && (oldCascadeMenuRefPtr->menuPtr != NULL)) { @@ -1687,25 +2011,36 @@ ConfigureMenuCloneEntries(interp, menuPtr, index, argc, argv, flags) } } - if (ConfigureMenuEntry(mePtr, argc, argv, flags) != TCL_OK) { + if (ConfigureMenuEntry(mePtr, objc, objv) != TCL_OK) { return TCL_ERROR; } - if (cascadeEntryChanged && (newMenuName != NULL)) { + if (cascadeEntryChanged && (mePtr->namePtr != NULL)) { if (cascadeMenuRefPtr->menuPtr != NULL) { - char *newArgV[2]; - char *newCloneName; - - newCloneName = TkNewMenuName(menuPtr->interp, - Tk_PathName(menuListPtr->tkwin), + Tcl_Obj *newObjv[2]; + Tcl_Obj *newCloneNamePtr; + Tcl_Obj *pathNamePtr = Tcl_NewStringObj( + Tk_PathName(menuListPtr->tkwin), -1); + Tcl_Obj *normalPtr = Tcl_NewStringObj("normal", -1); + Tcl_Obj *menuObjPtr = Tcl_NewStringObj("-menu", -1); + + Tcl_IncrRefCount(pathNamePtr); + newCloneNamePtr = TkNewMenuName(menuPtr->interp, + pathNamePtr, cascadeMenuRefPtr->menuPtr); - CloneMenu(cascadeMenuRefPtr->menuPtr, newCloneName, - "normal"); - - newArgV[0] = "-menu"; - newArgV[1] = newCloneName; - ConfigureMenuEntry(mePtr, 2, newArgV, flags); - ckfree(newCloneName); + Tcl_IncrRefCount(newCloneNamePtr); + Tcl_IncrRefCount(normalPtr); + CloneMenu(cascadeMenuRefPtr->menuPtr, newCloneNamePtr, + normalPtr); + + newObjv[0] = menuObjPtr; + newObjv[1] = newCloneNamePtr; + Tcl_IncrRefCount(menuObjPtr); + ConfigureMenuEntry(mePtr, 2, newObjv); + Tcl_DecrRefCount(newCloneNamePtr); + Tcl_DecrRefCount(pathNamePtr); + Tcl_DecrRefCount(normalPtr); + Tcl_DecrRefCount(menuObjPtr); } } } @@ -1724,7 +2059,7 @@ ConfigureMenuCloneEntries(interp, menuPtr, index, argc, argv, flags) * A standard Tcl result. If all went well, then *indexPtr is * filled in with the entry index corresponding to string * (ranges from -1 to the number of entries in the menu minus - * one). Otherwise an error message is left in interp->result. + * one). Otherwise an error message is left in the interp's result. * * Side effects: * None. @@ -1733,38 +2068,39 @@ ConfigureMenuCloneEntries(interp, menuPtr, index, argc, argv, flags) */ int -TkGetMenuIndex(interp, menuPtr, string, lastOK, indexPtr) +TkGetMenuIndex(interp, menuPtr, objPtr, lastOK, indexPtr) Tcl_Interp *interp; /* For error messages. */ TkMenu *menuPtr; /* Menu for which the index is being * specified. */ - char *string; /* Specification of an entry in menu. See + Tcl_Obj *objPtr; /* Specification of an entry in menu. See * manual entry for valid .*/ int lastOK; /* Non-zero means its OK to return index * just *after* last entry. */ - int *indexPtr; /* Where to store converted relief. */ + int *indexPtr; /* Where to store converted index. */ { int i; + char *string = Tcl_GetStringFromObj(objPtr, NULL); if ((string[0] == 'a') && (strcmp(string, "active") == 0)) { *indexPtr = menuPtr->active; - return TCL_OK; + goto success; } if (((string[0] == 'l') && (strcmp(string, "last") == 0)) || ((string[0] == 'e') && (strcmp(string, "end") == 0))) { *indexPtr = menuPtr->numEntries - ((lastOK) ? 0 : 1); - return TCL_OK; + goto success; } if ((string[0] == 'n') && (strcmp(string, "none") == 0)) { *indexPtr = -1; - return TCL_OK; + goto success; } if (string[0] == '@') { if (GetIndexFromCoords(interp, menuPtr, string, indexPtr) == TCL_OK) { - return TCL_OK; + goto success; } } @@ -1780,25 +2116,29 @@ TkGetMenuIndex(interp, menuPtr, string, lastOK, indexPtr) i = -1; } *indexPtr = i; - return TCL_OK; + goto success; } Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); } for (i = 0; i < menuPtr->numEntries; i++) { - char *label; - - label = menuPtr->entries[i]->label; + Tcl_Obj *labelPtr = menuPtr->entries[i]->labelPtr; + char *label = (labelPtr == NULL) ? NULL + : Tcl_GetStringFromObj(labelPtr, NULL); + if ((label != NULL) - && (Tcl_StringMatch(menuPtr->entries[i]->label, string))) { + && (Tcl_StringMatch(label, string))) { *indexPtr = i; - return TCL_OK; + goto success; } } Tcl_AppendResult(interp, "bad menu entry index \"", string, "\"", (char *) NULL); return TCL_ERROR; + +success: + return TCL_OK; } /* @@ -1834,7 +2174,6 @@ MenuCmdDeletedProc(clientData) */ if (tkwin != NULL) { - menuPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); } } @@ -1890,41 +2229,49 @@ MenuNewEntry(menuPtr, index, type) mePtr = (TkMenuEntry *) ckalloc(sizeof(TkMenuEntry)); menuPtr->entries[index] = mePtr; mePtr->type = type; + mePtr->optionTable = menuPtr->optionTablesPtr->entryOptionTables[type]; mePtr->menuPtr = menuPtr; - mePtr->label = NULL; + mePtr->labelPtr = NULL; mePtr->labelLength = 0; mePtr->underline = -1; - mePtr->bitmap = None; - mePtr->imageString = NULL; + mePtr->bitmapPtr = NULL; + mePtr->imagePtr = NULL; mePtr->image = NULL; - mePtr->selectImageString = NULL; + mePtr->selectImagePtr = NULL; mePtr->selectImage = NULL; - mePtr->accel = NULL; + mePtr->accelPtr = NULL; mePtr->accelLength = 0; - mePtr->state = tkNormalUid; - mePtr->border = NULL; - mePtr->fg = NULL; - mePtr->activeBorder = NULL; - mePtr->activeFg = NULL; - mePtr->tkfont = NULL; - mePtr->indicatorOn = 1; - mePtr->indicatorFg = NULL; + mePtr->state = ENTRY_DISABLED; + mePtr->borderPtr = NULL; + mePtr->fgPtr = NULL; + mePtr->activeBorderPtr = NULL; + mePtr->activeFgPtr = NULL; + mePtr->fontPtr = NULL; + mePtr->indicatorOn = 0; + mePtr->indicatorFgPtr = NULL; mePtr->columnBreak = 0; mePtr->hideMargin = 0; - mePtr->command = NULL; - mePtr->name = NULL; + mePtr->commandPtr = NULL; + mePtr->namePtr = NULL; mePtr->childMenuRefPtr = NULL; - mePtr->onValue = NULL; - mePtr->offValue = NULL; + mePtr->onValuePtr = NULL; + mePtr->offValuePtr = NULL; mePtr->entryFlags = 0; mePtr->index = index; mePtr->nextCascadePtr = NULL; + if (Tk_InitOptions(menuPtr->interp, (char *) mePtr, + mePtr->optionTable, menuPtr->tkwin) != TCL_OK) { + ckfree((char *) mePtr); + return NULL; + } TkMenuInitializeEntryDrawingFields(mePtr); if (TkpMenuNewEntry(mePtr) != TCL_OK) { + Tk_FreeConfigOptions((char *) mePtr, mePtr->optionTable, + menuPtr->tkwin); ckfree((char *) mePtr); return NULL; } - + return mePtr; } @@ -1946,25 +2293,24 @@ MenuNewEntry(menuPtr, index, type) */ static int -MenuAddOrInsert(interp, menuPtr, indexString, argc, argv) +MenuAddOrInsert(interp, menuPtr, indexPtr, objc, objv) Tcl_Interp *interp; /* Used for error reporting. */ TkMenu *menuPtr; /* Widget in which to create new * entry. */ - char *indexString; /* String describing index at which + Tcl_Obj *indexPtr; /* Object describing index at which * to insert. NULL means insert at * end. */ - int argc; /* Number of elements in argv. */ - char **argv; /* Arguments to command: first arg + int objc; /* Number of elements in objv. */ + Tcl_Obj *CONST objv[]; /* Arguments to command: first arg * is type of entry, others are * config options. */ { - int c, type, index; - size_t length; + int type, index; TkMenuEntry *mePtr; TkMenu *menuListPtr; - if (indexString != NULL) { - if (TkGetMenuIndex(interp, menuPtr, indexString, 1, &index) + if (indexPtr != NULL) { + if (TkGetMenuIndex(interp, menuPtr, indexPtr, 1, &index) != TCL_OK) { return TCL_ERROR; } @@ -1972,11 +2318,12 @@ MenuAddOrInsert(interp, menuPtr, indexString, argc, argv) index = menuPtr->numEntries; } if (index < 0) { + char *indexString = Tcl_GetStringFromObj(indexPtr, NULL); Tcl_AppendResult(interp, "bad index \"", indexString, "\"", (char *) NULL); return TCL_ERROR; } - if (menuPtr->tearOff && (index == 0)) { + if (menuPtr->tearoff && (index == 0)) { index = 1; } @@ -1984,30 +2331,11 @@ MenuAddOrInsert(interp, menuPtr, indexString, argc, argv) * Figure out the type of the new entry. */ - c = argv[0][0]; - length = strlen(argv[0]); - if ((c == 'c') && (strncmp(argv[0], "cascade", length) == 0) - && (length >= 2)) { - type = CASCADE_ENTRY; - } else if ((c == 'c') && (strncmp(argv[0], "checkbutton", length) == 0) - && (length >= 2)) { - type = CHECK_BUTTON_ENTRY; - } else if ((c == 'c') && (strncmp(argv[0], "command", length) == 0) - && (length >= 2)) { - type = COMMAND_ENTRY; - } else if ((c == 'r') - && (strncmp(argv[0], "radiobutton", length) == 0)) { - type = RADIO_BUTTON_ENTRY; - } else if ((c == 's') - && (strncmp(argv[0], "separator", length) == 0)) { - type = SEPARATOR_ENTRY; - } else { - Tcl_AppendResult(interp, "bad menu entry type \"", - argv[0], "\": must be cascade, checkbutton, ", - "command, radiobutton, or separator", (char *) NULL); + if (Tcl_GetIndexFromObj(interp, objv[0], menuEntryTypeStrings, + "menu entry type", 0, &type) != TCL_OK) { return TCL_ERROR; } - + /* * Now we have to add an entry for every instance related to this menu. */ @@ -2019,9 +2347,9 @@ MenuAddOrInsert(interp, menuPtr, indexString, argc, argv) if (mePtr == NULL) { return TCL_ERROR; } - if (ConfigureMenuEntry(mePtr, argc-1, argv+1, 0) != TCL_OK) { + if (ConfigureMenuEntry(mePtr, objc - 1, objv + 1) != TCL_OK) { TkMenu *errorMenuPtr; - int i; + int i; for (errorMenuPtr = menuPtr->masterMenuPtr; errorMenuPtr != NULL; @@ -2054,28 +2382,40 @@ MenuAddOrInsert(interp, menuPtr, indexString, argc, argv) */ if ((menuPtr != menuListPtr) && (type == CASCADE_ENTRY)) { - if ((mePtr->name != NULL) && (mePtr->childMenuRefPtr != NULL) + if ((mePtr->namePtr != NULL) + && (mePtr->childMenuRefPtr != NULL) && (mePtr->childMenuRefPtr->menuPtr != NULL)) { TkMenu *cascadeMenuPtr = mePtr->childMenuRefPtr->menuPtr->masterMenuPtr; - char *newCascadeName; - char *newArgv[2]; + Tcl_Obj *newCascadePtr; + Tcl_Obj *menuNamePtr = Tcl_NewStringObj("-menu", -1); + Tcl_Obj *windowNamePtr = + Tcl_NewStringObj(Tk_PathName(menuListPtr->tkwin), -1); + Tcl_Obj *normalPtr = Tcl_NewStringObj("normal", -1); + Tcl_Obj *newObjv[2]; TkMenuReferences *menuRefPtr; - - newCascadeName = TkNewMenuName(menuListPtr->interp, - Tk_PathName(menuListPtr->tkwin), - cascadeMenuPtr); - CloneMenu(cascadeMenuPtr, newCascadeName, "normal"); + + Tcl_IncrRefCount(windowNamePtr); + newCascadePtr = TkNewMenuName(menuListPtr->interp, + windowNamePtr, cascadeMenuPtr); + Tcl_IncrRefCount(newCascadePtr); + Tcl_IncrRefCount(normalPtr); + CloneMenu(cascadeMenuPtr, newCascadePtr, normalPtr); - menuRefPtr = TkFindMenuReferences(menuListPtr->interp, - newCascadeName); + menuRefPtr = TkFindMenuReferencesObj(menuListPtr->interp, + newCascadePtr); if (menuRefPtr == NULL) { panic("CloneMenu failed inside of MenuAddOrInsert."); } - newArgv[0] = "-menu"; - newArgv[1] = newCascadeName; - ConfigureMenuEntry(mePtr, 2, newArgv, 0); - ckfree(newCascadeName); + newObjv[0] = menuNamePtr; + newObjv[1] = newCascadePtr; + Tcl_IncrRefCount(menuNamePtr); + Tcl_IncrRefCount(newCascadePtr); + ConfigureMenuEntry(mePtr, 2, newObjv); + Tcl_DecrRefCount(newCascadePtr); + Tcl_DecrRefCount(menuNamePtr); + Tcl_DecrRefCount(windowNamePtr); + Tcl_DecrRefCount(normalPtr); } } } @@ -2112,6 +2452,8 @@ MenuVarProc(clientData, interp, name1, name2, flags) TkMenuEntry *mePtr = (TkMenuEntry *) clientData; TkMenu *menuPtr; char *value; + char *name = Tcl_GetStringFromObj(mePtr->namePtr, NULL); + char *onValue; menuPtr = mePtr->menuPtr; @@ -2123,7 +2465,7 @@ MenuVarProc(clientData, interp, name1, name2, flags) if (flags & TCL_TRACE_UNSETS) { mePtr->entryFlags &= ~ENTRY_SELECTED; if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { - Tcl_TraceVar(interp, mePtr->name, + Tcl_TraceVar(interp, name, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuVarProc, clientData); } @@ -2137,17 +2479,22 @@ MenuVarProc(clientData, interp, name1, name2, flags) * the menu entry. */ - value = Tcl_GetVar(interp, mePtr->name, TCL_GLOBAL_ONLY); + value = Tcl_GetVar(interp, name, TCL_GLOBAL_ONLY); if (value == NULL) { value = ""; } - if (strcmp(value, mePtr->onValue) == 0) { - if (mePtr->entryFlags & ENTRY_SELECTED) { + if (mePtr->onValuePtr != NULL) { + onValue = Tcl_GetStringFromObj(mePtr->onValuePtr, NULL); + if (strcmp(value, onValue) == 0) { + if (mePtr->entryFlags & ENTRY_SELECTED) { + return (char *) NULL; + } + mePtr->entryFlags |= ENTRY_SELECTED; + } else if (mePtr->entryFlags & ENTRY_SELECTED) { + mePtr->entryFlags &= ~ENTRY_SELECTED; + } else { return (char *) NULL; } - mePtr->entryFlags |= ENTRY_SELECTED; - } else if (mePtr->entryFlags & ENTRY_SELECTED) { - mePtr->entryFlags &= ~ENTRY_SELECTED; } else { return (char *) NULL; } @@ -2193,15 +2540,15 @@ TkActivateMenuEntry(menuPtr, index) * might already have been changed to disabled). */ - if (mePtr->state == tkActiveUid) { - mePtr->state = tkNormalUid; + if (mePtr->state == ENTRY_ACTIVE) { + mePtr->state = ENTRY_NORMAL; } TkEventuallyRedrawMenu(menuPtr, menuPtr->entries[menuPtr->active]); } menuPtr->active = index; if (index >= 0) { mePtr = menuPtr->entries[index]; - mePtr->state = tkActiveUid; + mePtr->state = ENTRY_ACTIVE; TkEventuallyRedrawMenu(menuPtr, mePtr); } return result; @@ -2237,9 +2584,13 @@ TkPostCommand(menuPtr) * the menu's geometry if needed. */ - if (menuPtr->postCommand != NULL) { - result = TkCopyAndGlobalEval(menuPtr->interp, - menuPtr->postCommand); + if (menuPtr->postCommandPtr != NULL) { + Tcl_Obj *postCommandPtr = menuPtr->postCommandPtr; + + Tcl_IncrRefCount(postCommandPtr); + result = Tcl_EvalObjEx(menuPtr->interp, postCommandPtr, + TCL_EVAL_GLOBAL); + Tcl_DecrRefCount(postCommandPtr); if (result != TCL_OK) { return result; } @@ -2269,64 +2620,53 @@ TkPostCommand(menuPtr) */ static int -CloneMenu(menuPtr, newMenuName, newMenuTypeString) +CloneMenu(menuPtr, newMenuNamePtr, newMenuTypePtr) TkMenu *menuPtr; /* The menu we are going to clone */ - char *newMenuName; /* The name to give the new menu */ - char *newMenuTypeString; /* What kind of menu is this, a normal menu + Tcl_Obj *newMenuNamePtr; /* The name to give the new menu */ + Tcl_Obj *newMenuTypePtr; /* What kind of menu is this, a normal menu * a menubar, or a tearoff? */ { int returnResult; - int menuType; - size_t length; + int menuType, i; TkMenuReferences *menuRefPtr; - Tcl_Obj *commandObjPtr; + Tcl_Obj *menuDupCommandArray[4]; - if (newMenuTypeString == NULL) { + if (newMenuTypePtr == NULL) { menuType = MASTER_MENU; } else { - length = strlen(newMenuTypeString); - if (strncmp(newMenuTypeString, "normal", length) == 0) { - menuType = MASTER_MENU; - } else if (strncmp(newMenuTypeString, "tearoff", length) == 0) { - menuType = TEAROFF_MENU; - } else if (strncmp(newMenuTypeString, "menubar", length) == 0) { - menuType = MENUBAR; - } else { - Tcl_AppendResult(menuPtr->interp, - "bad menu type - must be normal, tearoff, or menubar", - (char *) NULL); - return TCL_ERROR; - } + if (Tcl_GetIndexFromObj(menuPtr->interp, newMenuTypePtr, + menuTypeStrings, "menu type", 0, &menuType) != TCL_OK) { + return TCL_ERROR; + } } - commandObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); - Tcl_ListObjAppendElement(menuPtr->interp, commandObjPtr, - Tcl_NewStringObj("tkMenuDup", -1)); - Tcl_ListObjAppendElement(menuPtr->interp, commandObjPtr, - Tcl_NewStringObj(Tk_PathName(menuPtr->tkwin), -1)); - Tcl_ListObjAppendElement(menuPtr->interp, commandObjPtr, - Tcl_NewStringObj(newMenuName, -1)); - if ((newMenuTypeString == NULL) || (newMenuTypeString[0] == '\0')) { - Tcl_ListObjAppendElement(menuPtr->interp, commandObjPtr, - Tcl_NewStringObj("normal", -1)); + menuDupCommandArray[0] = Tcl_NewStringObj("tkMenuDup", -1); + menuDupCommandArray[1] = Tcl_NewStringObj(Tk_PathName(menuPtr->tkwin), -1); + menuDupCommandArray[2] = newMenuNamePtr; + if (newMenuTypePtr == NULL) { + menuDupCommandArray[3] = Tcl_NewStringObj("normal", -1); } else { - Tcl_ListObjAppendElement(menuPtr->interp, commandObjPtr, - Tcl_NewStringObj(newMenuTypeString, -1)); + menuDupCommandArray[3] = newMenuTypePtr; + } + for (i = 0; i < 4; i++) { + Tcl_IncrRefCount(menuDupCommandArray[i]); } - Tcl_IncrRefCount(commandObjPtr); Tcl_Preserve((ClientData) menuPtr); - returnResult = Tcl_EvalObj(menuPtr->interp, commandObjPtr); - Tcl_DecrRefCount(commandObjPtr); + returnResult = Tcl_EvalObjv(menuPtr->interp, 4, menuDupCommandArray, 0); + for (i = 0; i < 4; i++) { + Tcl_DecrRefCount(menuDupCommandArray[i]); + } /* * Make sure the tcl command actually created the clone. */ if ((returnResult == TCL_OK) && - ((menuRefPtr = TkFindMenuReferences(menuPtr->interp, newMenuName)) - != (TkMenuReferences *) NULL) + ((menuRefPtr = TkFindMenuReferencesObj(menuPtr->interp, + newMenuNamePtr)) != (TkMenuReferences *) NULL) && (menuPtr->numEntries == menuRefPtr->menuPtr->numEntries)) { TkMenu *newMenuPtr = menuRefPtr->menuPtr; + Tcl_Obj *newObjv[3]; char *newArgv[3]; int i, numElements; @@ -2359,8 +2699,8 @@ CloneMenu(menuPtr, newMenuName, newMenuTypeString) if (Tk_BindtagsCmd((ClientData)newMenuPtr->tkwin, newMenuPtr->interp, 2, newArgv) == TCL_OK) { char *windowName; - Tcl_Obj *bindingsPtr = - Tcl_NewStringObj(newMenuPtr->interp->result, -1); + Tcl_Obj *bindingsPtr = + Tcl_DuplicateObj(Tcl_GetObjResult(newMenuPtr->interp)); Tcl_Obj *elementPtr; Tcl_ListObjLength(newMenuPtr->interp, bindingsPtr, &numElements); @@ -2372,11 +2712,12 @@ CloneMenu(menuPtr, newMenuName, newMenuTypeString) == 0) { Tcl_Obj *newElementPtr = Tcl_NewStringObj( Tk_PathName(newMenuPtr->masterMenuPtr->tkwin), -1); + Tcl_IncrRefCount(newElementPtr); Tcl_ListObjReplace(menuPtr->interp, bindingsPtr, i + 1, 0, 1, &newElementPtr); newArgv[2] = Tcl_GetStringFromObj(bindingsPtr, NULL); - Tk_BindtagsCmd((ClientData)newMenuPtr->tkwin, - menuPtr->interp, 3, newArgv); + Tk_BindtagsCmd((ClientData)newMenuPtr->tkwin, + menuPtr->interp, 3, newArgv); break; } } @@ -2389,30 +2730,35 @@ CloneMenu(menuPtr, newMenuName, newMenuTypeString) */ for (i = 0; i < menuPtr->numEntries; i++) { - char *newCascadeName; TkMenuReferences *cascadeRefPtr; TkMenu *oldCascadePtr; if ((menuPtr->entries[i]->type == CASCADE_ENTRY) - && (menuPtr->entries[i]->name != NULL)) { + && (menuPtr->entries[i]->namePtr != NULL)) { cascadeRefPtr = - TkFindMenuReferences(menuPtr->interp, - menuPtr->entries[i]->name); + TkFindMenuReferencesObj(menuPtr->interp, + menuPtr->entries[i]->namePtr); if ((cascadeRefPtr != NULL) && (cascadeRefPtr->menuPtr)) { - char *nameString; + Tcl_Obj *windowNamePtr = + Tcl_NewStringObj(Tk_PathName(newMenuPtr->tkwin), + -1); + Tcl_Obj *newCascadePtr; oldCascadePtr = cascadeRefPtr->menuPtr; - nameString = Tk_PathName(newMenuPtr->tkwin); - newCascadeName = TkNewMenuName(menuPtr->interp, - nameString, oldCascadePtr); - CloneMenu(oldCascadePtr, newCascadeName, NULL); - - newArgv[0] = "-menu"; - newArgv[1] = newCascadeName; - ConfigureMenuEntry(newMenuPtr->entries[i], 2, newArgv, - TK_CONFIG_ARGV_ONLY); - ckfree(newCascadeName); + Tcl_IncrRefCount(windowNamePtr); + newCascadePtr = TkNewMenuName(menuPtr->interp, + windowNamePtr, oldCascadePtr); + Tcl_IncrRefCount(newCascadePtr); + CloneMenu(oldCascadePtr, newCascadePtr, NULL); + + newObjv[0] = Tcl_NewStringObj("-menu", -1); + newObjv[1] = newCascadePtr; + Tcl_IncrRefCount(newObjv[0]); + ConfigureMenuEntry(newMenuPtr->entries[i], 2, newObjv); + Tcl_DecrRefCount(newObjv[0]); + Tcl_DecrRefCount(newCascadePtr); + Tcl_DecrRefCount(windowNamePtr); } } } @@ -2442,22 +2788,24 @@ CloneMenu(menuPtr, newMenuName, newMenuTypeString) */ static int -MenuDoYPosition(interp, menuPtr, arg) +MenuDoYPosition(interp, menuPtr, objPtr) Tcl_Interp *interp; TkMenu *menuPtr; - char *arg; + Tcl_Obj *objPtr; { int index; TkRecomputeMenu(menuPtr); - if (TkGetMenuIndex(interp, menuPtr, arg, 0, &index) != TCL_OK) { + if (TkGetMenuIndex(interp, menuPtr, objPtr, 0, &index) != TCL_OK) { goto error; } + Tcl_ResetResult(interp); if (index < 0) { - interp->result = "0"; + Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); } else { - sprintf(interp->result, "%d", menuPtr->entries[index]->y); + Tcl_SetObjResult(interp, Tcl_NewIntObj(menuPtr->entries[index]->y)); } + return TCL_OK; error: @@ -2507,7 +2855,8 @@ GetIndexFromCoords(interp, menuPtr, string, indexPtr) goto error; } } else { - x = menuPtr->borderWidth; + Tk_GetPixelsFromObj(interp, menuPtr->tkwin, + menuPtr->borderWidthPtr, &x); } for (i = 0; i < menuPtr->numEntries; i++) { @@ -2583,65 +2932,66 @@ RecursivelyDeleteMenu(menuPtr) *---------------------------------------------------------------------- */ -char * -TkNewMenuName(interp, parentName, menuPtr) +Tcl_Obj * +TkNewMenuName(interp, parentPtr, menuPtr) Tcl_Interp *interp; /* The interp the new name has to live in.*/ - char *parentName; /* The prefix path of the new name. */ + Tcl_Obj *parentPtr; /* The prefix path of the new name. */ TkMenu *menuPtr; /* The menu we are cloning. */ { - Tcl_DString resultDString; - Tcl_DString childDString; + Tcl_Obj *resultPtr = NULL; /* Initialization needed only to prevent + * compiler warning. */ + Tcl_Obj *childPtr; char *destString; - int offset, i; - int doDot = parentName[strlen(parentName) - 1] != '.'; + int i; + int doDot; Tcl_CmdInfo cmdInfo; - char *returnString; Tcl_HashTable *nameTablePtr = NULL; TkWindow *winPtr = (TkWindow *) menuPtr->tkwin; + char *parentName = Tcl_GetStringFromObj(parentPtr, NULL); + if (winPtr->mainPtr != NULL) { nameTablePtr = &(winPtr->mainPtr->nameTable); } - - Tcl_DStringInit(&childDString); - Tcl_DStringAppend(&childDString, Tk_PathName(menuPtr->tkwin), -1); - for (destString = Tcl_DStringValue(&childDString); + + doDot = parentName[strlen(parentName) - 1] != '.'; + + childPtr = Tcl_NewStringObj(Tk_PathName(menuPtr->tkwin), -1); + for (destString = Tcl_GetStringFromObj(childPtr, NULL); *destString != '\0'; destString++) { if (*destString == '.') { *destString = '#'; } } - offset = 0; - for (i = 0; ; i++) { if (i == 0) { - Tcl_DStringInit(&resultDString); - Tcl_DStringAppend(&resultDString, parentName, -1); + resultPtr = Tcl_DuplicateObj(parentPtr); if (doDot) { - Tcl_DStringAppend(&resultDString, ".", -1); + Tcl_AppendToObj(resultPtr, ".", -1); } - Tcl_DStringAppend(&resultDString, - Tcl_DStringValue(&childDString), -1); - destString = Tcl_DStringValue(&resultDString); + Tcl_AppendObjToObj(resultPtr, childPtr); } else { - if (i == 1) { - offset = Tcl_DStringLength(&resultDString); - Tcl_DStringSetLength(&resultDString, offset + 10); - destString = Tcl_DStringValue(&resultDString); - } - sprintf(destString + offset, "%d", i); + Tcl_Obj *intPtr; + + Tcl_DecrRefCount(resultPtr); + resultPtr = Tcl_DuplicateObj(parentPtr); + if (doDot) { + Tcl_AppendToObj(resultPtr, ".", -1); + } + Tcl_AppendObjToObj(resultPtr, childPtr); + intPtr = Tcl_NewIntObj(i); + Tcl_AppendObjToObj(resultPtr, intPtr); + Tcl_DecrRefCount(intPtr); } + destString = Tcl_GetStringFromObj(resultPtr, NULL); if ((Tcl_GetCommandInfo(interp, destString, &cmdInfo) == 0) && ((nameTablePtr == NULL) || (Tcl_FindHashEntry(nameTablePtr, destString) == NULL))) { break; } } - returnString = ckalloc(strlen(destString) + 1); - strcpy(returnString, destString); - Tcl_DStringFree(&resultDString); - Tcl_DStringFree(&childDString); - return returnString; + Tcl_DecrRefCount(childPtr); + return resultPtr; } /* @@ -2756,32 +3106,45 @@ TkSetWindowMenuBar(interp, tkwin, oldMenuName, menuName) menuPtr = menuRefPtr->menuPtr; if (menuPtr != NULL) { - char *cloneMenuName; + Tcl_Obj *cloneMenuPtr; TkMenuReferences *cloneMenuRefPtr; - char *newArgv[4]; + Tcl_Obj *newObjv[4]; + Tcl_Obj *windowNamePtr = Tcl_NewStringObj(Tk_PathName(tkwin), + -1); + Tcl_Obj *menubarPtr = Tcl_NewStringObj("menubar", -1); /* * Clone the menu and all of the cascades underneath it. */ - cloneMenuName = TkNewMenuName(interp, Tk_PathName(tkwin), + Tcl_IncrRefCount(windowNamePtr); + cloneMenuPtr = TkNewMenuName(interp, windowNamePtr, menuPtr); - CloneMenu(menuPtr, cloneMenuName, "menubar"); + Tcl_IncrRefCount(cloneMenuPtr); + Tcl_IncrRefCount(menubarPtr); + CloneMenu(menuPtr, cloneMenuPtr, menubarPtr); - cloneMenuRefPtr = TkFindMenuReferences(interp, cloneMenuName); + cloneMenuRefPtr = TkFindMenuReferencesObj(interp, cloneMenuPtr); if ((cloneMenuRefPtr != NULL) && (cloneMenuRefPtr->menuPtr != NULL)) { + Tcl_Obj *cursorPtr = Tcl_NewStringObj("-cursor", -1); + Tcl_Obj *nullPtr = Tcl_NewObj(); cloneMenuRefPtr->menuPtr->parentTopLevelPtr = tkwin; menuBarPtr = cloneMenuRefPtr->menuPtr; - newArgv[0] = "-cursor"; - newArgv[1] = ""; + newObjv[0] = cursorPtr; + newObjv[1] = nullPtr; + Tcl_IncrRefCount(cursorPtr); + Tcl_IncrRefCount(nullPtr); ConfigureMenu(menuPtr->interp, cloneMenuRefPtr->menuPtr, - 2, newArgv, TK_CONFIG_ARGV_ONLY); + 2, newObjv); + Tcl_DecrRefCount(cursorPtr); + Tcl_DecrRefCount(nullPtr); } TkpSetWindowMenuBar(tkwin, menuBarPtr); - - ckfree(cloneMenuName); + Tcl_DecrRefCount(cloneMenuPtr); + Tcl_DecrRefCount(menubarPtr); + Tcl_DecrRefCount(windowNamePtr); } else { TkpSetWindowMenuBar(tkwin, NULL); } @@ -2948,6 +3311,35 @@ TkFindMenuReferences(interp, pathName) /* *---------------------------------------------------------------------- * + * TkFindMenuReferencesObj -- + * + * Given a pathname, gives back a pointer to the TkMenuReferences + * structure. + * + * Results: + * Returns a pointer to a menu reference structure. Should not + * be freed by calller; when a field of the reference is cleared, + * TkFreeMenuReferences should be called. Returns NULL if no reference + * with this pathname exists. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TkMenuReferences * +TkFindMenuReferencesObj(interp, objPtr) + Tcl_Interp *interp; /* The interp the menu is living in. */ + Tcl_Obj *objPtr; /* The path of the menu widget */ +{ + char *pathName = Tcl_GetStringFromObj(objPtr, NULL); + return TkFindMenuReferences(interp, pathName); +} + +/* + *---------------------------------------------------------------------- + * * TkFreeMenuReferences -- * * This is called after one of the fields in a menu reference @@ -3013,7 +3405,7 @@ DeleteMenuCloneEntries(menuPtr, first, last) } for (i = last + 1; i < menuListPtr->numEntries; i++) { menuListPtr->entries[i - numDeleted] = menuListPtr->entries[i]; - menuListPtr->entries[i - numDeleted]->index = i; + menuListPtr->entries[i - numDeleted]->index = i - numDeleted; } menuListPtr->numEntries -= numDeleted; if (menuListPtr->numEntries == 0) { @@ -3050,8 +3442,21 @@ DeleteMenuCloneEntries(menuPtr, first, last) void TkMenuInit() { + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + if (!menusInitialized) { - TkpMenuInit(); - menusInitialized = 1; + Tcl_MutexLock(&menuMutex); + if (!menusInitialized) { + TkpMenuInit(); + menusInitialized = 1; + } + Tcl_MutexUnlock(&menuMutex); + } + if (!tsdPtr->menusInitialized) { + TkpMenuThreadInit(); + tsdPtr->menusInitialized = 1; } } + + diff --git a/tk/generic/tkMenu.h b/tk/generic/tkMenu.h index 27b9dfa61b3..d1b8e39dd3a 100644 --- a/tk/generic/tkMenu.h +++ b/tk/generic/tkMenu.h @@ -3,7 +3,7 @@ * * Declarations shared among all of the files that implement menu widgets. * - * Copyright (c) 1996-1997 by Sun Microsystems, Inc. + * Copyright (c) 1996-1998 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -47,66 +47,72 @@ typedef struct TkMenuEntry { int type; /* Type of menu entry; see below for * valid types. */ struct TkMenu *menuPtr; /* Menu with which this entry is associated. */ - char *label; /* Main text label displayed in entry (NULL - * if no label). Malloc'ed. */ + Tk_OptionTable optionTable; /* Option table for this menu entry. */ + Tcl_Obj *labelPtr; /* Main text label displayed in entry (NULL + * if no label). */ int labelLength; /* Number of non-NULL characters in label. */ - Tk_Uid state; /* State of button for display purposes: + int state; /* State of button for display purposes: * normal, active, or disabled. */ - int underline; /* Index of character to underline. */ - Pixmap bitmap; /* Bitmap to display in menu entry, or None. + int underline; /* Value of -underline option: specifies index + * of character to underline (<0 means don't + * underline anything). */ + Tcl_Obj *underlinePtr; /* Index of character to underline. */ + Tcl_Obj *bitmapPtr; /* Bitmap to display in menu entry, or None. * If not None then label is ignored. */ - char *imageString; /* Name of image to display (malloc'ed), or + Tcl_Obj *imagePtr; /* Name of image to display, or * NULL. If non-NULL, bitmap, text, and * textVarName are ignored. */ Tk_Image image; /* Image to display in menu entry, or NULL if * none. */ - char *selectImageString; /* Name of image to display when selected - * (malloc'ed), or NULL. */ + Tcl_Obj *selectImagePtr; /* Name of image to display when selected, or + * NULL. */ Tk_Image selectImage; /* Image to display in entry when selected, * or NULL if none. Ignored if image is * NULL. */ - char *accel; /* Accelerator string displayed at right + Tcl_Obj *accelPtr; /* Accelerator string displayed at right * of menu entry. NULL means no such * accelerator. Malloc'ed. */ int accelLength; /* Number of non-NULL characters in * accelerator. */ int indicatorOn; /* True means draw indicator, false means - * don't draw it. */ + * don't draw it. This field is ignored unless + * the entry is a radio or check button. */ /* * Display attributes */ - Tk_3DBorder border; /* Structure used to draw background for + Tcl_Obj *borderPtr; /* Structure used to draw background for * entry. NULL means use overall border * for menu. */ - XColor *fg; /* Foreground color to use for entry. NULL + Tcl_Obj *fgPtr; /* Foreground color to use for entry. NULL * means use foreground color from menu. */ - Tk_3DBorder activeBorder; /* Used to draw background and border when + Tcl_Obj *activeBorderPtr; /* Used to draw background and border when * element is active. NULL means use * activeBorder from menu. */ - XColor *activeFg; /* Foreground color to use when entry is + Tcl_Obj *activeFgPtr; /* Foreground color to use when entry is * active. NULL means use active foreground * from menu. */ - XColor *indicatorFg; /* Color for indicators in radio and check + Tcl_Obj *indicatorFgPtr; /* Color for indicators in radio and check * button entries. NULL means use indicatorFg * GC from menu. */ - Tk_Font tkfont; /* Text font for menu entries. NULL means + Tcl_Obj *fontPtr; /* Text font for menu entries. NULL means * use overall font for menu. */ int columnBreak; /* If this is 0, this item appears below * the item in front of it. If this is - * 1, this item starts a new column. */ + * 1, this item starts a new column. This + * field is always 0 for tearoff and separator + * entries. */ int hideMargin; /* If this is 0, then the item has enough - * margin to accomodate a standard check - * mark and a default right margin. If this - * is 1, then the item has no such margins. - * and checkbuttons and radiobuttons with - * this set will have a rectangle drawn - * in the indicator around the item if - * the item is checked. - * This is useful palette menus.*/ + * margin to accomodate a standard check mark + * and a default right margin. If this is 1, + * then the item has no such margins. and + * checkbuttons and radiobuttons with this set + * will have a rectangle drawn in the indicator + * around the item if the item is checked. This + * is useful for palette menus. This field is + * ignored for separators and tearoffs. */ int indicatorSpace; /* The width of the indicator space for this - * entry. - */ + * entry. */ int labelWidth; /* Number of pixels to allow for displaying * labels in menu entries. */ @@ -114,15 +120,15 @@ typedef struct TkMenuEntry { * Information used to implement this entry's action: */ - char *command; /* Command to invoke when entry is invoked. + Tcl_Obj *commandPtr; /* Command to invoke when entry is invoked. * Malloc'ed. */ - char *name; /* Name of variable (for check buttons and + Tcl_Obj *namePtr; /* Name of variable (for check buttons and * radio buttons) or menu (for cascade * entries). Malloc'ed.*/ - char *onValue; /* Value to store in variable when selected + Tcl_Obj *onValuePtr; /* Value to store in variable when selected * (only for radio and check buttons). * Malloc'ed. */ - char *offValue; /* Value to store in variable when not + Tcl_Obj *offValuePtr; /* Value to store in variable when not * selected (only for check buttons). * Malloc'ed. */ @@ -179,7 +185,7 @@ typedef struct TkMenuEntry { * does not yet exist. */ TkMenuPlatformEntryData platformEntryData; /* The data for the specific type of menu. - * Depends on platform and menu type what + * Depends on platform and menu type what * kind of options are in this structure. */ } TkMenuEntry; @@ -191,9 +197,9 @@ typedef struct TkMenuEntry { * button and that it should be drawn in * the "selected" state. * ENTRY_NEEDS_REDISPLAY: Non-zero means the entry should be redisplayed. - * ENTRY_LAST_COLUMN: Used by the drawing code. If the entry is in the - * last column, the space to its right needs to - * be filled. + * ENTRY_LAST_COLUMN: Used by the drawing code. If the entry is in + * the last column, the space to its right needs + * to be filled. * ENTRY_PLATFORM_FLAG1 - 4 These flags are reserved for use by the * platform-dependent implementation of menus * and should not be used by anything else. @@ -211,25 +217,22 @@ typedef struct TkMenuEntry { * Types defined for MenuEntries: */ -#define COMMAND_ENTRY 0 -#define SEPARATOR_ENTRY 1 -#define CHECK_BUTTON_ENTRY 2 -#define RADIO_BUTTON_ENTRY 3 -#define CASCADE_ENTRY 4 -#define TEAROFF_ENTRY 5 +#define CASCADE_ENTRY 0 +#define CHECK_BUTTON_ENTRY 1 +#define COMMAND_ENTRY 2 +#define RADIO_BUTTON_ENTRY 3 +#define SEPARATOR_ENTRY 4 +#define TEAROFF_ENTRY 5 /* - * Mask bits for above types: + * Menu states */ -#define COMMAND_MASK TK_CONFIG_USER_BIT -#define SEPARATOR_MASK (TK_CONFIG_USER_BIT << 1) -#define CHECK_BUTTON_MASK (TK_CONFIG_USER_BIT << 2) -#define RADIO_BUTTON_MASK (TK_CONFIG_USER_BIT << 3) -#define CASCADE_MASK (TK_CONFIG_USER_BIT << 4) -#define TEAROFF_MASK (TK_CONFIG_USER_BIT << 5) -#define ALL_MASK (COMMAND_MASK | SEPARATOR_MASK \ - | CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | CASCADE_MASK | TEAROFF_MASK) +EXTERN char *tkMenuStateStrings[]; + +#define ENTRY_ACTIVE 0 +#define ENTRY_NORMAL 1 +#define ENTRY_DISABLED 2 /* * A data structure of the following type is kept for each @@ -253,7 +256,7 @@ typedef struct TkMenu { * nothing active. */ int menuType; /* MASTER_MENU, TEAROFF_MENU, or MENUBAR. * See below for definitions. */ - char *menuTypeName; /* Used to control whether created tkwin + Tcl_Obj *menuTypePtr; /* Used to control whether created tkwin * is a toplevel or not. "normal", "menubar", * or "toplevel" */ @@ -261,20 +264,21 @@ typedef struct TkMenu { * Information used when displaying widget: */ - Tk_3DBorder border; /* Structure used to draw 3-D + Tcl_Obj *borderPtr; /* Structure used to draw 3-D * border and background for menu. */ - int borderWidth; /* Width of border around whole menu. */ - Tk_3DBorder activeBorder; /* Used to draw background and border for + Tcl_Obj *borderWidthPtr; /* Width of border around whole menu. */ + Tcl_Obj *activeBorderPtr; /* Used to draw background and border for * active element (if any). */ - int activeBorderWidth; /* Width of border around active element. */ - int relief; /* 3-d effect: TK_RELIEF_RAISED, etc. */ - Tk_Font tkfont; /* Text font for menu entries. */ - XColor *fg; /* Foreground color for entries. */ - XColor *disabledFg; /* Foreground color when disabled. NULL + Tcl_Obj *activeBorderWidthPtr; + /* Width of border around active element. */ + Tcl_Obj *reliefPtr; /* 3-d effect: TK_RELIEF_RAISED, etc. */ + Tcl_Obj *fontPtr; /* Text font for menu entries. */ + Tcl_Obj *fgPtr; /* Foreground color for entries. */ + Tcl_Obj *disabledFgPtr; /* Foreground color when disabled. NULL * means use normalFg with a 50% stipple * instead. */ - XColor *activeFg; /* Foreground color for active entry. */ - XColor *indicatorFg; /* Color for indicators in radio and check + Tcl_Obj *activeFgPtr; /* Foreground color for active entry. */ + Tcl_Obj *indicatorFgPtr; /* Color for indicators in radio and check * button entries. */ Pixmap gray; /* Bitmap for drawing disabled entries in * a stippled fashion. None means not @@ -305,7 +309,7 @@ typedef struct TkMenu { * Miscellaneous information: */ - int tearOff; /* 1 means this menu can be torn off. On some + int tearoff; /* 1 means this menu can be torn off. On some * platforms, the user can drag an outline * of the menu by just dragging outside of * the menu, and the tearoff is created where @@ -313,17 +317,17 @@ typedef struct TkMenu { * indicator (such as a dashed stripe) is * drawn, and when the menu is selected, the * tearoff is created. */ - char *title; /* The title to use when this menu is torn + Tcl_Obj *titlePtr; /* The title to use when this menu is torn * off. If this is NULL, a default scheme * will be used to generate a title for * tearoff. */ - char *tearOffCommand; /* If non-NULL, points to a command to + Tcl_Obj *tearoffCommandPtr; /* If non-NULL, points to a command to * run whenever the menu is torn-off. */ - char *takeFocus; /* Value of -takefocus option; not used in + Tcl_Obj *takeFocusPtr; /* Value of -takefocus option; not used in * the C code, but used by keyboard traversal * scripts. Malloc'ed, but may be NULL. */ - Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *postCommand; /* Used to detect cycles in cascade hierarchy + Tcl_Obj *cursorPtr; /* Current cursor for window, or None. */ + Tcl_Obj *postCommandPtr; /* Used to detect cycles in cascade hierarchy * trees when preprocessing postcommands * on some platforms. See PostMenu for * more details. */ @@ -341,6 +345,9 @@ typedef struct TkMenu { /* A pointer to the original menu for this * clone chain. Points back to this structure * if this menu is a master menu. */ + struct TkMenuOptionTables *optionTablesPtr; + /* A pointer to the collection of option tables + * that work with menus and menu entries. */ Tk_Window parentTopLevelPtr;/* If this menu is a menubar, this is the * toplevel that owns the menu. Only applicable * for menubar clones. @@ -360,6 +367,13 @@ typedef struct TkMenu { * Depends on platform and menu type what * kind of options are in this structure. */ + Tk_OptionSpec *extensionPtr; + /* Needed by the configuration package for + * this widget to be extended. */ + Tk_SavedOptions *errorStructPtr; + /* We actually have to allocate these because + * multiple menus get changed during one + * ConfigureMenu call. */ } TkMenu; /* @@ -407,6 +421,16 @@ typedef struct TkMenuReferences { } TkMenuReferences; /* + * This structure contains all of the option tables that are needed + * by menus. + */ + +typedef struct TkMenuOptionTables { + Tk_OptionTable menuOptionTable; /* The option table for menus. */ + Tk_OptionTable entryOptionTables[6];/* The tables for menu entries. */ +} TkMenuOptionTables; + +/* * Flag bits for menus: * * REDRAW_PENDING: Non-zero means a DoWhenIdle handler @@ -453,13 +477,6 @@ typedef struct TkMenuReferences { #define DECORATION_BORDER_WIDTH 2 /* - * Configuration specs. Needed for platform-specific default initializations. - */ - -EXTERN Tk_ConfigSpec tkMenuEntryConfigSpecs[]; -EXTERN Tk_ConfigSpec tkMenuConfigSpecs[]; - -/* * Menu-related procedures that are shared among Tk modules but not exported * to the outside world: */ @@ -470,21 +487,26 @@ EXTERN void TkBindMenu _ANSI_ARGS_(( Tk_Window tkwin, TkMenu *menuPtr)); EXTERN TkMenuReferences * TkCreateMenuReferences _ANSI_ARGS_((Tcl_Interp *interp, - char *pathName)); + char *name)); EXTERN void TkDestroyMenu _ANSI_ARGS_((TkMenu *menuPtr)); -EXTERN void TkEventuallyRecomputeMenu _ANSI_ARGS_((TkMenu *menuPtr)); +EXTERN void TkEventuallyRecomputeMenu _ANSI_ARGS_(( + TkMenu *menuPtr)); EXTERN void TkEventuallyRedrawMenu _ANSI_ARGS_(( TkMenu *menuPtr, TkMenuEntry *mePtr)); EXTERN TkMenuReferences * TkFindMenuReferences _ANSI_ARGS_((Tcl_Interp *interp, - char *pathName)); + char *name)); +EXTERN TkMenuReferences * + TkFindMenuReferencesObj _ANSI_ARGS_(( + Tcl_Interp *interp, Tcl_Obj *namePtr)); EXTERN void TkFreeMenuReferences _ANSI_ARGS_(( TkMenuReferences *menuRefPtr)); EXTERN Tcl_HashTable * TkGetMenuHashTable _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int TkGetMenuIndex _ANSI_ARGS_((Tcl_Interp *interp, - TkMenu *menuPtr, char *string, int lastOK, + TkMenu *menuPtr, Tcl_Obj *objPtr, int lastOK, int *indexPtr)); -EXTERN void TkMenuInitializeDrawingFields _ANSI_ARGS_((TkMenu *menuPtr)); +EXTERN void TkMenuInitializeDrawingFields _ANSI_ARGS_(( + TkMenu *menuPtr)); EXTERN void TkMenuInitializeEntryDrawingFields _ANSI_ARGS_(( TkMenuEntry *mePtr)); EXTERN int TkInvokeMenu _ANSI_ARGS_((Tcl_Interp *interp, @@ -506,8 +528,8 @@ EXTERN void TkMenuSelectImageProc _ANSI_ARGS_ ((ClientData clientData, int x, int y, int width, int height, int imgWidth, int imgHeight)); -EXTERN char * TkNewMenuName _ANSI_ARGS_((Tcl_Interp *interp, - char *parentName, TkMenu *menuPtr)); +EXTERN Tcl_Obj * TkNewMenuName _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *parentNamePtr, TkMenu *menuPtr)); EXTERN int TkPostCommand _ANSI_ARGS_((TkMenu *menuPtr)); EXTERN int TkPostSubmenu _ANSI_ARGS_((Tcl_Interp *interp, TkMenu *menuPtr, TkMenuEntry *mePtr)); @@ -521,7 +543,8 @@ EXTERN void TkRecomputeMenu _ANSI_ARGS_((TkMenu *menuPtr)); * common code. */ -EXTERN void TkpComputeMenubarGeometry _ANSI_ARGS_((TkMenu *menuPtr)); +EXTERN void TkpComputeMenubarGeometry _ANSI_ARGS_(( + TkMenu *menuPtr)); EXTERN void TkpComputeStandardMenuGeometry _ANSI_ARGS_ ((TkMenu *menuPtr)); EXTERN int TkpConfigureMenuEntry @@ -547,3 +570,4 @@ EXTERN void TkpSetWindowMenuBar _ANSI_ARGS_((Tk_Window tkwin, #endif /* _TKMENU */ + diff --git a/tk/generic/tkMenuDraw.c b/tk/generic/tkMenuDraw.c index 6109310bb7a..123795c4801 100644 --- a/tk/generic/tkMenuDraw.c +++ b/tk/generic/tkMenuDraw.c @@ -31,7 +31,7 @@ static void DisplayMenu _ANSI_ARGS_((ClientData clientData)); * TkMenuInitializeDrawingFields -- * * Fills in drawing fields of a new menu. Called when new menu is - * created by Tk_MenuCmd. + * created by MenuCmd. * * Results: * None. @@ -188,6 +188,9 @@ TkMenuConfigureDrawOptions(menuPtr) XGCValues gcValues; GC newGC; unsigned long mask; + Tk_3DBorder border, activeBorder; + Tk_Font tkfont; + XColor *fg, *activeFg, *indicatorFg; XColor *foreground, *background; /* @@ -196,33 +199,40 @@ TkMenuConfigureDrawOptions(menuPtr) * defaults that couldn't be specified to Tk_ConfigureWidget. */ - Tk_SetBackgroundFromBorder(menuPtr->tkwin, menuPtr->border); + border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr); + Tk_SetBackgroundFromBorder(menuPtr->tkwin, border); - gcValues.font = Tk_FontId(menuPtr->tkfont); - gcValues.foreground = menuPtr->fg->pixel; - gcValues.background = Tk_3DBorderColor(menuPtr->border)->pixel; - newGC = Tk_GetGCColor(menuPtr->tkwin, GCForeground|GCBackground|GCFont, - &gcValues, menuPtr->fg, Tk_3DBorderColor(menuPtr->border)); + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); + gcValues.font = Tk_FontId(tkfont); + fg = Tk_GetColorFromObj(menuPtr->tkwin, menuPtr->fgPtr); + gcValues.foreground = fg->pixel; + gcValues.background = Tk_3DBorderColor(border)->pixel; + newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont, + &gcValues); if (menuPtr->textGC != None) { Tk_FreeGC(menuPtr->display, menuPtr->textGC); } menuPtr->textGC = newGC; - gcValues.font = Tk_FontId(menuPtr->tkfont); - background = Tk_3DBorderColor(menuPtr->border); + gcValues.font = Tk_FontId(tkfont); + background = Tk_3DBorderColor(border); gcValues.background = background->pixel; - if (menuPtr->disabledFg != NULL) { - foreground = menuPtr->disabledFg; + if (menuPtr->disabledFgPtr != NULL) { + XColor *disabledFg; + + disabledFg = Tk_GetColorFromObj(menuPtr->tkwin, + menuPtr->disabledFgPtr); + foreground = disabledFg; gcValues.foreground = foreground->pixel; mask = GCForeground|GCBackground|GCFont; } else { - foreground = background; + foreground = background; background = NULL; gcValues.foreground = gcValues.background; mask = GCForeground; if (menuPtr->gray == None) { menuPtr->gray = Tk_GetBitmap(menuPtr->interp, menuPtr->tkwin, - Tk_GetUid("gray50")); + "gray50"); } if (menuPtr->gray != None) { gcValues.fill_style = FillStippled; @@ -230,47 +240,47 @@ TkMenuConfigureDrawOptions(menuPtr) mask = GCForeground|GCFillStyle|GCStipple; } } - newGC = Tk_GetGCColor(menuPtr->tkwin, mask, &gcValues, foreground, - background); + newGC = Tk_GetGC(menuPtr->tkwin, mask, &gcValues); if (menuPtr->disabledGC != None) { Tk_FreeGC(menuPtr->display, menuPtr->disabledGC); } menuPtr->disabledGC = newGC; - gcValues.foreground = Tk_3DBorderColor(menuPtr->border)->pixel; + gcValues.foreground = Tk_3DBorderColor(border)->pixel; if (menuPtr->gray == None) { menuPtr->gray = Tk_GetBitmap(menuPtr->interp, menuPtr->tkwin, - Tk_GetUid("gray50")); + "gray50"); } if (menuPtr->gray != None) { gcValues.fill_style = FillStippled; gcValues.stipple = menuPtr->gray; - newGC = Tk_GetGCColor(menuPtr->tkwin, - GCForeground|GCFillStyle|GCStipple, &gcValues, - Tk_3DBorderColor(menuPtr->border), NULL); + newGC = Tk_GetGC(menuPtr->tkwin, + GCForeground|GCFillStyle|GCStipple, &gcValues); } if (menuPtr->disabledImageGC != None) { Tk_FreeGC(menuPtr->display, menuPtr->disabledImageGC); } menuPtr->disabledImageGC = newGC; - gcValues.font = Tk_FontId(menuPtr->tkfont); - gcValues.foreground = menuPtr->activeFg->pixel; - gcValues.background = - Tk_3DBorderColor(menuPtr->activeBorder)->pixel; - newGC = Tk_GetGCColor(menuPtr->tkwin, GCForeground|GCBackground|GCFont, - &gcValues, menuPtr->activeFg, - Tk_3DBorderColor(menuPtr->activeBorder)); + gcValues.font = Tk_FontId(tkfont); + activeFg = Tk_GetColorFromObj(menuPtr->tkwin, menuPtr->activeFgPtr); + gcValues.foreground = activeFg->pixel; + activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin, + menuPtr->activeBorderPtr); + gcValues.background = Tk_3DBorderColor(activeBorder)->pixel; + newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont, + &gcValues); if (menuPtr->activeGC != None) { Tk_FreeGC(menuPtr->display, menuPtr->activeGC); } menuPtr->activeGC = newGC; - gcValues.foreground = menuPtr->indicatorFg->pixel; - gcValues.background = Tk_3DBorderColor(menuPtr->border)->pixel; - newGC = Tk_GetGCColor(menuPtr->tkwin, GCForeground|GCBackground|GCFont, - &gcValues, menuPtr->indicatorFg, - Tk_3DBorderColor(menuPtr->border)); + indicatorFg = Tk_GetColorFromObj(menuPtr->tkwin, + menuPtr->indicatorFgPtr); + gcValues.foreground = indicatorFg->pixel; + gcValues.background = Tk_3DBorderColor(border)->pixel; + newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont, + &gcValues); if (menuPtr->indicatorGC != None) { Tk_FreeGC(menuPtr->display, menuPtr->indicatorGC); } @@ -306,9 +316,10 @@ TkMenuConfigureEntryDrawOptions(mePtr, index) Tk_Font tkfont; TkMenu *menuPtr = mePtr->menuPtr; - tkfont = (mePtr->tkfont == NULL) ? menuPtr->tkfont : mePtr->tkfont; + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, + (mePtr->fontPtr != NULL) ? mePtr->fontPtr : menuPtr->fontPtr); - if (mePtr->state == tkActiveUid) { + if (mePtr->state == ENTRY_ACTIVE) { if (index != menuPtr->active) { TkActivateMenuEntry(menuPtr, index); } @@ -316,34 +327,26 @@ TkMenuConfigureEntryDrawOptions(mePtr, index) if (index == menuPtr->active) { TkActivateMenuEntry(menuPtr, -1); } - if ((mePtr->state != tkNormalUid) - && (mePtr->state != tkDisabledUid)) { - Tcl_AppendResult(menuPtr->interp, "bad state value \"", - mePtr->state, - "\": must be normal, active, or disabled", (char *) NULL); - mePtr->state = tkNormalUid; - return TCL_ERROR; - } } - if ((mePtr->tkfont != NULL) - || (mePtr->border != NULL) - || (mePtr->fg != NULL) - || (mePtr->activeBorder != NULL) - || (mePtr->activeFg != NULL) - || (mePtr->indicatorFg != NULL)) { - XColor *foreground, *background; - - background = Tk_3DBorderColor( - (mePtr->border != NULL) - ? mePtr->border - : menuPtr->border); - foreground = (mePtr->fg != NULL) - ? mePtr->fg - : menuPtr->fg; + if ((mePtr->fontPtr != NULL) + || (mePtr->borderPtr != NULL) + || (mePtr->fgPtr != NULL) + || (mePtr->activeBorderPtr != NULL) + || (mePtr->activeFgPtr != NULL) + || (mePtr->indicatorFgPtr != NULL)) { + XColor *fg, *bg, *indicatorFg, *activeFg; + Tk_3DBorder border, activeBorder; + + fg = Tk_GetColorFromObj(menuPtr->tkwin, (mePtr->fgPtr != NULL) + ? mePtr->fgPtr : menuPtr->fgPtr); - gcValues.foreground = foreground->pixel; - gcValues.background = background->pixel; + gcValues.foreground = fg->pixel; + border = Tk_Get3DBorderFromObj(menuPtr->tkwin, + (mePtr->borderPtr != NULL) ? mePtr->borderPtr + : menuPtr->borderPtr); + bg = Tk_3DBorderColor(border); + gcValues.background = bg->pixel; gcValues.font = Tk_FontId(tkfont); @@ -354,48 +357,43 @@ TkMenuConfigureEntryDrawOptions(mePtr, index) */ gcValues.graphics_exposures = False; - newGC = Tk_GetGCColor(menuPtr->tkwin, + newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont|GCGraphicsExposures, - &gcValues, foreground, background); - - if (mePtr->indicatorFg != NULL) { - foreground = mePtr->indicatorFg; - gcValues.foreground = foreground->pixel; - } else if (menuPtr->indicatorFg != NULL) { - foreground = menuPtr->indicatorFg; - gcValues.foreground = foreground->pixel; - } - newIndicatorGC = Tk_GetGCColor(menuPtr->tkwin, + &gcValues); + indicatorFg = Tk_GetColorFromObj(menuPtr->tkwin, + (mePtr->indicatorFgPtr != NULL) ? mePtr->indicatorFgPtr + : menuPtr->indicatorFgPtr); + gcValues.foreground = indicatorFg->pixel; + newIndicatorGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCGraphicsExposures, - &gcValues, foreground, background); - - if ((menuPtr->disabledFg != NULL) || (mePtr->image != NULL)) { - foreground = menuPtr->disabledFg; - gcValues.foreground = foreground->pixel; + &gcValues); + if ((menuPtr->disabledFgPtr != NULL) || (mePtr->image != NULL)) { + fg = Tk_GetColorFromObj(menuPtr->tkwin, + menuPtr->disabledFgPtr); + gcValues.foreground = fg->pixel; mask = GCForeground|GCBackground|GCFont|GCGraphicsExposures; } else { - foreground = background; - background = NULL; + fg = bg; gcValues.foreground = gcValues.background; gcValues.fill_style = FillStippled; gcValues.stipple = menuPtr->gray; mask = GCForeground|GCFillStyle|GCStipple; } - newDisabledGC = Tk_GetGCColor(menuPtr->tkwin, mask, &gcValues, - foreground, background); - - foreground = (mePtr->activeFg != NULL) - ? mePtr->activeFg - : menuPtr->activeFg; - gcValues.foreground = foreground->pixel; - background = Tk_3DBorderColor( - (mePtr->activeBorder != NULL) - ? mePtr->activeBorder - : menuPtr->activeBorder); - gcValues.background = background->pixel; - newActiveGC = Tk_GetGCColor(menuPtr->tkwin, + newDisabledGC = Tk_GetGC(menuPtr->tkwin, mask, &gcValues); + + activeFg = Tk_GetColorFromObj(menuPtr->tkwin, + (mePtr->activeFgPtr != NULL) ? mePtr->activeFgPtr + : menuPtr->activeFgPtr); + activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin, + (mePtr->activeBorderPtr != NULL) ? mePtr->activeBorderPtr + : menuPtr->activeBorderPtr); + + gcValues.foreground = activeFg->pixel; + bg = Tk_3DBorderColor(activeBorder); + gcValues.background = bg->pixel; + newActiveGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont|GCGraphicsExposures, - &gcValues, foreground, background); + &gcValues); } else { newGC = None; newActiveGC = None; @@ -496,7 +494,7 @@ TkRecomputeMenu(menuPtr) void TkEventuallyRedrawMenu(menuPtr, mePtr) register TkMenu *menuPtr; /* Information about menu to redraw. */ - register TkMenuEntry *mePtr; /* Entry to redraw. NULL means redraw + register TkMenuEntry *mePtr;/* Entry to redraw. NULL means redraw * all the entries in the menu. */ { int i; @@ -637,21 +635,30 @@ DisplayMenu(clientData) register TkMenuEntry *mePtr; register Tk_Window tkwin = menuPtr->tkwin; int index, strictMotif; - Tk_Font tkfont = menuPtr->tkfont; + Tk_Font tkfont; Tk_FontMetrics menuMetrics; int width; + int borderWidth; + Tk_3DBorder border; + int activeBorderWidth; + int relief; + menuPtr->menuFlags &= ~REDRAW_PENDING; if ((menuPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr, + &borderWidth); + border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr); + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, + menuPtr->activeBorderWidthPtr, &activeBorderWidth); + if (menuPtr->menuType == MENUBAR) { - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), menuPtr->border, - menuPtr->borderWidth, menuPtr->borderWidth, - Tk_Width(tkwin) - 2 * menuPtr->borderWidth, - Tk_Height(tkwin) - 2 * menuPtr->borderWidth, 0, - TK_RELIEF_FLAT); + Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, borderWidth, + borderWidth, Tk_Width(tkwin) - 2 * borderWidth, + Tk_Height(tkwin) - 2 * borderWidth, 0, TK_RELIEF_FLAT); } strictMotif = Tk_StrictMotif(menuPtr->tkwin); @@ -661,7 +668,8 @@ DisplayMenu(clientData) * all of the time. */ - Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics); + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); + Tk_GetFontMetrics(tkfont, &menuMetrics); /* * Loop through all of the entries, drawing them one at a time. @@ -681,22 +689,22 @@ DisplayMenu(clientData) } else { if (mePtr->entryFlags & ENTRY_LAST_COLUMN) { width = Tk_Width(menuPtr->tkwin) - mePtr->x - - menuPtr->activeBorderWidth; + - activeBorderWidth; } else { - width = mePtr->width + menuPtr->borderWidth; + width = mePtr->width + borderWidth; } } TkpDrawMenuEntry(mePtr, Tk_WindowId(menuPtr->tkwin), tkfont, &menuMetrics, mePtr->x, mePtr->y, width, mePtr->height, strictMotif, 1); - if ((index > 0) && (menuPtr->menuType != MENUBAR) + if ((index > 0) && (menuPtr->menuType != MENUBAR) && mePtr->columnBreak) { mePtr = menuPtr->entries[index - 1]; - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), menuPtr->border, + Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, mePtr->x, mePtr->y + mePtr->height, mePtr->width, - Tk_Height(tkwin) - mePtr->y - mePtr->height - - menuPtr->activeBorderWidth, 0, + Tk_Height(tkwin) - mePtr->y - mePtr->height - + activeBorderWidth, 0, TK_RELIEF_FLAT); } } @@ -705,28 +713,29 @@ DisplayMenu(clientData) int x, y, height; if (menuPtr->numEntries == 0) { - x = y = menuPtr->borderWidth; - width = Tk_Width(tkwin) - 2 * menuPtr->activeBorderWidth; - height = Tk_Height(tkwin) - 2 * menuPtr->activeBorderWidth; + x = y = borderWidth; + width = Tk_Width(tkwin) - 2 * activeBorderWidth; + height = Tk_Height(tkwin) - 2 * activeBorderWidth; } else { mePtr = menuPtr->entries[menuPtr->numEntries - 1]; Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), - menuPtr->border, mePtr->x, mePtr->y + mePtr->height, - mePtr->width, Tk_Height(tkwin) - mePtr->y - mePtr->height - - menuPtr->activeBorderWidth, 0, + border, mePtr->x, mePtr->y + mePtr->height, mePtr->width, + Tk_Height(tkwin) - mePtr->y - mePtr->height + - activeBorderWidth, 0, TK_RELIEF_FLAT); x = mePtr->x + mePtr->width; y = mePtr->y + mePtr->height; - width = Tk_Width(tkwin) - x - menuPtr->activeBorderWidth; - height = Tk_Height(tkwin) - y - menuPtr->activeBorderWidth; + width = Tk_Width(tkwin) - x - activeBorderWidth; + height = Tk_Height(tkwin) - y - activeBorderWidth; } - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), menuPtr->border, x, y, + Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, x, y, width, height, 0, TK_RELIEF_FLAT); } + Tk_GetReliefFromObj(NULL, menuPtr->reliefPtr, &relief); Tk_Draw3DRectangle(menuPtr->tkwin, Tk_WindowId(tkwin), - menuPtr->border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), - menuPtr->borderWidth, menuPtr->relief); + border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), borderWidth, + relief); } /* @@ -760,11 +769,12 @@ TkMenuEventProc(clientData, eventPtr) TkEventuallyRecomputeMenu(menuPtr); TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL); } else if (eventPtr->type == ActivateNotify) { - if (menuPtr->menuType == TEAROFF_MENU) { - TkpSetMainMenubar(menuPtr->interp, menuPtr->tkwin, NULL); - } + if (menuPtr->menuType == TEAROFF_MENU) { + TkpSetMainMenubar(menuPtr->interp, menuPtr->tkwin, NULL); + } } else if (eventPtr->type == DestroyNotify) { if (menuPtr->tkwin != NULL) { + TkDestroyMenu(menuPtr); menuPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(menuPtr->interp, menuPtr->widgetCmd); } @@ -774,7 +784,7 @@ TkMenuEventProc(clientData, eventPtr) if (menuPtr->menuFlags & RESIZE_PENDING) { Tcl_CancelIdleCall(ComputeMenuGeometry, (ClientData) menuPtr); } - TkDestroyMenu(menuPtr); + Tcl_EventuallyFree((ClientData) menuPtr, TCL_DYNAMIC); } } @@ -942,7 +952,6 @@ TkPostSubmenu(interp, menuPtr, mePtr) * posted. NULL means make sure that * no submenu is posted. */ { - char string[30]; int result, x, y; if (mePtr == menuPtr->postedCascade) { @@ -950,6 +959,8 @@ TkPostSubmenu(interp, menuPtr, mePtr) } if (menuPtr->postedCascade != NULL) { + char *name = Tcl_GetStringFromObj(menuPtr->postedCascade->namePtr, + NULL); /* * Note: when unposting a submenu, we have to redraw the entire @@ -969,17 +980,15 @@ TkPostSubmenu(interp, menuPtr, mePtr) */ TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL); - result = Tcl_VarEval(interp, menuPtr->postedCascade->name, - " unpost", (char *) NULL); + result = Tcl_VarEval(interp, name, " unpost", (char *) NULL); menuPtr->postedCascade = NULL; if (result != TCL_OK) { return result; } } - if ((mePtr != NULL) && (mePtr->name != NULL) + if ((mePtr != NULL) && (mePtr->namePtr != NULL) && Tk_IsMapped(menuPtr->tkwin)) { - /* * Position the cascade with its upper left corner slightly * below and to the left of the upper right corner of the @@ -988,10 +997,13 @@ TkPostSubmenu(interp, menuPtr, mePtr) * The menu has to redrawn so that the entry can change relief. */ + char string[TCL_INTEGER_SPACE * 2]; + char *name; + + name = Tcl_GetStringFromObj(mePtr->namePtr, NULL); Tk_GetRootCoords(menuPtr->tkwin, &x, &y); AdjustMenuCoords(menuPtr, mePtr, &x, &y, string); - result = Tcl_VarEval(interp, mePtr->name, " post ", string, - (char *) NULL); + result = Tcl_VarEval(interp, name, " post ", string, (char *) NULL); if (result != TCL_OK) { return result; } @@ -1030,10 +1042,16 @@ AdjustMenuCoords(menuPtr, mePtr, xPtr, yPtr, string) *xPtr += mePtr->x; *yPtr += mePtr->y + mePtr->height; } else { - *xPtr += Tk_Width(menuPtr->tkwin) - menuPtr->borderWidth - - menuPtr->activeBorderWidth - 2; - *yPtr += mePtr->y - + menuPtr->activeBorderWidth + 2; + int borderWidth, activeBorderWidth; + + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr, + &borderWidth); + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, + menuPtr->activeBorderWidthPtr, &activeBorderWidth); + *xPtr += Tk_Width(menuPtr->tkwin) - borderWidth - activeBorderWidth + - 2; + *yPtr += mePtr->y + activeBorderWidth + 2; } sprintf(string, "%d %d", *xPtr, *yPtr); } + diff --git a/tk/generic/tkMenubutton.c b/tk/generic/tkMenubutton.c index f7f9c6cb7c1..059499a7d24 100644 --- a/tk/generic/tkMenubutton.c +++ b/tk/generic/tkMenubutton.c @@ -18,117 +18,140 @@ #include "default.h" /* - * Uids internal to menubuttons. + * The following table defines the legal values for the -direction + * option. It is used together with the "enum direction" declaration + * in tkMenubutton.h. */ -static Tk_Uid aboveUid = NULL; -static Tk_Uid belowUid = NULL; -static Tk_Uid leftUid = NULL; -static Tk_Uid rightUid = NULL; -static Tk_Uid flushUid = NULL; +static char *directionStrings[] = { + "above", "below", "flush", "left", "right", (char *) NULL +}; + +/* + * The following table defines the legal values for the -state option. + * It is used together with the "enum state" declaration in tkMenubutton.h. + */ + +static char *stateStrings[] = { + "active", "disabled", "normal", (char *) NULL +}; /* * Information used for parsing configuration specs: */ -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_MENUBUTTON_ACTIVE_BG_COLOR, Tk_Offset(TkMenuButton, activeBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_MENUBUTTON_ACTIVE_BG_MONO, Tk_Offset(TkMenuButton, activeBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_MENUBUTTON_ACTIVE_FG_COLOR, Tk_Offset(TkMenuButton, activeFg), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", - DEF_MENUBUTTON_ACTIVE_FG_MONO, Tk_Offset(TkMenuButton, activeFg), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", - DEF_MENUBUTTON_ANCHOR, Tk_Offset(TkMenuButton, anchor), 0}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_MENUBUTTON_BG_COLOR, Tk_Offset(TkMenuButton, normalBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_MENUBUTTON_BG_MONO, Tk_Offset(TkMenuButton, normalBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap", - DEF_MENUBUTTON_BITMAP, Tk_Offset(TkMenuButton, bitmap), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_MENUBUTTON_BORDER_WIDTH, Tk_Offset(TkMenuButton, borderWidth), 0}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_MENUBUTTON_CURSOR, Tk_Offset(TkMenuButton, cursor), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-direction", "direction", "Direction", - DEF_MENUBUTTON_DIRECTION, Tk_Offset(TkMenuButton, direction), - 0}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground", + DEF_MENUBUTTON_ACTIVE_BG_COLOR, -1, + Tk_Offset(TkMenuButton, activeBorder), 0, + (ClientData) DEF_MENUBUTTON_ACTIVE_BG_MONO, 0}, + {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "Background", + DEF_MENUBUTTON_ACTIVE_FG_COLOR, -1, + Tk_Offset(TkMenuButton, activeFg), + 0, (ClientData) DEF_MENUBUTTON_ACTIVE_FG_MONO, 0}, + {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", + DEF_MENUBUTTON_ANCHOR, -1, + Tk_Offset(TkMenuButton, anchor), 0, 0, 0}, + {TK_OPTION_BORDER, "-background", "background", "Background", + DEF_MENUBUTTON_BG_COLOR, -1, Tk_Offset(TkMenuButton, normalBorder), + 0, (ClientData) DEF_MENUBUTTON_BG_MONO, 0}, + {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, + {TK_OPTION_BITMAP, "-bitmap", "bitmap", "Bitmap", + DEF_MENUBUTTON_BITMAP, -1, Tk_Offset(TkMenuButton, bitmap), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + DEF_MENUBUTTON_BORDER_WIDTH, -1, + Tk_Offset(TkMenuButton, borderWidth), 0, 0, 0}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + DEF_MENUBUTTON_CURSOR, -1, Tk_Offset(TkMenuButton, cursor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-direction", "direction", "Direction", + DEF_MENUBUTTON_DIRECTION, -1, Tk_Offset(TkMenuButton, direction), + 0, (ClientData) directionStrings, 0}, + {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground", "DisabledForeground", DEF_MENUBUTTON_DISABLED_FG_COLOR, - Tk_Offset(TkMenuButton, disabledFg), - TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", - "DisabledForeground", DEF_MENUBUTTON_DISABLED_FG_MONO, - Tk_Offset(TkMenuButton, disabledFg), - TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_MENUBUTTON_FONT, Tk_Offset(TkMenuButton, tkfont), 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_MENUBUTTON_FG, Tk_Offset(TkMenuButton, normalFg), 0}, - {TK_CONFIG_STRING, "-height", "height", "Height", - DEF_MENUBUTTON_HEIGHT, Tk_Offset(TkMenuButton, heightString), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_MENUBUTTON_HIGHLIGHT_BG, - Tk_Offset(TkMenuButton, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_MENUBUTTON_HIGHLIGHT, Tk_Offset(TkMenuButton, highlightColorPtr), - 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", + -1, Tk_Offset(TkMenuButton, disabledFg), TK_OPTION_NULL_OK, + (ClientData) DEF_MENUBUTTON_DISABLED_FG_MONO, 0}, + {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + DEF_MENUBUTTON_FONT, -1, Tk_Offset(TkMenuButton, tkfont), 0, 0, 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + DEF_MENUBUTTON_FG, -1, Tk_Offset(TkMenuButton, normalFg), 0, 0, 0}, + {TK_OPTION_STRING, "-height", "height", "Height", + DEF_MENUBUTTON_HEIGHT, -1, Tk_Offset(TkMenuButton, heightString), + 0, 0, 0}, + {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground", + "HighlightBackground", DEF_MENUBUTTON_HIGHLIGHT_BG_COLOR, + -1, Tk_Offset(TkMenuButton, highlightBgColorPtr), 0, 0, 0}, + {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", + DEF_MENUBUTTON_HIGHLIGHT, -1, + Tk_Offset(TkMenuButton, highlightColorPtr), 0, 0, 0}, + {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_MENUBUTTON_HIGHLIGHT_WIDTH, - Tk_Offset(TkMenuButton, highlightWidth), 0}, - {TK_CONFIG_STRING, "-image", "image", "Image", - DEF_MENUBUTTON_IMAGE, Tk_Offset(TkMenuButton, imageString), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn", - DEF_MENUBUTTON_INDICATOR, Tk_Offset(TkMenuButton, indicatorOn), 0}, - {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", - DEF_MENUBUTTON_JUSTIFY, Tk_Offset(TkMenuButton, justify), 0}, - {TK_CONFIG_STRING, "-menu", "menu", "Menu", - DEF_MENUBUTTON_MENU, Tk_Offset(TkMenuButton, menuName), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", - DEF_MENUBUTTON_PADX, Tk_Offset(TkMenuButton, padX), 0}, - {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", - DEF_MENUBUTTON_PADY, Tk_Offset(TkMenuButton, padY), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_MENUBUTTON_RELIEF, Tk_Offset(TkMenuButton, relief), 0}, - {TK_CONFIG_UID, "-state", "state", "State", - DEF_MENUBUTTON_STATE, Tk_Offset(TkMenuButton, state), 0}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_MENUBUTTON_TAKE_FOCUS, Tk_Offset(TkMenuButton, takeFocus), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_STRING, "-text", "text", "Text", - DEF_MENUBUTTON_TEXT, Tk_Offset(TkMenuButton, text), 0}, - {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable", - DEF_MENUBUTTON_TEXT_VARIABLE, Tk_Offset(TkMenuButton, textVarName), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-underline", "underline", "Underline", - DEF_MENUBUTTON_UNDERLINE, Tk_Offset(TkMenuButton, underline), 0}, - {TK_CONFIG_STRING, "-width", "width", "Width", - DEF_MENUBUTTON_WIDTH, Tk_Offset(TkMenuButton, widthString), 0}, - {TK_CONFIG_PIXELS, "-wraplength", "wrapLength", "WrapLength", - DEF_MENUBUTTON_WRAP_LENGTH, Tk_Offset(TkMenuButton, wrapLength), 0}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + -1, Tk_Offset(TkMenuButton, highlightWidth), 0, 0, 0}, + {TK_OPTION_STRING, "-image", "image", "Image", + DEF_MENUBUTTON_IMAGE, -1, Tk_Offset(TkMenuButton, imageString), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn", + DEF_MENUBUTTON_INDICATOR, -1, Tk_Offset(TkMenuButton, indicatorOn), + 0, 0, 0}, + {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", + DEF_BUTTON_JUSTIFY, -1, Tk_Offset(TkMenuButton, justify), 0, 0, 0}, + {TK_OPTION_STRING, "-menu", "menu", "Menu", + DEF_MENUBUTTON_MENU, -1, Tk_Offset(TkMenuButton, menuName), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-padx", "padX", "Pad", + DEF_MENUBUTTON_PADX, -1, Tk_Offset(TkMenuButton, padX), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-pady", "padY", "Pad", + DEF_MENUBUTTON_PADY, -1, Tk_Offset(TkMenuButton, padY), + 0, 0, 0}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + DEF_MENUBUTTON_RELIEF, -1, Tk_Offset(TkMenuButton, relief), + 0, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", "state", "State", + DEF_MENUBUTTON_STATE, -1, Tk_Offset(TkMenuButton, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + DEF_MENUBUTTON_TAKE_FOCUS, -1, + Tk_Offset(TkMenuButton, takeFocus), TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-text", "text", "Text", + DEF_MENUBUTTON_TEXT, -1, Tk_Offset(TkMenuButton, text), 0, 0, 0}, + {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", + DEF_MENUBUTTON_TEXT_VARIABLE, -1, + Tk_Offset(TkMenuButton, textVarName), TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_INT, "-underline", "underline", "Underline", + DEF_MENUBUTTON_UNDERLINE, -1, Tk_Offset(TkMenuButton, underline), + 0, 0, 0}, + {TK_OPTION_STRING, "-width", "width", "Width", + DEF_MENUBUTTON_WIDTH, -1, Tk_Offset(TkMenuButton, widthString), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength", + DEF_MENUBUTTON_WRAP_LENGTH, -1, Tk_Offset(TkMenuButton, wrapLength), + 0, 0, 0}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; /* + * The following tables define the menubutton widget commands and map the + * indexes into the string tables into a single enumerated type used + * to dispatch the scale widget command. + */ + +static char *commandNames[] = { + "cget", "configure", (char *) NULL +}; + +enum command { + COMMAND_CGET, COMMAND_CONFIGURE +}; + +/* * Forward declarations for procedures defined later in this file: */ @@ -142,17 +165,18 @@ static void MenuButtonImageProc _ANSI_ARGS_((ClientData clientData, static char * MenuButtonTextVarProc _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)); -static int MenuButtonWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); +static int MenuButtonWidgetObjCmd _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[])); static int ConfigureMenuButton _ANSI_ARGS_((Tcl_Interp *interp, - TkMenuButton *mbPtr, int argc, char **argv, - int flags)); + TkMenuButton *mbPtr, int objc, + Tcl_Obj *CONST objv[])); static void DestroyMenuButton _ANSI_ARGS_((char *memPtr)); /* *-------------------------------------------------------------- * - * Tk_MenubuttonCmd -- + * Tk_MenubuttonObjCmd -- * * This procedure is invoked to process the "button", "label", * "radiobutton", and "checkbutton" Tcl commands. See the @@ -168,20 +192,38 @@ static void DestroyMenuButton _ANSI_ARGS_((char *memPtr)); */ int -Tk_MenubuttonCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ +Tk_MenubuttonObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Either NULL or pointer to + * option table. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { register TkMenuButton *mbPtr; - Tk_Window tkwin = (Tk_Window) clientData; - Tk_Window new; + Tk_OptionTable optionTable; + Tk_Window tkwin; + + optionTable = (Tk_OptionTable) clientData; + if (optionTable == NULL) { + Tcl_CmdInfo info; + char *name; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); + /* + * We haven't created the option table for this widget class + * yet. Do it now and save the table as the clientData for + * the command, so we'll have access to it in future + * invocations of the command. + */ + + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + name = Tcl_GetString(objv[0]); + Tcl_GetCommandInfo(interp, name, &info); + info.objClientData = (ClientData) optionTable; + Tcl_SetCommandInfo(interp, name, &info); + } + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } @@ -189,25 +231,28 @@ Tk_MenubuttonCmd(clientData, interp, argc, argv) * Create the new window. */ - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { + tkwin = Tk_CreateWindowFromPath(interp, + Tk_MainWindow(interp), Tcl_GetString(objv[1]), (char *) NULL); + if (tkwin == NULL) { return TCL_ERROR; } - Tk_SetClass(new, "Menubutton"); - mbPtr = TkpCreateMenuButton(new); + Tk_SetClass(tkwin, "Menubutton"); + mbPtr = TkpCreateMenuButton(tkwin); - TkSetClassProcs(new, &tkpMenubuttonClass, (ClientData) mbPtr); + TkSetClassProcs(tkwin, &tkpMenubuttonClass, (ClientData) mbPtr); /* * Initialize the data structure for the button. */ - mbPtr->tkwin = new; - mbPtr->display = Tk_Display (new); + mbPtr->tkwin = tkwin; + mbPtr->display = Tk_Display (tkwin); mbPtr->interp = interp; - mbPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(mbPtr->tkwin), - MenuButtonWidgetCmd, (ClientData) mbPtr, MenuButtonCmdDeletedProc); + mbPtr->widgetCmd = Tcl_CreateObjCommand(interp, + Tk_PathName(mbPtr->tkwin), MenuButtonWidgetObjCmd, + (ClientData) mbPtr, MenuButtonCmdDeletedProc); + mbPtr->optionTable = optionTable; mbPtr->menuName = NULL; mbPtr->text = NULL; mbPtr->underline = -1; @@ -215,7 +260,7 @@ Tk_MenubuttonCmd(clientData, interp, argc, argv) mbPtr->bitmap = None; mbPtr->imageString = NULL; mbPtr->image = NULL; - mbPtr->state = tkNormalUid; + mbPtr->state = STATE_NORMAL; mbPtr->normalBorder = NULL; mbPtr->activeBorder = NULL; mbPtr->borderWidth = 0; @@ -247,34 +292,35 @@ Tk_MenubuttonCmd(clientData, interp, argc, argv) mbPtr->indicatorOn = 0; mbPtr->indicatorWidth = 0; mbPtr->indicatorHeight = 0; + mbPtr->direction = DIRECTION_FLUSH; mbPtr->cursor = None; mbPtr->takeFocus = NULL; mbPtr->flags = 0; - if (aboveUid == NULL) { - aboveUid = Tk_GetUid("above"); - belowUid = Tk_GetUid("below"); - leftUid = Tk_GetUid("left"); - rightUid = Tk_GetUid("right"); - flushUid = Tk_GetUid("flush"); - } - mbPtr->direction = flushUid; Tk_CreateEventHandler(mbPtr->tkwin, ExposureMask|StructureNotifyMask|FocusChangeMask, MenuButtonEventProc, (ClientData) mbPtr); - if (ConfigureMenuButton(interp, mbPtr, argc-2, argv+2, 0) != TCL_OK) { + + if (Tk_InitOptions(interp, (char *) mbPtr, optionTable, tkwin) + != TCL_OK) { Tk_DestroyWindow(mbPtr->tkwin); return TCL_ERROR; } - interp->result = Tk_PathName(mbPtr->tkwin); + if (ConfigureMenuButton(interp, mbPtr, objc-2, objv+2) != TCL_OK) { + Tk_DestroyWindow(mbPtr->tkwin); + return TCL_ERROR; + } + + Tcl_SetStringObj(Tcl_GetObjResult(interp), Tk_PathName(mbPtr->tkwin), + -1); return TCL_OK; } /* *-------------------------------------------------------------- * - * MenuButtonWidgetCmd -- + * MenuButtonWidgetObjCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a widget managed by this module. @@ -290,56 +336,68 @@ Tk_MenubuttonCmd(clientData, interp, argc, argv) */ static int -MenuButtonWidgetCmd(clientData, interp, argc, argv) +MenuButtonWidgetObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about button widget. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { register TkMenuButton *mbPtr = (TkMenuButton *) clientData; - int result; - size_t length; - int c; + int result, index; + Tcl_Obj *objPtr; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option ?arg arg ...?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } + result = Tcl_GetIndexFromObj(interp, objv[1], + commandNames, "option", 0, &index); + if (result != TCL_OK) { + return result; + } Tcl_Preserve((ClientData) mbPtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - result = TCL_ERROR; - } else { - result = Tk_ConfigureValue(interp, mbPtr->tkwin, configSpecs, - (char *) mbPtr, argv[2], 0); + + switch (index) { + case COMMAND_CGET: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "cget option"); + goto error; + } + + objPtr = Tk_GetOptionValue(interp, (char *) mbPtr, + mbPtr->optionTable, objv[2], mbPtr->tkwin); + if (objPtr == NULL) { + goto error; + } else { + Tcl_SetObjResult(interp, objPtr); + } + break; } - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, mbPtr->tkwin, configSpecs, - (char *) mbPtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, mbPtr->tkwin, configSpecs, - (char *) mbPtr, argv[2], 0); - } else { - result = ConfigureMenuButton(interp, mbPtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); + + case COMMAND_CONFIGURE: { + if (objc <= 3) { + objPtr = Tk_GetOptionInfo(interp, (char *) mbPtr, + mbPtr->optionTable, + (objc == 3) ? objv[2] : (Tcl_Obj *) NULL, + mbPtr->tkwin); + if (objPtr == NULL) { + goto error; + } else { + Tcl_SetObjResult(interp, objPtr); + } + } else { + result = ConfigureMenuButton(interp, mbPtr, objc-2, + objv+2); + } + break; } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget or configure", - (char *) NULL); - result = TCL_ERROR; } Tcl_Release((ClientData) mbPtr); return result; + + error: + Tcl_Release((ClientData) mbPtr); + return TCL_ERROR; } /* @@ -348,9 +406,9 @@ MenuButtonWidgetCmd(clientData, interp, argc, argv) * DestroyMenuButton -- * * This procedure is invoked to recycle all of the resources - * associated with a button widget. It is invoked as a + * associated with a menubutton widget. It is invoked as a * when-idle handler in order to make sure that there is no - * other use of the button pending at the time of the deletion. + * other use of the menubutton pending at the time of the deletion. * * Results: * None. @@ -366,6 +424,11 @@ DestroyMenuButton(memPtr) char *memPtr; /* Info about button widget. */ { register TkMenuButton *mbPtr = (TkMenuButton *) memPtr; + TkpDestroyMenuButton(mbPtr); + + if (mbPtr->flags & REDRAW_PENDING) { + Tcl_CancelIdleCall(TkpDisplayMenuButton, (ClientData) mbPtr); + } /* * Free up all the stuff that requires special handling, then @@ -373,6 +436,7 @@ DestroyMenuButton(memPtr) * stuff. */ + Tcl_DeleteCommandFromToken(mbPtr->interp, mbPtr->widgetCmd); if (mbPtr->textVarName != NULL) { Tcl_UntraceVar(mbPtr->interp, mbPtr->textVarName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, @@ -387,15 +451,19 @@ DestroyMenuButton(memPtr) if (mbPtr->activeTextGC != None) { Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC); } + if (mbPtr->disabledGC != None) { + Tk_FreeGC(mbPtr->display, mbPtr->disabledGC); + } if (mbPtr->gray != None) { Tk_FreeBitmap(mbPtr->display, mbPtr->gray); } - if (mbPtr->disabledGC != None) { - Tk_FreeGC(mbPtr->display, mbPtr->disabledGC); + if (mbPtr->textLayout != NULL) { + Tk_FreeTextLayout(mbPtr->textLayout); } - Tk_FreeTextLayout(mbPtr->textLayout); - Tk_FreeOptions(configSpecs, (char *) mbPtr, mbPtr->display, 0); - ckfree((char *) mbPtr); + Tk_FreeConfigOptions((char *) mbPtr, mbPtr->optionTable, + mbPtr->tkwin); + mbPtr->tkwin = NULL; + Tcl_EventuallyFree((ClientData) mbPtr, TCL_DYNAMIC); } /* @@ -409,7 +477,7 @@ DestroyMenuButton(memPtr) * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, @@ -420,147 +488,174 @@ DestroyMenuButton(memPtr) */ static int -ConfigureMenuButton(interp, mbPtr, argc, argv, flags) +ConfigureMenuButton(interp, mbPtr, objc, objv) Tcl_Interp *interp; /* Used for error reporting. */ - register TkMenuButton *mbPtr; /* Information about widget; may or may - * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ + register TkMenuButton *mbPtr; + /* Information about widget; may or may + * not already have values for some + * fields. */ + int objc; /* Number of valid entries in objv. */ + Tcl_Obj *CONST objv[]; /* Arguments. */ { - int result; + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int error; Tk_Image image; /* - * Eliminate any existing trace on variables monitored by the menubutton. + * Eliminate any existing trace on variables monitored by the + * menubutton. */ if (mbPtr->textVarName != NULL) { - Tcl_UntraceVar(interp, mbPtr->textVarName, + Tcl_UntraceVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuButtonTextVarProc, (ClientData) mbPtr); } - result = Tk_ConfigureWidget(interp, mbPtr->tkwin, configSpecs, - argc, argv, (char *) mbPtr, flags); - if (result != TCL_OK) { - return TCL_ERROR; - } - /* - * A few options need special processing, such as setting the - * background from a 3-D border, or filling in complicated - * defaults that couldn't be specified to Tk_ConfigureWidget. + * The following loop is potentially executed twice. During the + * first pass configuration options get set to their new values. + * If there is an error in this pass, we execute a second pass + * to restore all the options to their previous values. */ - if ((mbPtr->state == tkActiveUid) && !Tk_StrictMotif(mbPtr->tkwin)) { - Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->activeBorder); - } else { - Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->normalBorder); - if ((mbPtr->state != tkNormalUid) && (mbPtr->state != tkActiveUid) - && (mbPtr->state != tkDisabledUid)) { - Tcl_AppendResult(interp, "bad state value \"", mbPtr->state, - "\": must be normal, active, or disabled", (char *) NULL); - mbPtr->state = tkNormalUid; - return TCL_ERROR; + for (error = 0; error <= 1; error++) { + if (!error) { + /* + * First pass: set options to new values. + */ + + if (Tk_SetOptions(interp, (char *) mbPtr, + mbPtr->optionTable, objc, objv, + mbPtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) { + continue; + } + } else { + /* + * Second pass: restore options to old values. + */ + + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); } - } - if ((mbPtr->direction != aboveUid) && (mbPtr->direction != belowUid) - && (mbPtr->direction != leftUid) && (mbPtr->direction != rightUid) - && (mbPtr->direction != flushUid)) { - Tcl_AppendResult(interp, "bad direction value \"", mbPtr->direction, - "\": must be above, below, left, right, or flush", - (char *) NULL); - mbPtr->direction = belowUid; - return TCL_ERROR; - } - - if (mbPtr->highlightWidth < 0) { - mbPtr->highlightWidth = 0; - } + /* + * A few options need special processing, such as setting the + * background from a 3-D border, or filling in complicated + * defaults that couldn't be specified to Tk_SetOptions. + */ - if (mbPtr->padX < 0) { - mbPtr->padX = 0; - } - if (mbPtr->padY < 0) { - mbPtr->padY = 0; - } + if ((mbPtr->state == STATE_ACTIVE) + && !Tk_StrictMotif(mbPtr->tkwin)) { + Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->activeBorder); + } else { + Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->normalBorder); + } - /* - * Get the image for the widget, if there is one. Allocate the - * new image before freeing the old one, so that the reference - * count doesn't go to zero and cause image data to be discarded. - */ + if (mbPtr->highlightWidth < 0) { + mbPtr->highlightWidth = 0; + } - if (mbPtr->imageString != NULL) { - image = Tk_GetImage(mbPtr->interp, mbPtr->tkwin, - mbPtr->imageString, MenuButtonImageProc, (ClientData) mbPtr); - if (image == NULL) { - return TCL_ERROR; + if (mbPtr->padX < 0) { + mbPtr->padX = 0; + } + if (mbPtr->padY < 0) { + mbPtr->padY = 0; } - } else { - image = NULL; - } - if (mbPtr->image != NULL) { - Tk_FreeImage(mbPtr->image); - } - mbPtr->image = image; - if ((mbPtr->image == NULL) && (mbPtr->bitmap == None) - && (mbPtr->textVarName != NULL)) { /* - * The menubutton displays a variable. Set up a trace to watch - * for any changes in it. + * Get the image for the widget, if there is one. Allocate the + * new image before freeing the old one, so that the reference + * count doesn't go to zero and cause image data to be discarded. */ - char *value; + if (mbPtr->imageString != NULL) { + image = Tk_GetImage(mbPtr->interp, mbPtr->tkwin, + mbPtr->imageString, MenuButtonImageProc, + (ClientData) mbPtr); + if (image == NULL) { + return TCL_ERROR; + } + } else { + image = NULL; + } + if (mbPtr->image != NULL) { + Tk_FreeImage(mbPtr->image); + } + mbPtr->image = image; - value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY); - if (value == NULL) { - Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text, - TCL_GLOBAL_ONLY); + /* + * Recompute the geometry for the button. + */ + + if ((mbPtr->bitmap != None) || (mbPtr->image != NULL)) { + if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->widthString, + &mbPtr->width) != TCL_OK) { + widthError: + Tcl_AddErrorInfo(interp, "\n (processing -width option)"); + continue; + } + if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->heightString, + &mbPtr->height) != TCL_OK) { + heightError: + Tcl_AddErrorInfo(interp, "\n (processing -height option)"); + continue; + } } else { - if (mbPtr->text != NULL) { - ckfree(mbPtr->text); + if (Tcl_GetInt(interp, mbPtr->widthString, &mbPtr->width) + != TCL_OK) { + goto widthError; + } + if (Tcl_GetInt(interp, mbPtr->heightString, &mbPtr->height) + != TCL_OK) { + goto heightError; } - mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1)); - strcpy(mbPtr->text, value); } - Tcl_TraceVar(interp, mbPtr->textVarName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - MenuButtonTextVarProc, (ClientData) mbPtr); + break; } - /* - * Recompute the geometry for the button. - */ + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + } - if ((mbPtr->bitmap != None) || (mbPtr->image != NULL)) { - if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->widthString, - &mbPtr->width) != TCL_OK) { - widthError: - Tcl_AddErrorInfo(interp, "\n (processing -width option)"); - return TCL_ERROR; - } - if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->heightString, - &mbPtr->height) != TCL_OK) { - heightError: - Tcl_AddErrorInfo(interp, "\n (processing -height option)"); - return TCL_ERROR; - } - } else { - if (Tcl_GetInt(interp, mbPtr->widthString, &mbPtr->width) - != TCL_OK) { - goto widthError; - } - if (Tcl_GetInt(interp, mbPtr->heightString, &mbPtr->height) - != TCL_OK) { - goto heightError; - } + if ((mbPtr->image == NULL) && (mbPtr->bitmap == None) + && (mbPtr->textVarName != NULL)) { + + /* + * The menubutton displays the value of a variable. + * Set up a trace to watch for any changes in it, create + * the variable if it doesn't exist, and fetch its + * current value. + */ + + char *value; + + value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY); + if (value == NULL) { + Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text, + TCL_GLOBAL_ONLY); + } else { + if (mbPtr->text != NULL) { + ckfree(mbPtr->text); + } + mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1)); + strcpy(mbPtr->text, value); + } + Tcl_TraceVar(interp, mbPtr->textVarName, + TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + MenuButtonTextVarProc, (ClientData) mbPtr); } + TkMenuButtonWorldChanged((ClientData) mbPtr); - return TCL_OK; + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + return TCL_OK; + } } /* @@ -605,8 +700,7 @@ TkMenuButtonWorldChanged(instanceData) gcValues.graphics_exposures = False; mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures; - gc = Tk_GetGCColor(mbPtr->tkwin, mask, &gcValues, mbPtr->normalFg, - Tk_3DBorderColor(mbPtr->normalBorder)); + gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues); if (mbPtr->normalTextGC != None) { Tk_FreeGC(mbPtr->display, mbPtr->normalTextGC); } @@ -616,8 +710,7 @@ TkMenuButtonWorldChanged(instanceData) gcValues.foreground = mbPtr->activeFg->pixel; gcValues.background = Tk_3DBorderColor(mbPtr->activeBorder)->pixel; mask = GCForeground | GCBackground | GCFont; - gc = Tk_GetGCColor(mbPtr->tkwin, mask, &gcValues, mbPtr->activeFg, - Tk_3DBorderColor(mbPtr->activeBorder)); + gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues); if (mbPtr->activeTextGC != None) { Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC); } @@ -627,11 +720,11 @@ TkMenuButtonWorldChanged(instanceData) background = Tk_3DBorderColor(mbPtr->normalBorder); gcValues.background = background->pixel; if ((mbPtr->disabledFg != NULL) && (mbPtr->imageString == NULL)) { - foreground = mbPtr->disabledFg; + foreground = mbPtr->disabledFg; gcValues.foreground = foreground->pixel; mask = GCForeground | GCBackground | GCFont; } else { - foreground = background; + foreground = background; background = NULL; gcValues.foreground = gcValues.background; mask = GCForeground; @@ -645,7 +738,7 @@ TkMenuButtonWorldChanged(instanceData) mask |= GCFillStyle | GCStipple; } } - gc = Tk_GetGCColor(mbPtr->tkwin, mask, &gcValues, foreground, background); + gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues); if (mbPtr->disabledGC != None) { Tk_FreeGC(mbPtr->display, mbPtr->disabledGC); } @@ -697,15 +790,7 @@ MenuButtonEventProc(clientData, eventPtr) goto redraw; } else if (eventPtr->type == DestroyNotify) { - TkpDestroyMenuButton(mbPtr); - if (mbPtr->tkwin != NULL) { - mbPtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(mbPtr->interp, mbPtr->widgetCmd); - } - if (mbPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(TkpDisplayMenuButton, (ClientData) mbPtr); - } - Tcl_EventuallyFree((ClientData) mbPtr, DestroyMenuButton); + DestroyMenuButton((char *) mbPtr); } else if (eventPtr->type == FocusIn) { if (eventPtr->xfocus.detail != NotifyInferior) { mbPtr->flags |= GOT_FOCUS; @@ -763,7 +848,6 @@ MenuButtonCmdDeletedProc(clientData) */ if (tkwin != NULL) { - mbPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); } } @@ -870,3 +954,4 @@ MenuButtonImageProc(clientData, x, y, width, height, imgWidth, imgHeight) } } } + diff --git a/tk/generic/tkMenubutton.h b/tk/generic/tkMenubutton.h index b2382c6bde6..2bca6431e73 100644 --- a/tk/generic/tkMenubutton.h +++ b/tk/generic/tkMenubutton.h @@ -25,6 +25,23 @@ #endif /* + * Legal values for the "orient" field of TkMenubutton records. + */ + +enum direction { + DIRECTION_ABOVE, DIRECTION_BELOW, DIRECTION_FLUSH, + DIRECTION_LEFT, DIRECTION_RIGHT +}; + +/* + * Legal values for the "state" field of TkMenubutton records. + */ + +enum state { + STATE_ACTIVE, STATE_DISABLED, STATE_NORMAL +}; + +/* * A data structure of the following type is kept for each * widget managed by this file: */ @@ -39,6 +56,8 @@ typedef struct { * freed up even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with menubutton. */ Tcl_Command widgetCmd; /* Token for menubutton's widget command. */ + Tk_OptionTable optionTable; /* Table that defines configuration options + * available for this widget. */ char *menuName; /* Name of menu associated with widget. * Malloc-ed. */ @@ -65,7 +84,7 @@ typedef struct { * Information used when displaying widget: */ - Tk_Uid state; /* State of button for display purposes: + enum state state; /* State of button for display purposes: * normal, active, or disabled. */ Tk_3DBorder normalBorder; /* Structure used to draw 3-D * border and background when window @@ -143,7 +162,7 @@ typedef struct { * Miscellaneous information: */ - Tk_Uid direction; /* Direction for where to pop the menu. + enum direction direction; /* Direction for where to pop the menu. * Valid directions are "above", "below", * "left", "right", and "flush". "flush" * means that the upper left corner of the @@ -213,3 +232,4 @@ EXTERN void TkMenuButtonWorldChanged _ANSI_ARGS_(( # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TKMENUBUTTON */ + diff --git a/tk/generic/tkMessage.c b/tk/generic/tkMessage.c index e1313bb6bff..eabffe0197c 100644 --- a/tk/generic/tkMessage.c +++ b/tk/generic/tkMessage.c @@ -6,7 +6,7 @@ * in a window according to a particular aspect ratio. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -40,7 +40,7 @@ typedef struct { char *string; /* String displayed in message. */ int numChars; /* Number of characters in string, not - * including terminating NULL character. */ + * including terminating NULL. */ char *textVarName; /* Name of variable (malloc'ed) or NULL. * If non-NULL, message displays the contents * of this variable. */ @@ -274,7 +274,7 @@ Tk_MessageCmd(clientData, interp, argc, argv) goto error; } - interp->result = Tk_PathName(msgPtr->tkwin); + Tcl_SetResult(interp, Tk_PathName(msgPtr->tkwin), TCL_STATIC); return TCL_OK; error: @@ -401,7 +401,7 @@ DestroyMessage(memPtr) * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, @@ -465,9 +465,7 @@ ConfigureMessage(interp, msgPtr, argc, argv, flags) * that couldn't be specified to Tk_ConfigureWidget. */ - msgPtr->numChars = strlen(msgPtr->string); - - Tk_SetBackgroundFromBorder(msgPtr->tkwin, msgPtr->border); + msgPtr->numChars = Tcl_NumUtfChars(msgPtr->string, -1); if (msgPtr->highlightWidth < 0) { msgPtr->highlightWidth = 0; @@ -500,16 +498,19 @@ MessageWorldChanged(instanceData) ClientData instanceData; /* Information about widget. */ { XGCValues gcValues; - GC gc; + GC gc = None; Tk_FontMetrics fm; Message *msgPtr; msgPtr = (Message *) instanceData; + if (msgPtr->border != NULL) { + Tk_SetBackgroundFromBorder(msgPtr->tkwin, msgPtr->border); + } + gcValues.font = Tk_FontId(msgPtr->tkfont); gcValues.foreground = msgPtr->fgColorPtr->pixel; - gc = Tk_GetGCColor(msgPtr->tkwin, GCForeground | GCFont, &gcValues, - msgPtr->fgColorPtr, NULL); + gc = Tk_GetGC(msgPtr->tkwin, GCForeground | GCFont, &gcValues); if (msgPtr->textGC != None) { Tk_FreeGC(msgPtr->display, msgPtr->textGC); } @@ -645,13 +646,23 @@ DisplayMessage(clientData) register Message *msgPtr = (Message *) clientData; register Tk_Window tkwin = msgPtr->tkwin; int x, y; + int borderWidth = msgPtr->highlightWidth; msgPtr->flags &= ~REDRAW_PENDING; if ((msgPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border, 0, 0, - Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); + if (msgPtr->border != NULL) { + borderWidth += msgPtr->borderWidth; + } + if (msgPtr->relief == TK_RELIEF_FLAT) { + borderWidth = msgPtr->highlightWidth; + } + Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border, + borderWidth, borderWidth, + Tk_Width(tkwin) - 2 * borderWidth, + Tk_Height(tkwin) - 2 * borderWidth, + 0, TK_RELIEF_FLAT); /* * Compute starting y-location for message based on message size @@ -663,7 +674,7 @@ DisplayMessage(clientData) Tk_DrawTextLayout(Tk_Display(tkwin), Tk_WindowId(tkwin), msgPtr->textGC, msgPtr->textLayout, x, y, 0, -1); - if (msgPtr->relief != TK_RELIEF_FLAT) { + if (borderWidth > msgPtr->highlightWidth) { Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), msgPtr->border, msgPtr->highlightWidth, msgPtr->highlightWidth, Tk_Width(tkwin) - 2*msgPtr->highlightWidth, @@ -671,15 +682,17 @@ DisplayMessage(clientData) msgPtr->borderWidth, msgPtr->relief); } if (msgPtr->highlightWidth != 0) { - GC gc; + GC fgGC, bgGC; + bgGC = Tk_GCForColor(msgPtr->highlightBgColorPtr, Tk_WindowId(tkwin)); if (msgPtr->flags & GOT_FOCUS) { - gc = Tk_GCForColor(msgPtr->highlightColorPtr, Tk_WindowId(tkwin)); + fgGC = Tk_GCForColor(msgPtr->highlightColorPtr, Tk_WindowId(tkwin)); + TkpDrawHighlightBorder(tkwin, fgGC, bgGC, msgPtr->highlightWidth, + Tk_WindowId(tkwin)); } else { - gc = Tk_GCForColor(msgPtr->highlightBgColorPtr, Tk_WindowId(tkwin)); + TkpDrawHighlightBorder(tkwin, bgGC, bgGC, msgPtr->highlightWidth, + Tk_WindowId(tkwin)); } - Tk_DrawFocusHighlight(tkwin, gc, msgPtr->highlightWidth, - Tk_WindowId(tkwin)); } } @@ -835,8 +848,8 @@ MessageTextVarProc(clientData, interp, name1, name2, flags) if (msgPtr->string != NULL) { ckfree(msgPtr->string); } - msgPtr->numChars = strlen(value); - msgPtr->string = (char *) ckalloc((unsigned) (msgPtr->numChars + 1)); + msgPtr->numChars = Tcl_NumUtfChars(value, -1); + msgPtr->string = (char *) ckalloc((unsigned) (strlen(value) + 1)); strcpy(msgPtr->string, value); ComputeMessageGeometry(msgPtr); @@ -847,3 +860,4 @@ MessageTextVarProc(clientData, interp, name1, name2, flags) } return (char *) NULL; } + diff --git a/tk/generic/tkObj.c b/tk/generic/tkObj.c new file mode 100644 index 00000000000..071cb383f43 --- /dev/null +++ b/tk/generic/tkObj.c @@ -0,0 +1,660 @@ +/* + * tkObj.c -- + * + * This file contains procedures that implement the common Tk object + * types + * + * Copyright (c) 1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +#include "tkInt.h" + +/* + * The following structure is the internal representation for pixel objects. + */ + +typedef struct PixelRep { + double value; + int units; + Tk_Window tkwin; + int returnValue; +} PixelRep; + +#define SIMPLE_PIXELREP(objPtr) \ + ((objPtr)->internalRep.twoPtrValue.ptr2 == 0) + +#define SET_SIMPLEPIXEL(objPtr, intval) \ + (objPtr)->internalRep.twoPtrValue.ptr1 = (VOID *) (intval); \ + (objPtr)->internalRep.twoPtrValue.ptr2 = 0 + +#define GET_SIMPLEPIXEL(objPtr) \ + ((int) (objPtr)->internalRep.twoPtrValue.ptr1) + +#define SET_COMPLEXPIXEL(objPtr, repPtr) \ + (objPtr)->internalRep.twoPtrValue.ptr1 = 0; \ + (objPtr)->internalRep.twoPtrValue.ptr2 = (VOID *) repPtr + +#define GET_COMPLEXPIXEL(objPtr) \ + ((PixelRep *) (objPtr)->internalRep.twoPtrValue.ptr2) + + +/* + * The following structure is the internal representation for mm objects. + */ + +typedef struct MMRep { + double value; + int units; + Tk_Window tkwin; + double returnValue; +} MMRep; + +/* + * Prototypes for procedures defined later in this file: + */ + +static void DupMMInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, + Tcl_Obj *copyPtr)); +static void DupPixelInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, + Tcl_Obj *copyPtr)); +static void FreeMMInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr)); +static void FreePixelInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr)); +static int SetMMFromAny _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr)); +static int SetPixelFromAny _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr)); +static int SetWindowFromAny _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr)); + +/* + * The following structure defines the implementation of the "pixel" + * Tcl object, used for measuring distances. The pixel object remembers + * its initial display-independant settings. + */ + +static Tcl_ObjType pixelObjType = { + "pixel", /* name */ + FreePixelInternalRep, /* freeIntRepProc */ + DupPixelInternalRep, /* dupIntRepProc */ + NULL, /* updateStringProc */ + SetPixelFromAny /* setFromAnyProc */ +}; + +/* + * The following structure defines the implementation of the "pixel" + * Tcl object, used for measuring distances. The pixel object remembers + * its initial display-independant settings. + */ + +static Tcl_ObjType mmObjType = { + "mm", /* name */ + FreeMMInternalRep, /* freeIntRepProc */ + DupMMInternalRep, /* dupIntRepProc */ + NULL, /* updateStringProc */ + SetMMFromAny /* setFromAnyProc */ +}; + +/* + * The following structure defines the implementation of the "window" + * Tcl object. + */ + +static Tcl_ObjType windowObjType = { + "window", /* name */ + (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */ + (Tcl_DupInternalRepProc *) NULL, /* dupIntRepProc */ + NULL, /* updateStringProc */ + SetWindowFromAny /* setFromAnyProc */ +}; + + + +/* + *---------------------------------------------------------------------- + * + * Tk_GetPixelsFromObj -- + * + * Attempt to return a pixel value from the Tcl object "objPtr". If the + * object is not already a pixel value, an attempt will be made to convert + * it to one. + * + * Results: + * The return value is a standard Tcl object result. If an error occurs + * during conversion, an error message is left in the interpreter's + * result unless "interp" is NULL. + * + * Side effects: + * If the object is not already a pixel, the conversion will free + * any old internal representation. + * + *---------------------------------------------------------------------- + */ + +int +Tk_GetPixelsFromObj(interp, tkwin, objPtr, intPtr) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + Tk_Window tkwin; + Tcl_Obj *objPtr; /* The object from which to get pixels. */ + int *intPtr; /* Place to store resulting pixels. */ +{ + int result; + double d; + PixelRep *pixelPtr; + static double bias[] = { + 1.0, 10.0, 25.4, 25.4 / 72.0 + }; + + if (objPtr->typePtr != &pixelObjType) { + result = SetPixelFromAny(interp, objPtr); + if (result != TCL_OK) { + return result; + } + } + + if (SIMPLE_PIXELREP(objPtr)) { + *intPtr = GET_SIMPLEPIXEL(objPtr); + } else { + pixelPtr = GET_COMPLEXPIXEL(objPtr); + if (pixelPtr->tkwin != tkwin) { + d = pixelPtr->value; + if (pixelPtr->units >= 0) { + d *= bias[pixelPtr->units] * WidthOfScreen(Tk_Screen(tkwin)); + d /= WidthMMOfScreen(Tk_Screen(tkwin)); + } + if (d < 0) { + pixelPtr->returnValue = (int) (d - 0.5); + } else { + pixelPtr->returnValue = (int) (d + 0.5); + } + pixelPtr->tkwin = tkwin; + } + *intPtr = pixelPtr->returnValue; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FreePixelInternalRep -- + * + * Deallocate the storage associated with a pixel object's internal + * representation. + * + * Results: + * None. + * + * Side effects: + * Frees objPtr's internal representation and sets objPtr's + * internalRep to NULL. + * + *---------------------------------------------------------------------- + */ + +static void +FreePixelInternalRep(objPtr) + Tcl_Obj *objPtr; /* Pixel object with internal rep to free. */ +{ + PixelRep *pixelPtr; + + if (!SIMPLE_PIXELREP(objPtr)) { + pixelPtr = GET_COMPLEXPIXEL(objPtr); + ckfree((char *) pixelPtr); + } + SET_SIMPLEPIXEL(objPtr, 0); +} + +/* + *---------------------------------------------------------------------- + * + * DupPixelInternalRep -- + * + * Initialize the internal representation of a pixel Tcl_Obj to a + * copy of the internal representation of an existing pixel object. + * + * Results: + * None. + * + * Side effects: + * copyPtr's internal rep is set to the pixel corresponding to + * srcPtr's internal rep. + * + *---------------------------------------------------------------------- + */ + +static void +DupPixelInternalRep(srcPtr, copyPtr) + register Tcl_Obj *srcPtr; /* Object with internal rep to copy. */ + register Tcl_Obj *copyPtr; /* Object with internal rep to set. */ +{ + PixelRep *oldPtr, *newPtr; + + copyPtr->typePtr = srcPtr->typePtr; + + if (SIMPLE_PIXELREP(srcPtr)) { + SET_SIMPLEPIXEL(copyPtr, GET_SIMPLEPIXEL(srcPtr)); + } else { + oldPtr = GET_COMPLEXPIXEL(srcPtr); + newPtr = (PixelRep *) ckalloc(sizeof(PixelRep)); + newPtr->value = oldPtr->value; + newPtr->units = oldPtr->units; + newPtr->tkwin = oldPtr->tkwin; + newPtr->returnValue = oldPtr->returnValue; + SET_COMPLEXPIXEL(copyPtr, newPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * SetPixelFromAny -- + * + * Attempt to generate a pixel internal form for the Tcl object + * "objPtr". + * + * Results: + * The return value is a standard Tcl result. If an error occurs during + * conversion, an error message is left in the interpreter's result + * unless "interp" is NULL. + * + * Side effects: + * If no error occurs, a pixel representation of the object is + * stored internally and the type of "objPtr" is set to pixel. + * + *---------------------------------------------------------------------- + */ + +static int +SetPixelFromAny(interp, objPtr) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + Tcl_Obj *objPtr; /* The object to convert. */ +{ + Tcl_ObjType *typePtr; + char *string, *rest; + double d; + int i, units; + PixelRep *pixelPtr; + + string = Tcl_GetStringFromObj(objPtr, NULL); + + d = strtod(string, &rest); + if (rest == string) { + /* + * Must copy string before resetting the result in case a caller + * is trying to convert the interpreter's result to pixels. + */ + + char buf[100]; + + error: + sprintf(buf, "bad screen distance \"%.50s\"", string); + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, buf, NULL); + return TCL_ERROR; + } + while ((*rest != '\0') && isspace(UCHAR(*rest))) { + rest++; + } + switch (*rest) { + case '\0': + units = -1; + break; + + case 'm': + units = 0; + break; + + case 'c': + units = 1; + break; + + case 'i': + units = 2; + break; + + case 'p': + units = 3; + break; + + default: + goto error; + } + + /* + * Free the old internalRep before setting the new one. + */ + + typePtr = objPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(objPtr); + } + + objPtr->typePtr = &pixelObjType; + + i = (int) d; + if ((units < 0) && (i == d)) { + SET_SIMPLEPIXEL(objPtr, i); + } else { + pixelPtr = (PixelRep *) ckalloc(sizeof(PixelRep)); + pixelPtr->value = d; + pixelPtr->units = units; + pixelPtr->tkwin = NULL; + pixelPtr->returnValue = i; + SET_COMPLEXPIXEL(objPtr, pixelPtr); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetMMFromObj -- + * + * Attempt to return an mm value from the Tcl object "objPtr". If the + * object is not already an mm value, an attempt will be made to convert + * it to one. + * + * Results: + * The return value is a standard Tcl object result. If an error occurs + * during conversion, an error message is left in the interpreter's + * result unless "interp" is NULL. + * + * Side effects: + * If the object is not already a pixel, the conversion will free + * any old internal representation. + * + *---------------------------------------------------------------------- + */ + +int +Tk_GetMMFromObj(interp, tkwin, objPtr, doublePtr) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + Tk_Window tkwin; + Tcl_Obj *objPtr; /* The object from which to get mms. */ + double *doublePtr; /* Place to store resulting millimeters. */ +{ + int result; + double d; + MMRep *mmPtr; + static double bias[] = { + 10.0, 25.4, 1.0, 25.4 / 72.0 + }; + + if (objPtr->typePtr != &mmObjType) { + result = SetMMFromAny(interp, objPtr); + if (result != TCL_OK) { + return result; + } + } + + mmPtr = (MMRep *) objPtr->internalRep.otherValuePtr; + if (mmPtr->tkwin != tkwin) { + d = mmPtr->value; + if (mmPtr->units == -1) { + d /= WidthOfScreen(Tk_Screen(tkwin)); + d *= WidthMMOfScreen(Tk_Screen(tkwin)); + } else { + d *= bias[mmPtr->units]; + } + mmPtr->tkwin = tkwin; + mmPtr->returnValue = d; + } + *doublePtr = mmPtr->returnValue; + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FreeMMInternalRep -- + * + * Deallocate the storage associated with a mm object's internal + * representation. + * + * Results: + * None. + * + * Side effects: + * Frees objPtr's internal representation and sets objPtr's + * internalRep to NULL. + * + *---------------------------------------------------------------------- + */ + +static void +FreeMMInternalRep(objPtr) + Tcl_Obj *objPtr; /* MM object with internal rep to free. */ +{ + ckfree((char *) objPtr->internalRep.otherValuePtr); + objPtr->internalRep.otherValuePtr = NULL; +} + +/* + *---------------------------------------------------------------------- + * + * DupMMInternalRep -- + * + * Initialize the internal representation of a pixel Tcl_Obj to a + * copy of the internal representation of an existing pixel object. + * + * Results: + * None. + * + * Side effects: + * copyPtr's internal rep is set to the pixel corresponding to + * srcPtr's internal rep. + * + *---------------------------------------------------------------------- + */ + +static void +DupMMInternalRep(srcPtr, copyPtr) + register Tcl_Obj *srcPtr; /* Object with internal rep to copy. */ + register Tcl_Obj *copyPtr; /* Object with internal rep to set. */ +{ + MMRep *oldPtr, *newPtr; + + copyPtr->typePtr = srcPtr->typePtr; + oldPtr = (MMRep *) srcPtr->internalRep.otherValuePtr; + newPtr = (MMRep *) ckalloc(sizeof(MMRep)); + newPtr->value = oldPtr->value; + newPtr->units = oldPtr->units; + newPtr->tkwin = oldPtr->tkwin; + newPtr->returnValue = oldPtr->returnValue; + copyPtr->internalRep.otherValuePtr = (VOID *) newPtr; +} + +/* + *---------------------------------------------------------------------- + * + * SetMMFromAny -- + * + * Attempt to generate a mm internal form for the Tcl object + * "objPtr". + * + * Results: + * The return value is a standard Tcl result. If an error occurs during + * conversion, an error message is left in the interpreter's result + * unless "interp" is NULL. + * + * Side effects: + * If no error occurs, a mm representation of the object is + * stored internally and the type of "objPtr" is set to mm. + * + *---------------------------------------------------------------------- + */ + +static int +SetMMFromAny(interp, objPtr) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + Tcl_Obj *objPtr; /* The object to convert. */ +{ + Tcl_ObjType *typePtr; + char *string, *rest; + double d; + int units; + MMRep *mmPtr; + + string = Tcl_GetStringFromObj(objPtr, NULL); + + d = strtod(string, &rest); + if (rest == string) { + /* + * Must copy string before resetting the result in case a caller + * is trying to convert the interpreter's result to mms. + */ + + error: + Tcl_AppendResult(interp, "bad screen distance \"", string, + "\"", (char *) NULL); + return TCL_ERROR; + } + while ((*rest != '\0') && isspace(UCHAR(*rest))) { + rest++; + } + switch (*rest) { + case '\0': + units = -1; + break; + + case 'c': + units = 0; + break; + + case 'i': + units = 1; + break; + + case 'm': + units = 2; + break; + + case 'p': + units = 3; + break; + + default: + goto error; + } + + /* + * Free the old internalRep before setting the new one. + */ + + typePtr = objPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(objPtr); + } + + objPtr->typePtr = &mmObjType; + + mmPtr = (MMRep *) ckalloc(sizeof(MMRep)); + mmPtr->value = d; + mmPtr->units = units; + mmPtr->tkwin = NULL; + mmPtr->returnValue = d; + objPtr->internalRep.otherValuePtr = (VOID *) mmPtr; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TkGetWindowFromObj -- + * + * Attempt to return a Tk_Window from the Tcl object "objPtr". If the + * object is not already a Tk_Window, an attempt will be made to convert + * it to one. + * + * Results: + * The return value is a standard Tcl object result. If an error occurs + * during conversion, an error message is left in the interpreter's + * result unless "interp" is NULL. + * + * Side effects: + * If the object is not already a Tk_Window, the conversion will free + * any old internal representation. + * + *---------------------------------------------------------------------- + */ + +int +TkGetWindowFromObj(interp, tkwin, objPtr, windowPtr) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + Tk_Window tkwin; /* A token to get the main window from. */ + register Tcl_Obj *objPtr; /* The object from which to get boolean. */ + Tk_Window *windowPtr; /* Place to store resulting window. */ +{ + register int result; + Tk_Window lastWindow; + + result = SetWindowFromAny(interp, objPtr); + if (result != TCL_OK) { + return result; + } + + lastWindow = (Tk_Window) objPtr->internalRep.twoPtrValue.ptr1; + if (tkwin != lastWindow) { + Tk_Window foundWindow = Tk_NameToWindow(interp, + Tcl_GetStringFromObj(objPtr, NULL), tkwin); + + if (foundWindow == NULL) { + return TCL_ERROR; + } + objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) tkwin; + objPtr->internalRep.twoPtrValue.ptr2 = (VOID *) foundWindow; + } + *windowPtr = (Tk_Window) objPtr->internalRep.twoPtrValue.ptr2; + + return result; +} + +/* + *---------------------------------------------------------------------- + * + * SetWindowFromAny -- + * + * Attempt to generate a Tk_Window internal form for the Tcl object + * "objPtr". + * + * Results: + * The return value is a standard Tcl result. If an error occurs during + * conversion, an error message is left in the interpreter's result + * unless "interp" is NULL. + * + * Side effects: + * If no error occurs, a standard window value is stored as "objPtr"s + * internal representation and the type of "objPtr" is set to Tk_Window. + * + *---------------------------------------------------------------------- + */ + +static int +SetWindowFromAny(interp, objPtr) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + register Tcl_Obj *objPtr; /* The object to convert. */ +{ + Tcl_ObjType *typePtr; + + /* + * Free the old internalRep before setting the new one. + */ + + Tcl_GetStringFromObj(objPtr, NULL); + typePtr = objPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(objPtr); + } + objPtr->typePtr = &windowObjType; + objPtr->internalRep.twoPtrValue.ptr1 = NULL; + objPtr->internalRep.twoPtrValue.ptr2 = NULL; + + return TCL_OK; +} + diff --git a/tk/generic/tkOldConfig.c b/tk/generic/tkOldConfig.c new file mode 100644 index 00000000000..18b22e451ee --- /dev/null +++ b/tk/generic/tkOldConfig.c @@ -0,0 +1,1023 @@ +/* + * tkOldConfig.c -- + * + * This file contains the Tk_ConfigureWidget procedure. THIS FILE + * IS HERE FOR BACKWARD COMPATIBILITY; THE NEW CONFIGURATION + * PACKAGE SHOULD BE USED FOR NEW PROJECTS. + * + * Copyright (c) 1990-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +#include "tkPort.h" +#include "tk.h" + +/* + * Values for "flags" field of Tk_ConfigSpec structures. Be sure + * to coordinate these values with those defined in tk.h + * (TK_CONFIG_COLOR_ONLY, etc.). There must not be overlap! + * + * INIT - Non-zero means (char *) things have been + * converted to Tk_Uid's. + */ + +#define INIT 0x20 + +/* + * Forward declarations for procedures defined later in this file: + */ + +static int DoConfig _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, Tk_ConfigSpec *specPtr, + Tk_Uid value, int valueIsUid, char *widgRec)); +static Tk_ConfigSpec * FindConfigSpec _ANSI_ARGS_((Tcl_Interp *interp, + Tk_ConfigSpec *specs, char *argvName, + int needFlags, int hateFlags)); +static char * FormatConfigInfo _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, Tk_ConfigSpec *specPtr, + char *widgRec)); +static char * FormatConfigValue _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, Tk_ConfigSpec *specPtr, + char *widgRec, char *buffer, + Tcl_FreeProc **freeProcPtr)); + +/* + *-------------------------------------------------------------- + * + * Tk_ConfigureWidget -- + * + * Process command-line options and database options to + * fill in fields of a widget record with resources and + * other parameters. + * + * Results: + * A standard Tcl return value. In case of an error, + * the interp's result will hold an error message. + * + * Side effects: + * The fields of widgRec get filled in with information + * from argc/argv and the option database. Old information + * in widgRec's fields gets recycled. + * + *-------------------------------------------------------------- + */ + +int +Tk_ConfigureWidget(interp, tkwin, specs, argc, argv, widgRec, flags) + Tcl_Interp *interp; /* Interpreter for error reporting. */ + Tk_Window tkwin; /* Window containing widget (needed to + * set up X resources). */ + Tk_ConfigSpec *specs; /* Describes legal options. */ + int argc; /* Number of elements in argv. */ + char **argv; /* Command-line options. */ + char *widgRec; /* Record whose fields are to be + * modified. Values must be properly + * initialized. */ + int flags; /* Used to specify additional flags + * that must be present in config specs + * for them to be considered. Also, + * may have TK_CONFIG_ARGV_ONLY set. */ +{ + register Tk_ConfigSpec *specPtr; + Tk_Uid value; /* Value of option from database. */ + int needFlags; /* Specs must contain this set of flags + * or else they are not considered. */ + int hateFlags; /* If a spec contains any bits here, it's + * not considered. */ + + if (tkwin == NULL) { + /* + * Either we're not really in Tk, or the main window was destroyed and + * we're on our way out of the application + */ + Tcl_AppendResult(interp, "NULL main window", (char *)NULL); + return TCL_ERROR; + } + + needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); + if (Tk_Depth(tkwin) <= 1) { + hateFlags = TK_CONFIG_COLOR_ONLY; + } else { + hateFlags = TK_CONFIG_MONO_ONLY; + } + + /* + * Pass one: scan through all the option specs, replacing strings + * with Tk_Uid structs (if this hasn't been done already) and + * clearing the TK_CONFIG_OPTION_SPECIFIED flags. + */ + + for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { + if (!(specPtr->specFlags & INIT) && (specPtr->argvName != NULL)) { + if (specPtr->dbName != NULL) { + specPtr->dbName = Tk_GetUid(specPtr->dbName); + } + if (specPtr->dbClass != NULL) { + specPtr->dbClass = Tk_GetUid(specPtr->dbClass); + } + if (specPtr->defValue != NULL) { + specPtr->defValue = Tk_GetUid(specPtr->defValue); + } + } + specPtr->specFlags = (specPtr->specFlags & ~TK_CONFIG_OPTION_SPECIFIED) + | INIT; + } + + /* + * Pass two: scan through all of the arguments, processing those + * that match entries in the specs. + */ + + for ( ; argc > 0; argc -= 2, argv += 2) { + char *arg; + + if (flags & TK_CONFIG_OBJS) { + arg = Tcl_GetStringFromObj((Tcl_Obj *) *argv, NULL); + } else { + arg = *argv; + } + specPtr = FindConfigSpec(interp, specs, arg, needFlags, hateFlags); + if (specPtr == NULL) { + return TCL_ERROR; + } + + /* + * Process the entry. + */ + + if (argc < 2) { + Tcl_AppendResult(interp, "value for \"", arg, + "\" missing", (char *) NULL); + return TCL_ERROR; + } + if (flags & TK_CONFIG_OBJS) { + arg = Tcl_GetString((Tcl_Obj *) argv[1]); + } else { + arg = argv[1]; + } + if (DoConfig(interp, tkwin, specPtr, arg, 0, widgRec) != TCL_OK) { + char msg[100]; + + sprintf(msg, "\n (processing \"%.40s\" option)", + specPtr->argvName); + Tcl_AddErrorInfo(interp, msg); + return TCL_ERROR; + } + specPtr->specFlags |= TK_CONFIG_OPTION_SPECIFIED; + } + + /* + * Pass three: scan through all of the specs again; if no + * command-line argument matched a spec, then check for info + * in the option database. If there was nothing in the + * database, then use the default. + */ + + if (!(flags & TK_CONFIG_ARGV_ONLY)) { + for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { + if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED) + || (specPtr->argvName == NULL) + || (specPtr->type == TK_CONFIG_SYNONYM)) { + continue; + } + if (((specPtr->specFlags & needFlags) != needFlags) + || (specPtr->specFlags & hateFlags)) { + continue; + } + value = NULL; + if (specPtr->dbName != NULL) { + value = Tk_GetOption(tkwin, specPtr->dbName, specPtr->dbClass); + } + if (value != NULL) { + if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) != + TCL_OK) { + char msg[200]; + + sprintf(msg, "\n (%s \"%.50s\" in widget \"%.50s\")", + "database entry for", + specPtr->dbName, Tk_PathName(tkwin)); + Tcl_AddErrorInfo(interp, msg); + return TCL_ERROR; + } + } else { + if (specPtr->defValue != NULL) { + value = Tk_GetUid(specPtr->defValue); + } else { + value = NULL; + } + if ((value != NULL) && !(specPtr->specFlags + & TK_CONFIG_DONT_SET_DEFAULT)) { + if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) != + TCL_OK) { + char msg[200]; + + sprintf(msg, + "\n (%s \"%.50s\" in widget \"%.50s\")", + "default value for", + specPtr->dbName, Tk_PathName(tkwin)); + Tcl_AddErrorInfo(interp, msg); + return TCL_ERROR; + } + } + } + } + } + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * FindConfigSpec -- + * + * Search through a table of configuration specs, looking for + * one that matches a given argvName. + * + * Results: + * The return value is a pointer to the matching entry, or NULL + * if nothing matched. In that case an error message is left + * in the interp's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static Tk_ConfigSpec * +FindConfigSpec(interp, specs, argvName, needFlags, hateFlags) + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_ConfigSpec *specs; /* Pointer to table of configuration + * specifications for a widget. */ + char *argvName; /* Name (suitable for use in a "config" + * command) identifying particular option. */ + int needFlags; /* Flags that must be present in matching + * entry. */ + int hateFlags; /* Flags that must NOT be present in + * matching entry. */ +{ + register Tk_ConfigSpec *specPtr; + register char c; /* First character of current argument. */ + Tk_ConfigSpec *matchPtr; /* Matching spec, or NULL. */ + size_t length; + + c = argvName[1]; + length = strlen(argvName); + matchPtr = NULL; + for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { + if (specPtr->argvName == NULL) { + continue; + } + if ((specPtr->argvName[1] != c) + || (strncmp(specPtr->argvName, argvName, length) != 0)) { + continue; + } + if (((specPtr->specFlags & needFlags) != needFlags) + || (specPtr->specFlags & hateFlags)) { + continue; + } + if (specPtr->argvName[length] == 0) { + matchPtr = specPtr; + goto gotMatch; + } + if (matchPtr != NULL) { + Tcl_AppendResult(interp, "ambiguous option \"", argvName, + "\"", (char *) NULL); + return (Tk_ConfigSpec *) NULL; + } + matchPtr = specPtr; + } + + if (matchPtr == NULL) { + Tcl_AppendResult(interp, "unknown option \"", argvName, + "\"", (char *) NULL); + return (Tk_ConfigSpec *) NULL; + } + + /* + * Found a matching entry. If it's a synonym, then find the + * entry that it's a synonym for. + */ + + gotMatch: + specPtr = matchPtr; + if (specPtr->type == TK_CONFIG_SYNONYM) { + for (specPtr = specs; ; specPtr++) { + if (specPtr->type == TK_CONFIG_END) { + Tcl_AppendResult(interp, + "couldn't find synonym for option \"", + argvName, "\"", (char *) NULL); + return (Tk_ConfigSpec *) NULL; + } + if ((specPtr->dbName == matchPtr->dbName) + && (specPtr->type != TK_CONFIG_SYNONYM) + && ((specPtr->specFlags & needFlags) == needFlags) + && !(specPtr->specFlags & hateFlags)) { + break; + } + } + } + return specPtr; +} + +/* + *-------------------------------------------------------------- + * + * DoConfig -- + * + * This procedure applies a single configuration option + * to a widget record. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * WidgRec is modified as indicated by specPtr and value. + * The old value is recycled, if that is appropriate for + * the value type. + * + *-------------------------------------------------------------- + */ + +static int +DoConfig(interp, tkwin, specPtr, value, valueIsUid, widgRec) + Tcl_Interp *interp; /* Interpreter for error reporting. */ + Tk_Window tkwin; /* Window containing widget (needed to + * set up X resources). */ + Tk_ConfigSpec *specPtr; /* Specifier to apply. */ + char *value; /* Value to use to fill in widgRec. */ + int valueIsUid; /* Non-zero means value is a Tk_Uid; + * zero means it's an ordinary string. */ + char *widgRec; /* Record whose fields are to be + * modified. Values must be properly + * initialized. */ +{ + char *ptr; + Tk_Uid uid; + int nullValue; + + nullValue = 0; + if ((*value == 0) && (specPtr->specFlags & TK_CONFIG_NULL_OK)) { + nullValue = 1; + } + + do { + ptr = widgRec + specPtr->offset; + switch (specPtr->type) { + case TK_CONFIG_BOOLEAN: + if (Tcl_GetBoolean(interp, value, (int *) ptr) != TCL_OK) { + return TCL_ERROR; + } + break; + case TK_CONFIG_INT: + if (Tcl_GetInt(interp, value, (int *) ptr) != TCL_OK) { + return TCL_ERROR; + } + break; + case TK_CONFIG_DOUBLE: + if (Tcl_GetDouble(interp, value, (double *) ptr) != TCL_OK) { + return TCL_ERROR; + } + break; + case TK_CONFIG_STRING: { + char *old, *new; + + if (nullValue) { + new = NULL; + } else { + new = (char *) ckalloc((unsigned) (strlen(value) + 1)); + strcpy(new, value); + } + old = *((char **) ptr); + if (old != NULL) { + ckfree(old); + } + *((char **) ptr) = new; + break; + } + case TK_CONFIG_UID: + if (nullValue) { + *((Tk_Uid *) ptr) = NULL; + } else { + uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); + *((Tk_Uid *) ptr) = uid; + } + break; + case TK_CONFIG_COLOR: { + XColor *newPtr, *oldPtr; + + if (nullValue) { + newPtr = NULL; + } else { + uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); + newPtr = Tk_GetColor(interp, tkwin, uid); + if (newPtr == NULL) { + return TCL_ERROR; + } + } + oldPtr = *((XColor **) ptr); + if (oldPtr != NULL) { + Tk_FreeColor(oldPtr); + } + *((XColor **) ptr) = newPtr; + break; + } + case TK_CONFIG_FONT: { + Tk_Font new; + + if (nullValue) { + new = NULL; + } else { + new = Tk_GetFont(interp, tkwin, value); + if (new == NULL) { + return TCL_ERROR; + } + } + Tk_FreeFont(*((Tk_Font *) ptr)); + *((Tk_Font *) ptr) = new; + break; + } + case TK_CONFIG_BITMAP: { + Pixmap new, old; + + if (nullValue) { + new = None; + } else { + uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); + new = Tk_GetBitmap(interp, tkwin, uid); + if (new == None) { + return TCL_ERROR; + } + } + old = *((Pixmap *) ptr); + if (old != None) { + Tk_FreeBitmap(Tk_Display(tkwin), old); + } + *((Pixmap *) ptr) = new; + break; + } + case TK_CONFIG_BORDER: { + Tk_3DBorder new, old; + + if (nullValue) { + new = NULL; + } else { + uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); + new = Tk_Get3DBorder(interp, tkwin, uid); + if (new == NULL) { + return TCL_ERROR; + } + } + old = *((Tk_3DBorder *) ptr); + if (old != NULL) { + Tk_Free3DBorder(old); + } + *((Tk_3DBorder *) ptr) = new; + break; + } + case TK_CONFIG_RELIEF: + uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); + if (Tk_GetRelief(interp, uid, (int *) ptr) != TCL_OK) { + return TCL_ERROR; + } + break; + case TK_CONFIG_CURSOR: + case TK_CONFIG_ACTIVE_CURSOR: { + Tk_Cursor new, old; + + if (nullValue) { + new = None; + } else { + uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); + new = Tk_GetCursor(interp, tkwin, uid); + if (new == None) { + return TCL_ERROR; + } + } + old = *((Tk_Cursor *) ptr); + if (old != None) { + Tk_FreeCursor(Tk_Display(tkwin), old); + } + *((Tk_Cursor *) ptr) = new; + if (specPtr->type == TK_CONFIG_ACTIVE_CURSOR) { + Tk_DefineCursor(tkwin, new); + } + break; + } + case TK_CONFIG_JUSTIFY: + uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); + if (Tk_GetJustify(interp, uid, (Tk_Justify *) ptr) != TCL_OK) { + return TCL_ERROR; + } + break; + case TK_CONFIG_ANCHOR: + uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); + if (Tk_GetAnchor(interp, uid, (Tk_Anchor *) ptr) != TCL_OK) { + return TCL_ERROR; + } + break; + case TK_CONFIG_CAP_STYLE: + uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); + if (Tk_GetCapStyle(interp, uid, (int *) ptr) != TCL_OK) { + return TCL_ERROR; + } + break; + case TK_CONFIG_JOIN_STYLE: + uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value); + if (Tk_GetJoinStyle(interp, uid, (int *) ptr) != TCL_OK) { + return TCL_ERROR; + } + break; + case TK_CONFIG_PIXELS: + if (Tk_GetPixels(interp, tkwin, value, (int *) ptr) + != TCL_OK) { + return TCL_ERROR; + } + break; + case TK_CONFIG_MM: + if (Tk_GetScreenMM(interp, tkwin, value, (double *) ptr) + != TCL_OK) { + return TCL_ERROR; + } + break; + case TK_CONFIG_WINDOW: { + Tk_Window tkwin2; + + if (nullValue) { + tkwin2 = NULL; + } else { + tkwin2 = Tk_NameToWindow(interp, value, tkwin); + if (tkwin2 == NULL) { + return TCL_ERROR; + } + } + *((Tk_Window *) ptr) = tkwin2; + break; + } + case TK_CONFIG_CUSTOM: + if ((*specPtr->customPtr->parseProc)( + specPtr->customPtr->clientData, interp, tkwin, + value, widgRec, specPtr->offset) != TCL_OK) { + return TCL_ERROR; + } + break; + default: { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "bad config table: unknown type %d", + specPtr->type); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + specPtr++; + } while ((specPtr->argvName == NULL) && (specPtr->type != TK_CONFIG_END)); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Tk_ConfigureInfo -- + * + * Return information about the configuration options + * for a window, and their current values. + * + * Results: + * Always returns TCL_OK. The interp's result will be modified + * hold a description of either a single configuration option + * available for "widgRec" via "specs", or all the configuration + * options available. In the "all" case, the result will + * available for "widgRec" via "specs". The result will + * be a list, each of whose entries describes one option. + * Each entry will itself be a list containing the option's + * name for use on command lines, database name, database + * class, default value, and current value (empty string + * if none). For options that are synonyms, the list will + * contain only two values: name and synonym name. If the + * "name" argument is non-NULL, then the only information + * returned is that for the named argument (i.e. the corresponding + * entry in the overall list is returned). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_ConfigureInfo(interp, tkwin, specs, widgRec, argvName, flags) + Tcl_Interp *interp; /* Interpreter for error reporting. */ + Tk_Window tkwin; /* Window corresponding to widgRec. */ + Tk_ConfigSpec *specs; /* Describes legal options. */ + char *widgRec; /* Record whose fields contain current + * values for options. */ + char *argvName; /* If non-NULL, indicates a single option + * whose info is to be returned. Otherwise + * info is returned for all options. */ + int flags; /* Used to specify additional flags + * that must be present in config specs + * for them to be considered. */ +{ + register Tk_ConfigSpec *specPtr; + int needFlags, hateFlags; + char *list; + char *leader = "{"; + + needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); + if (Tk_Depth(tkwin) <= 1) { + hateFlags = TK_CONFIG_COLOR_ONLY; + } else { + hateFlags = TK_CONFIG_MONO_ONLY; + } + + /* + * If information is only wanted for a single configuration + * spec, then handle that one spec specially. + */ + + Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); + if (argvName != NULL) { + specPtr = FindConfigSpec(interp, specs, argvName, needFlags, + hateFlags); + if (specPtr == NULL) { + return TCL_ERROR; + } + Tcl_SetResult(interp, + FormatConfigInfo(interp, tkwin, specPtr, widgRec), + TCL_DYNAMIC); + return TCL_OK; + } + + /* + * Loop through all the specs, creating a big list with all + * their information. + */ + + for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { + if ((argvName != NULL) && (specPtr->argvName != argvName)) { + continue; + } + if (((specPtr->specFlags & needFlags) != needFlags) + || (specPtr->specFlags & hateFlags)) { + continue; + } + if (specPtr->argvName == NULL) { + continue; + } + list = FormatConfigInfo(interp, tkwin, specPtr, widgRec); + Tcl_AppendResult(interp, leader, list, "}", (char *) NULL); + ckfree(list); + leader = " {"; + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * FormatConfigInfo -- + * + * Create a valid Tcl list holding the configuration information + * for a single configuration option. + * + * Results: + * A Tcl list, dynamically allocated. The caller is expected to + * arrange for this list to be freed eventually. + * + * Side effects: + * Memory is allocated. + * + *-------------------------------------------------------------- + */ + +static char * +FormatConfigInfo(interp, tkwin, specPtr, widgRec) + Tcl_Interp *interp; /* Interpreter to use for things + * like floating-point precision. */ + Tk_Window tkwin; /* Window corresponding to widget. */ + register Tk_ConfigSpec *specPtr; /* Pointer to information describing + * option. */ + char *widgRec; /* Pointer to record holding current + * values of info for widget. */ +{ + char *argv[6], *result; + char buffer[200]; + Tcl_FreeProc *freeProc = (Tcl_FreeProc *) NULL; + + argv[0] = specPtr->argvName; + argv[1] = specPtr->dbName; + argv[2] = specPtr->dbClass; + argv[3] = specPtr->defValue; + if (specPtr->type == TK_CONFIG_SYNONYM) { + return Tcl_Merge(2, argv); + } + argv[4] = FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, + &freeProc); + if (argv[1] == NULL) { + argv[1] = ""; + } + if (argv[2] == NULL) { + argv[2] = ""; + } + if (argv[3] == NULL) { + argv[3] = ""; + } + if (argv[4] == NULL) { + argv[4] = ""; + } + result = Tcl_Merge(5, argv); + if (freeProc != NULL) { + if ((freeProc == TCL_DYNAMIC) || (freeProc == (Tcl_FreeProc *) free)) { + ckfree(argv[4]); + } else { + (*freeProc)(argv[4]); + } + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * FormatConfigValue -- + * + * This procedure formats the current value of a configuration + * option. + * + * Results: + * The return value is the formatted value of the option given + * by specPtr and widgRec. If the value is static, so that it + * need not be freed, *freeProcPtr will be set to NULL; otherwise + * *freeProcPtr will be set to the address of a procedure to + * free the result, and the caller must invoke this procedure + * when it is finished with the result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static char * +FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, freeProcPtr) + Tcl_Interp *interp; /* Interpreter for use in real conversions. */ + Tk_Window tkwin; /* Window corresponding to widget. */ + Tk_ConfigSpec *specPtr; /* Pointer to information describing option. + * Must not point to a synonym option. */ + char *widgRec; /* Pointer to record holding current + * values of info for widget. */ + char *buffer; /* Static buffer to use for small values. + * Must have at least 200 bytes of storage. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to word to fill in with address + * of procedure to free the result, or NULL + * if result is static. */ +{ + char *ptr, *result; + + *freeProcPtr = NULL; + ptr = widgRec + specPtr->offset; + result = ""; + switch (specPtr->type) { + case TK_CONFIG_BOOLEAN: + if (*((int *) ptr) == 0) { + result = "0"; + } else { + result = "1"; + } + break; + case TK_CONFIG_INT: + sprintf(buffer, "%d", *((int *) ptr)); + result = buffer; + break; + case TK_CONFIG_DOUBLE: + Tcl_PrintDouble(interp, *((double *) ptr), buffer); + result = buffer; + break; + case TK_CONFIG_STRING: + result = (*(char **) ptr); + if (result == NULL) { + result = ""; + } + break; + case TK_CONFIG_UID: { + Tk_Uid uid = *((Tk_Uid *) ptr); + if (uid != NULL) { + result = uid; + } + break; + } + case TK_CONFIG_COLOR: { + XColor *colorPtr = *((XColor **) ptr); + if (colorPtr != NULL) { + result = Tk_NameOfColor(colorPtr); + } + break; + } + case TK_CONFIG_FONT: { + Tk_Font tkfont = *((Tk_Font *) ptr); + if (tkfont != NULL) { + result = Tk_NameOfFont(tkfont); + } + break; + } + case TK_CONFIG_BITMAP: { + Pixmap pixmap = *((Pixmap *) ptr); + if (pixmap != None) { + result = Tk_NameOfBitmap(Tk_Display(tkwin), pixmap); + } + break; + } + case TK_CONFIG_BORDER: { + Tk_3DBorder border = *((Tk_3DBorder *) ptr); + if (border != NULL) { + result = Tk_NameOf3DBorder(border); + } + break; + } + case TK_CONFIG_RELIEF: + result = Tk_NameOfRelief(*((int *) ptr)); + break; + case TK_CONFIG_CURSOR: + case TK_CONFIG_ACTIVE_CURSOR: { + Tk_Cursor cursor = *((Tk_Cursor *) ptr); + if (cursor != None) { + result = Tk_NameOfCursor(Tk_Display(tkwin), cursor); + } + break; + } + case TK_CONFIG_JUSTIFY: + result = Tk_NameOfJustify(*((Tk_Justify *) ptr)); + break; + case TK_CONFIG_ANCHOR: + result = Tk_NameOfAnchor(*((Tk_Anchor *) ptr)); + break; + case TK_CONFIG_CAP_STYLE: + result = Tk_NameOfCapStyle(*((int *) ptr)); + break; + case TK_CONFIG_JOIN_STYLE: + result = Tk_NameOfJoinStyle(*((int *) ptr)); + break; + case TK_CONFIG_PIXELS: + sprintf(buffer, "%d", *((int *) ptr)); + result = buffer; + break; + case TK_CONFIG_MM: + Tcl_PrintDouble(interp, *((double *) ptr), buffer); + result = buffer; + break; + case TK_CONFIG_WINDOW: { + Tk_Window tkwin; + + tkwin = *((Tk_Window *) ptr); + if (tkwin != NULL) { + result = Tk_PathName(tkwin); + } + break; + } + case TK_CONFIG_CUSTOM: + result = (*specPtr->customPtr->printProc)( + specPtr->customPtr->clientData, tkwin, widgRec, + specPtr->offset, freeProcPtr); + break; + default: + result = "?? unknown type ??"; + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_ConfigureValue -- + * + * This procedure returns the current value of a configuration + * option for a widget. + * + * Results: + * The return value is a standard Tcl completion code (TCL_OK or + * TCL_ERROR). The interp's result will be set to hold either the value + * of the option given by argvName (if TCL_OK is returned) or + * an error message (if TCL_ERROR is returned). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Tk_ConfigureValue(interp, tkwin, specs, widgRec, argvName, flags) + Tcl_Interp *interp; /* Interpreter for error reporting. */ + Tk_Window tkwin; /* Window corresponding to widgRec. */ + Tk_ConfigSpec *specs; /* Describes legal options. */ + char *widgRec; /* Record whose fields contain current + * values for options. */ + char *argvName; /* Gives the command-line name for the + * option whose value is to be returned. */ + int flags; /* Used to specify additional flags + * that must be present in config specs + * for them to be considered. */ +{ + Tk_ConfigSpec *specPtr; + int needFlags, hateFlags; + + needFlags = flags & ~(TK_CONFIG_USER_BIT - 1); + if (Tk_Depth(tkwin) <= 1) { + hateFlags = TK_CONFIG_COLOR_ONLY; + } else { + hateFlags = TK_CONFIG_MONO_ONLY; + } + specPtr = FindConfigSpec(interp, specs, argvName, needFlags, hateFlags); + if (specPtr == NULL) { + return TCL_ERROR; + } + interp->result = FormatConfigValue(interp, tkwin, specPtr, widgRec, + interp->result, &interp->freeProc); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_FreeOptions -- + * + * Free up all resources associated with configuration options. + * + * Results: + * None. + * + * Side effects: + * Any resource in widgRec that is controlled by a configuration + * option (e.g. a Tk_3DBorder or XColor) is freed in the appropriate + * fashion. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +void +Tk_FreeOptions(specs, widgRec, display, needFlags) + Tk_ConfigSpec *specs; /* Describes legal options. */ + char *widgRec; /* Record whose fields contain current + * values for options. */ + Display *display; /* X display; needed for freeing some + * resources. */ + int needFlags; /* Used to specify additional flags + * that must be present in config specs + * for them to be considered. */ +{ + register Tk_ConfigSpec *specPtr; + char *ptr; + + for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) { + if ((specPtr->specFlags & needFlags) != needFlags) { + continue; + } + ptr = widgRec + specPtr->offset; + switch (specPtr->type) { + case TK_CONFIG_STRING: + if (*((char **) ptr) != NULL) { + ckfree(*((char **) ptr)); + *((char **) ptr) = NULL; + } + break; + case TK_CONFIG_COLOR: + if (*((XColor **) ptr) != NULL) { + Tk_FreeColor(*((XColor **) ptr)); + *((XColor **) ptr) = NULL; + } + break; + case TK_CONFIG_FONT: + Tk_FreeFont(*((Tk_Font *) ptr)); + *((Tk_Font *) ptr) = NULL; + break; + case TK_CONFIG_BITMAP: + if (*((Pixmap *) ptr) != None) { + Tk_FreeBitmap(display, *((Pixmap *) ptr)); + *((Pixmap *) ptr) = None; + } + break; + case TK_CONFIG_BORDER: + if (*((Tk_3DBorder *) ptr) != NULL) { + Tk_Free3DBorder(*((Tk_3DBorder *) ptr)); + *((Tk_3DBorder *) ptr) = NULL; + } + break; + case TK_CONFIG_CURSOR: + case TK_CONFIG_ACTIVE_CURSOR: + if (*((Tk_Cursor *) ptr) != None) { + Tk_FreeCursor(display, *((Tk_Cursor *) ptr)); + *((Tk_Cursor *) ptr) = None; + } + } + } +} + + diff --git a/tk/generic/tkOption.c b/tk/generic/tkOption.c index f3807167edb..54e1f27d75e 100644 --- a/tk/generic/tkOption.c +++ b/tk/generic/tkOption.c @@ -6,7 +6,7 @@ * with windows either by name or by class or both. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -141,13 +141,6 @@ typedef struct ElArray { */ #define NUM_STACKS 8 -static ElArray *stacks[NUM_STACKS]; -static TkWindow *cachedWindow = NULL; /* Lowest-level window currently - * loaded in stacks at present. - * NULL means stacks have never - * been used, or have been - * invalidated because of a change - * to the database. */ /* * One of the following structures is used to keep track of each @@ -163,33 +156,41 @@ typedef struct StackLevel { * fields when popping out of a level. */ } StackLevel; -/* - * Information about all of the stack levels that are currently - * active. This array grows dynamically to become as large as needed. - */ +typedef struct ThreadSpecificData { + int initialized; /* 0 means the ThreadSpecific Data structure + * for the current thread needs to be + * initialized. */ + ElArray *stacks[NUM_STACKS]; + TkWindow *cachedWindow; + /* Lowest-level window currently + * loaded in stacks at present. + * NULL means stacks have never + * been used, or have been + * invalidated because of a change + * to the database. */ + /* + * Information about all of the stack levels that are currently + * active. This array grows dynamically to become as large as needed. + */ -static StackLevel *levels = NULL; - /* Array describing current stack. */ -static int numLevels = 0; /* Total space allocated. */ -static int curLevel = -1; /* Highest level currently in use. Note: + StackLevel *levels; /* Array describing current stack. */ + int numLevels; /* Total space allocated. */ + int curLevel; /* Highest level currently in use. Note: * curLevel is never 0! (I don't remember * why anymore...) */ + /* + * The variable below is a serial number for all options entered into + * the database so far. It increments on each addition to the option + * database. It is used in computing option priorities, so that the + * most recent entry wins when choosing between options at the same + * priority level. + */ -/* - * The variable below is a serial number for all options entered into - * the database so far. It increments on each addition to the option - * database. It is used in computing option priorities, so that the - * most recent entry wins when choosing between options at the same - * priority level. - */ - -static int serial = 0; - -/* - * Special "no match" Element to use as default for searches. - */ - -static Element defaultMatch; + int serial; + Element defaultMatch; /* Special "no match" Element to use as + * default for searches.*/ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; /* * Forward declarations for procedures defined in this file: @@ -248,11 +249,13 @@ Tk_AddOption(tkwin, name, value, priority) int count, firstField, length; #define TMP_SIZE 100 char tmp[TMP_SIZE+1]; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (winPtr->mainPtr->optionRootPtr == NULL) { OptionInit(winPtr->mainPtr); } - cachedWindow = NULL; /* Invalidate the cache. */ + tsdPtr->cachedWindow = NULL; /* Invalidate the cache. */ /* * Compute the priority for the new element, including both the @@ -265,8 +268,8 @@ Tk_AddOption(tkwin, name, value, priority) } else if (priority > TK_MAX_PRIO) { priority = TK_MAX_PRIO; } - newEl.priority = (priority << 24) + serial; - serial++; + newEl.priority = (priority << 24) + tsdPtr->serial; + tsdPtr->serial++; /* * Parse the option one field at a time. @@ -396,28 +399,30 @@ Tk_GetOption(tkwin, name, className) Tk_Uid nameId, classId; register Element *elPtr, *bestPtr; register int count; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * Note: no need to call OptionInit here: it will be done by * the SetupStacks call below (squeeze out those nanoseconds). */ - if (tkwin != (Tk_Window) cachedWindow) { + if (tkwin != (Tk_Window) tsdPtr->cachedWindow) { SetupStacks((TkWindow *) tkwin, 1); } nameId = Tk_GetUid(name); - bestPtr = &defaultMatch; - for (elPtr = stacks[EXACT_LEAF_NAME]->els, - count = stacks[EXACT_LEAF_NAME]->numUsed; count > 0; + bestPtr = &tsdPtr->defaultMatch; + for (elPtr = tsdPtr->stacks[EXACT_LEAF_NAME]->els, + count = tsdPtr->stacks[EXACT_LEAF_NAME]->numUsed; count > 0; elPtr++, count--) { if ((elPtr->nameUid == nameId) && (elPtr->priority > bestPtr->priority)) { bestPtr = elPtr; } } - for (elPtr = stacks[WILDCARD_LEAF_NAME]->els, - count = stacks[WILDCARD_LEAF_NAME]->numUsed; count > 0; + for (elPtr = tsdPtr->stacks[WILDCARD_LEAF_NAME]->els, + count = tsdPtr->stacks[WILDCARD_LEAF_NAME]->numUsed; count > 0; elPtr++, count--) { if ((elPtr->nameUid == nameId) && (elPtr->priority > bestPtr->priority)) { @@ -426,17 +431,17 @@ Tk_GetOption(tkwin, name, className) } if (className != NULL) { classId = Tk_GetUid(className); - for (elPtr = stacks[EXACT_LEAF_CLASS]->els, - count = stacks[EXACT_LEAF_CLASS]->numUsed; count > 0; + for (elPtr = tsdPtr->stacks[EXACT_LEAF_CLASS]->els, + count = tsdPtr->stacks[EXACT_LEAF_CLASS]->numUsed; count > 0; elPtr++, count--) { if ((elPtr->nameUid == classId) && (elPtr->priority > bestPtr->priority)) { bestPtr = elPtr; } } - for (elPtr = stacks[WILDCARD_LEAF_CLASS]->els, - count = stacks[WILDCARD_LEAF_CLASS]->numUsed; count > 0; - elPtr++, count--) { + for (elPtr = tsdPtr->stacks[WILDCARD_LEAF_CLASS]->els, + count = tsdPtr->stacks[WILDCARD_LEAF_CLASS]->numUsed; + count > 0; elPtr++, count--) { if ((elPtr->nameUid == classId) && (elPtr->priority > bestPtr->priority)) { bestPtr = elPtr; @@ -449,7 +454,7 @@ Tk_GetOption(tkwin, name, className) /* *-------------------------------------------------------------- * - * Tk_OptionCmd -- + * Tk_OptionObjCmd -- * * This procedure is invoked to process the "option" Tcl command. * See the user documentation for details on what it does. @@ -464,98 +469,117 @@ Tk_GetOption(tkwin, name, className) */ int -Tk_OptionCmd(clientData, interp, argc, argv) +Tk_OptionObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of Tcl_Obj arguments. */ + Tcl_Obj *CONST objv[]; /* Tcl_Obj arguments. */ { Tk_Window tkwin = (Tk_Window) clientData; - size_t length; - char c; + int index, result; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + static char *optionCmds[] = { + "add", "clear", "get", "readfile", NULL + }; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " cmd arg ?arg ...?\"", (char *) NULL); + enum optionVals { + OPTION_ADD, OPTION_CLEAR, OPTION_GET, OPTION_READFILE + }; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "cmd arg ?arg ...?"); return TCL_ERROR; } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'a') && (strncmp(argv[1], "add", length) == 0)) { - int priority; - - if ((argc != 4) && (argc != 5)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " add pattern value ?priority?\"", (char *) NULL); - return TCL_ERROR; - } - if (argc == 4) { - priority = TK_INTERACTIVE_PRIO; - } else { - priority = ParsePriority(interp, argv[4]); - if (priority < 0) { + + result = Tcl_GetIndexFromObj(interp, objv[1], optionCmds, "option", 0, + &index); + if (result != TCL_OK) { + return result; + } + + result = TCL_OK; + switch ((enum optionVals) index) { + case OPTION_ADD: { + int priority; + if ((objc != 4) && (objc != 5)) { + Tcl_WrongNumArgs(interp, 2, objv, "pattern value ?priority?"); return TCL_ERROR; } + + if (objc == 4) { + priority = TK_INTERACTIVE_PRIO; + } else { + priority = ParsePriority(interp, Tcl_GetString(objv[4])); + if (priority < 0) { + return TCL_ERROR; + } + } + Tk_AddOption(tkwin, Tcl_GetString(objv[2]), + Tcl_GetString(objv[3]), priority); + break; } - Tk_AddOption(tkwin, argv[2], argv[3], priority); - return TCL_OK; - } else if ((c == 'c') && (strncmp(argv[1], "clear", length) == 0)) { - TkMainInfo *mainPtr; - - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " clear\"", (char *) NULL); - return TCL_ERROR; - } - mainPtr = ((TkWindow *) tkwin)->mainPtr; - if (mainPtr->optionRootPtr != NULL) { - ClearOptionTree(mainPtr->optionRootPtr); - mainPtr->optionRootPtr = NULL; - } - cachedWindow = NULL; - return TCL_OK; - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - Tk_Window window; - Tk_Uid value; - - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " get window name class\"", (char *) NULL); - return TCL_ERROR; - } - window = Tk_NameToWindow(interp, argv[2], tkwin); - if (window == NULL) { - return TCL_ERROR; - } - value = Tk_GetOption(window, argv[3], argv[4]); - if (value != NULL) { - interp->result = value; + + case OPTION_CLEAR: { + TkMainInfo *mainPtr; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return TCL_ERROR; + } + mainPtr = ((TkWindow *) tkwin)->mainPtr; + if (mainPtr->optionRootPtr != NULL) { + ClearOptionTree(mainPtr->optionRootPtr); + mainPtr->optionRootPtr = NULL; + } + tsdPtr->cachedWindow = NULL; + break; } - return TCL_OK; - } else if ((c == 'r') && (strncmp(argv[1], "readfile", length) == 0)) { - int priority; - if ((argc != 3) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " readfile fileName ?priority?\"", - (char *) NULL); - return TCL_ERROR; + case OPTION_GET: { + Tk_Window window; + Tk_Uid value; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "window name class"); + return TCL_ERROR; + } + window = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin); + if (window == NULL) { + return TCL_ERROR; + } + value = Tk_GetOption(window, Tcl_GetString(objv[3]), + Tcl_GetString(objv[4])); + if (value != NULL) { + Tcl_SetResult(interp, value, TCL_STATIC); + } + break; } - if (argc == 4) { - priority = ParsePriority(interp, argv[3]); - if (priority < 0) { + + case OPTION_READFILE: { + int priority; + + if ((objc != 3) && (objc != 4)) { + Tcl_WrongNumArgs(interp, 2, objv, "fileName ?priority?"); return TCL_ERROR; } - } else { - priority = TK_INTERACTIVE_PRIO; + + if (objc == 4) { + priority = ParsePriority(interp, Tcl_GetString(objv[3])); + if (priority < 0) { + return TCL_ERROR; + } + } else { + priority = TK_INTERACTIVE_PRIO; + } + result = ReadOptionFile(interp, tkwin, Tcl_GetString(objv[2]), + priority); + break; } - return ReadOptionFile(interp, tkwin, argv[2], priority); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be add, clear, get, or readfile", (char *) NULL); - return TCL_ERROR; } + return result; } /* @@ -581,6 +605,9 @@ void TkOptionDeadWindow(winPtr) register TkWindow *winPtr; /* Window to be cleaned up. */ { + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + /* * If this window is in the option stacks, then clear the stacks. */ @@ -588,11 +615,11 @@ TkOptionDeadWindow(winPtr) if (winPtr->optionLevel != -1) { int i; - for (i = 1; i <= curLevel; i++) { - levels[i].winPtr->optionLevel = -1; + for (i = 1; i <= tsdPtr->curLevel; i++) { + tsdPtr->levels[i].winPtr->optionLevel = -1; } - curLevel = -1; - cachedWindow = NULL; + tsdPtr->curLevel = -1; + tsdPtr->cachedWindow = NULL; } /* @@ -632,6 +659,8 @@ TkOptionClassChanged(winPtr) { int i, j, *basePtr; ElArray *arrayPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (winPtr->optionLevel == -1) { return; @@ -642,22 +671,22 @@ TkOptionClassChanged(winPtr) * flush all of the levels above the matching one. */ - for (i = 1; i <= curLevel; i++) { - if (levels[i].winPtr == winPtr) { - for (j = i; j <= curLevel; j++) { - levels[j].winPtr->optionLevel = -1; + for (i = 1; i <= tsdPtr->curLevel; i++) { + if (tsdPtr->levels[i].winPtr == winPtr) { + for (j = i; j <= tsdPtr->curLevel; j++) { + tsdPtr->levels[j].winPtr->optionLevel = -1; } - curLevel = i-1; - basePtr = levels[i].bases; + tsdPtr->curLevel = i-1; + basePtr = tsdPtr->levels[i].bases; for (j = 0; j < NUM_STACKS; j++) { - arrayPtr = stacks[j]; + arrayPtr = tsdPtr->stacks[j]; arrayPtr->numUsed = basePtr[j]; arrayPtr->nextToUse = &arrayPtr->els[arrayPtr->numUsed]; } - if (curLevel <= 0) { - cachedWindow = NULL; + if (tsdPtr->curLevel <= 0) { + tsdPtr->cachedWindow = NULL; } else { - cachedWindow = levels[curLevel].winPtr; + tsdPtr->cachedWindow = tsdPtr->levels[tsdPtr->curLevel].winPtr; } break; } @@ -674,7 +703,7 @@ TkOptionClassChanged(winPtr) * Results: * The return value is the integer priority level corresponding * to string, or -1 if string doesn't point to a valid priority level. - * In this case, an error message is left in interp->result. + * In this case, an error message is left in the interp's result. * * Side effects: * None. @@ -734,7 +763,7 @@ ParsePriority(interp, string) * Results: * The return value is a standard Tcl return code. In the case of * an error in parsing string, TCL_ERROR will be returned and an - * error message will be left in interp->result. The memory at + * error message will be left in the interp's result. The memory at * string is totally trashed by this procedure. If you care about * its contents, make a copy before calling here. * @@ -797,8 +826,10 @@ AddFromString(interp, tkwin, string, priority) dst = name = src; while (*src != ':') { if ((*src == '\0') || (*src == '\n')) { - sprintf(interp->result, "missing colon on line %d", - lineNum); + char buf[32 + TCL_INTEGER_SPACE]; + + sprintf(buf, "missing colon on line %d", lineNum); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } if ((src[0] == '\\') && (src[1] == '\n')) { @@ -830,7 +861,10 @@ AddFromString(interp, tkwin, string, priority) src++; } if (*src == '\0') { - sprintf(interp->result, "missing value on line %d", lineNum); + char buf[32 + TCL_INTEGER_SPACE]; + + sprintf(buf, "missing value on line %d", lineNum); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } @@ -842,8 +876,10 @@ AddFromString(interp, tkwin, string, priority) dst = value = src; while (*src != '\n') { if (*src == '\0') { - sprintf(interp->result, "missing newline on line %d", - lineNum); + char buf[32 + TCL_INTEGER_SPACE]; + + sprintf(buf, "missing newline on line %d", lineNum); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } if ((src[0] == '\\') && (src[1] == '\n')) { @@ -879,7 +915,7 @@ AddFromString(interp, tkwin, string, priority) * Results: * The return value is a standard Tcl return code. In the case of * an error in parsing string, TCL_ERROR will be returned and an - * error message will be left in interp->result. + * error message will be left in the interp's result. * * Side effects: * None. @@ -1062,6 +1098,8 @@ SetupStacks(winPtr, leaf) int level, i, *iPtr; register StackLevel *levelPtr; register ElArray *arrayPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * The following array defines the order in which the current @@ -1086,7 +1124,7 @@ SetupStacks(winPtr, leaf) if (winPtr->parentPtr != NULL) { level = winPtr->parentPtr->optionLevel; - if ((level == -1) || (cachedWindow == NULL)) { + if ((level == -1) || (tsdPtr->cachedWindow == NULL)) { SetupStacks(winPtr->parentPtr, 0); level = winPtr->parentPtr->optionLevel; } @@ -1100,19 +1138,19 @@ SetupStacks(winPtr, leaf) * mark those windows as no longer having cached information. */ - if (curLevel >= level) { - while (curLevel >= level) { - levels[curLevel].winPtr->optionLevel = -1; - curLevel--; + if (tsdPtr->curLevel >= level) { + while (tsdPtr->curLevel >= level) { + tsdPtr->levels[tsdPtr->curLevel].winPtr->optionLevel = -1; + tsdPtr->curLevel--; } - levelPtr = &levels[level]; + levelPtr = &tsdPtr->levels[level]; for (i = 0; i < NUM_STACKS; i++) { - arrayPtr = stacks[i]; + arrayPtr = tsdPtr->stacks[i]; arrayPtr->numUsed = levelPtr->bases[i]; arrayPtr->nextToUse = &arrayPtr->els[arrayPtr->numUsed]; } } - curLevel = winPtr->optionLevel = level; + tsdPtr->curLevel = winPtr->optionLevel = level; /* * Step 3: if the root database information isn't loaded or @@ -1120,11 +1158,11 @@ SetupStacks(winPtr, leaf) * database root (this only happens if winPtr is a main window). */ - if ((curLevel == 1) - && ((cachedWindow == NULL) - || (cachedWindow->mainPtr != winPtr->mainPtr))) { + if ((tsdPtr->curLevel == 1) + && ((tsdPtr->cachedWindow == NULL) + || (tsdPtr->cachedWindow->mainPtr != winPtr->mainPtr))) { for (i = 0; i < NUM_STACKS; i++) { - arrayPtr = stacks[i]; + arrayPtr = tsdPtr->stacks[i]; arrayPtr->numUsed = 0; arrayPtr->nextToUse = arrayPtr->els; } @@ -1138,33 +1176,41 @@ SetupStacks(winPtr, leaf) * any more). */ - if (curLevel >= numLevels) { + if (tsdPtr->curLevel >= tsdPtr->numLevels) { StackLevel *newLevels; newLevels = (StackLevel *) ckalloc((unsigned) - (numLevels*2*sizeof(StackLevel))); - memcpy((VOID *) newLevels, (VOID *) levels, - (numLevels*sizeof(StackLevel))); - ckfree((char *) levels); - numLevels *= 2; - levels = newLevels; + (tsdPtr->numLevels*2*sizeof(StackLevel))); + memcpy((VOID *) newLevels, (VOID *) tsdPtr->levels, + (tsdPtr->numLevels*sizeof(StackLevel))); + ckfree((char *) tsdPtr->levels); + tsdPtr->numLevels *= 2; + tsdPtr->levels = newLevels; } - levelPtr = &levels[curLevel]; + levelPtr = &tsdPtr->levels[tsdPtr->curLevel]; levelPtr->winPtr = winPtr; - arrayPtr = stacks[EXACT_LEAF_NAME]; + arrayPtr = tsdPtr->stacks[EXACT_LEAF_NAME]; arrayPtr->numUsed = 0; arrayPtr->nextToUse = arrayPtr->els; - arrayPtr = stacks[EXACT_LEAF_CLASS]; + arrayPtr = tsdPtr->stacks[EXACT_LEAF_CLASS]; arrayPtr->numUsed = 0; arrayPtr->nextToUse = arrayPtr->els; - levelPtr->bases[EXACT_LEAF_NAME] = stacks[EXACT_LEAF_NAME]->numUsed; - levelPtr->bases[EXACT_LEAF_CLASS] = stacks[EXACT_LEAF_CLASS]->numUsed; - levelPtr->bases[EXACT_NODE_NAME] = stacks[EXACT_NODE_NAME]->numUsed; - levelPtr->bases[EXACT_NODE_CLASS] = stacks[EXACT_NODE_CLASS]->numUsed; - levelPtr->bases[WILDCARD_LEAF_NAME] = stacks[WILDCARD_LEAF_NAME]->numUsed; - levelPtr->bases[WILDCARD_LEAF_CLASS] = stacks[WILDCARD_LEAF_CLASS]->numUsed; - levelPtr->bases[WILDCARD_NODE_NAME] = stacks[WILDCARD_NODE_NAME]->numUsed; - levelPtr->bases[WILDCARD_NODE_CLASS] = stacks[WILDCARD_NODE_CLASS]->numUsed; + levelPtr->bases[EXACT_LEAF_NAME] = tsdPtr->stacks[EXACT_LEAF_NAME] + ->numUsed; + levelPtr->bases[EXACT_LEAF_CLASS] = tsdPtr->stacks[EXACT_LEAF_CLASS] + ->numUsed; + levelPtr->bases[EXACT_NODE_NAME] = tsdPtr->stacks[EXACT_NODE_NAME] + ->numUsed; + levelPtr->bases[EXACT_NODE_CLASS] = tsdPtr->stacks[EXACT_NODE_CLASS] + ->numUsed; + levelPtr->bases[WILDCARD_LEAF_NAME] = tsdPtr->stacks[WILDCARD_LEAF_NAME] + ->numUsed; + levelPtr->bases[WILDCARD_LEAF_CLASS] = tsdPtr->stacks[WILDCARD_LEAF_CLASS] + ->numUsed; + levelPtr->bases[WILDCARD_NODE_NAME] = tsdPtr->stacks[WILDCARD_NODE_NAME] + ->numUsed; + levelPtr->bases[WILDCARD_NODE_CLASS] = tsdPtr->stacks[WILDCARD_NODE_CLASS] + ->numUsed; /* @@ -1184,7 +1230,7 @@ SetupStacks(winPtr, leaf) } else { id = winPtr->nameUid; } - elPtr = stacks[i]->els; + elPtr = tsdPtr->stacks[i]->els; count = levelPtr->bases[i]; /* @@ -1203,7 +1249,7 @@ SetupStacks(winPtr, leaf) ExtendStacks(elPtr->child.arrayPtr, leaf); } } - cachedWindow = winPtr; + tsdPtr->cachedWindow = winPtr; } /* @@ -1232,13 +1278,16 @@ ExtendStacks(arrayPtr, leaf) { register int count; register Element *elPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); for (elPtr = arrayPtr->els, count = arrayPtr->numUsed; count > 0; elPtr++, count--) { if (!(elPtr->flags & (NODE|WILDCARD)) && !leaf) { continue; } - stacks[elPtr->flags] = ExtendArray(stacks[elPtr->flags], elPtr); + tsdPtr->stacks[elPtr->flags] = ExtendArray( + tsdPtr->stacks[elPtr->flags], elPtr); } } @@ -1266,24 +1315,32 @@ OptionInit(mainPtr) { int i; Tcl_Interp *interp; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + Element *defaultMatchPtr = &tsdPtr->defaultMatch; /* * First, once-only initialization. */ - - if (numLevels == 0) { - - numLevels = 5; - levels = (StackLevel *) ckalloc((unsigned) (5*sizeof(StackLevel))); + + if (tsdPtr->initialized == 0) { + tsdPtr->initialized = 1; + tsdPtr->cachedWindow = NULL; + tsdPtr->numLevels = 5; + tsdPtr->curLevel = -1; + tsdPtr->serial = 0; + + tsdPtr->levels = (StackLevel *) ckalloc((unsigned) + (5*sizeof(StackLevel))); for (i = 0; i < NUM_STACKS; i++) { - stacks[i] = NewArray(10); - levels[0].bases[i] = 0; + tsdPtr->stacks[i] = NewArray(10); + tsdPtr->levels[0].bases[i] = 0; } - defaultMatch.nameUid = NULL; - defaultMatch.child.valueUid = NULL; - defaultMatch.priority = -1; - defaultMatch.flags = 0; + defaultMatchPtr->nameUid = NULL; + defaultMatchPtr->child.valueUid = NULL; + defaultMatchPtr->priority = -1; + defaultMatchPtr->flags = 0; } /* diff --git a/tk/generic/tkPack.c b/tk/generic/tkPack.c index 9e5d2421fdf..d10d86782b9 100644 --- a/tk/generic/tkPack.c +++ b/tk/generic/tkPack.c @@ -5,7 +5,7 @@ * geometry manager for Tk. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -24,7 +24,7 @@ typedef enum {TOP, BOTTOM, LEFT, RIGHT} Side; * structure of the following type: */ -typedef struct Packer { +typedef struct /* Green Bay */ Packer { Tk_Window tkwin; /* Tk token for window. NULL means that * the window has been deleted, but the * packet hasn't had a chance to clean up @@ -96,19 +96,6 @@ typedef struct Packer { #define DONT_PROPAGATE 32 /* - * Hash table used to map from Tk_Window tokens to corresponding - * Packer structures: - */ - -static Tcl_HashTable packerHashTable; - -/* - * Have statics in this module been initialized? - */ - -static int initialized = 0; - -/* * The following structure is the official type record for the * packer: */ @@ -281,7 +268,7 @@ Tk_PackCmd(clientData, interp, argc, argv) } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) { register Packer *slavePtr; Tk_Window slave; - char buffer[300]; + char buffer[64 + TCL_INTEGER_SPACE * 4]; static char *sideNames[] = {"top", "bottom", "left", "right"}; if (argc != 3) { @@ -342,9 +329,9 @@ Tk_PackCmd(clientData, interp, argc, argv) masterPtr = GetPacker(master); if (argc == 3) { if (masterPtr->flags & DONT_PROPAGATE) { - interp->result = "0"; + Tcl_SetResult(interp, "0", TCL_STATIC); } else { - interp->result = "1"; + Tcl_SetResult(interp, "1", TCL_STATIC); } return TCL_OK; } @@ -957,10 +944,11 @@ GetPacker(tkwin) register Packer *packPtr; Tcl_HashEntry *hPtr; int new; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; - if (!initialized) { - initialized = 1; - Tcl_InitHashTable(&packerHashTable, TCL_ONE_WORD_KEYS); + if (!dispPtr->packInit) { + dispPtr->packInit = 1; + Tcl_InitHashTable(&dispPtr->packerHashTable, TCL_ONE_WORD_KEYS); } /* @@ -968,7 +956,8 @@ GetPacker(tkwin) * then create a new one. */ - hPtr = Tcl_CreateHashEntry(&packerHashTable, (char *) tkwin, &new); + hPtr = Tcl_CreateHashEntry(&dispPtr->packerHashTable, (char *) tkwin, + &new); if (!new) { return (Packer *) Tcl_GetHashValue(hPtr); } @@ -1324,6 +1313,7 @@ PackStructureProc(clientData, eventPtr) XEvent *eventPtr; /* Describes what just happened. */ { register Packer *packPtr = (Packer *) clientData; + if (eventPtr->type == ConfigureNotify) { if ((packPtr->slavePtr != NULL) && !(packPtr->flags & REQUESTED_REPACK)) { @@ -1353,8 +1343,11 @@ PackStructureProc(clientData, eventPtr) nextPtr = slavePtr->nextPtr; slavePtr->nextPtr = NULL; } - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&packerHashTable, - (char *) packPtr->tkwin)); + if (packPtr->tkwin != NULL) { + TkDisplay *dispPtr = ((TkWindow *) packPtr->tkwin)->dispPtr; + Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->packerHashTable, + (char *) packPtr->tkwin)); + } if (packPtr->flags & REQUESTED_REPACK) { Tcl_CancelIdleCall(ArrangePacking, (ClientData) packPtr); } @@ -1372,16 +1365,15 @@ PackStructureProc(clientData, eventPtr) Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr); } } else if (eventPtr->type == UnmapNotify) { - Packer *packPtr2; + register Packer *packPtr2; /* * Unmap all of the slaves when the master gets unmapped, * so that they don't bother to keep redisplaying * themselves. */ - for (packPtr2 = packPtr->slavePtr; packPtr2 != NULL; - packPtr2 = packPtr2->nextPtr) { + packPtr2 = packPtr2->nextPtr) { Tk_UnmapWindow(packPtr2->tkwin); } } @@ -1398,7 +1390,7 @@ PackStructureProc(clientData, eventPtr) * * Results: * TCL_OK is returned if all went well. Otherwise, TCL_ERROR is - * returned and interp->result is set to contain an error message. + * returned and the interp's result is set to contain an error message. * * Side effects: * Slave windows get taken over by the packer. @@ -1725,3 +1717,5 @@ ConfigureSlaves(interp, tkwin, argc, argv) } return TCL_OK; } + + diff --git a/tk/generic/tkPatch.h b/tk/generic/tkPatch.h new file mode 100644 index 00000000000..c36ed20a17a --- /dev/null +++ b/tk/generic/tkPatch.h @@ -0,0 +1,23 @@ +/* + * tkPatch.h -- + * + * This file does nothing except define a "patch level" for Tk. + * The patch level has the form "X.YpZ" where X.Y is the base + * release, and Z is a serial number that is used to sequence + * patches for a given release. Thus 4.0p1 is the first patch + * to release 4.0, 4.0p2 is the patch that follows 4.0p1, and + * so on. The "pZ" is omitted in an original new release, and + * it is replaced with "bZ" for beta releases or "aZ" for alpha + * releases (e.g. 4.0b1 is the first beta release of Tk 4.0). + * The patch level ensures that patches are applied in the + * correct order and only to appropriate sources. + * + * Copyright (c) 1994-1996 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: @(#) tkPatch.h 1.22 96/10/02 14:36:36 + */ + +#define TK_PATCH_LEVEL "4.2" diff --git a/tk/generic/tkPlace.c b/tk/generic/tkPlace.c index 2102b506117..d48895b2d41 100644 --- a/tk/generic/tkPlace.c +++ b/tk/generic/tkPlace.c @@ -5,7 +5,7 @@ * for Tk based on absolute placement or "rubber-sheet" placement. * * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -99,15 +99,6 @@ typedef struct Master { #define PARENT_RECONFIG_PENDING 1 /* - * The hash tables below both use Tk_Window tokens as keys. They map - * from Tk_Windows to Slave and Master structures for windows, if they - * exist. - */ - -static int initialized = 0; -static Tcl_HashTable masterTable; -static Tcl_HashTable slaveTable; -/* * The following structure is the official type record for the * placer: */ @@ -168,16 +159,7 @@ Tk_PlaceCmd(clientData, interp, argc, argv) Tcl_HashEntry *hPtr; size_t length; int c; - - /* - * Initialize, if that hasn't been done yet. - */ - - if (!initialized) { - Tcl_InitHashTable(&masterTable, TCL_ONE_WORD_KEYS); - Tcl_InitHashTable(&slaveTable, TCL_ONE_WORD_KEYS); - initialized = 1; - } + TkDisplay *dispPtr; if (argc < 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", @@ -196,6 +178,18 @@ Tk_PlaceCmd(clientData, interp, argc, argv) if (tkwin == NULL) { return TCL_ERROR; } + + /* + * Initialize, if that hasn't been done yet. + */ + + dispPtr = ((TkWindow *) tkwin)->dispPtr; + if (!dispPtr->placeInit) { + Tcl_InitHashTable(&dispPtr->masterTable, TCL_ONE_WORD_KEYS); + Tcl_InitHashTable(&dispPtr->slaveTable, TCL_ONE_WORD_KEYS); + dispPtr->placeInit = 1; + } + slavePtr = FindSlave(tkwin); return ConfigureSlave(interp, slavePtr, argc-2, argv+2); } @@ -209,6 +203,18 @@ Tk_PlaceCmd(clientData, interp, argc, argv) if (tkwin == NULL) { return TCL_ERROR; } + + /* + * Initialize, if that hasn't been done yet. + */ + + dispPtr = ((TkWindow *) tkwin)->dispPtr; + if (!dispPtr->placeInit) { + Tcl_InitHashTable(&dispPtr->masterTable, TCL_ONE_WORD_KEYS); + Tcl_InitHashTable(&dispPtr->slaveTable, TCL_ONE_WORD_KEYS); + dispPtr->placeInit = 1; + } + if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) { if (argc < 5) { Tcl_AppendResult(interp, "wrong # args: should be \"", @@ -225,7 +231,7 @@ Tk_PlaceCmd(clientData, interp, argc, argv) argv[0], " forget pathName\"", (char *) NULL); return TCL_ERROR; } - hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin); + hPtr = Tcl_FindHashEntry(&dispPtr->slaveTable, (char *) tkwin); if (hPtr == NULL) { return TCL_OK; } @@ -243,14 +249,14 @@ Tk_PlaceCmd(clientData, interp, argc, argv) Tk_UnmapWindow(tkwin); ckfree((char *) slavePtr); } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) { - char buffer[50]; + char buffer[32 + TCL_INTEGER_SPACE]; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " info pathName\"", (char *) NULL); return TCL_ERROR; } - hPtr = Tcl_FindHashEntry(&slaveTable, (char *) tkwin); + hPtr = Tcl_FindHashEntry(&dispPtr->slaveTable, (char *) tkwin); if (hPtr == NULL) { return TCL_OK; } @@ -306,7 +312,7 @@ Tk_PlaceCmd(clientData, interp, argc, argv) argv[0], " slaves pathName\"", (char *) NULL); return TCL_ERROR; } - hPtr = Tcl_FindHashEntry(&masterTable, (char *) tkwin); + hPtr = Tcl_FindHashEntry(&dispPtr->masterTable, (char *) tkwin); if (hPtr != NULL) { Master *masterPtr; masterPtr = (Master *) Tcl_GetHashValue(hPtr); @@ -348,8 +354,9 @@ FindSlave(tkwin) Tcl_HashEntry *hPtr; register Slave *slavePtr; int new; + TkDisplay * dispPtr = ((TkWindow *) tkwin)->dispPtr; - hPtr = Tcl_CreateHashEntry(&slaveTable, (char *) tkwin, &new); + hPtr = Tcl_CreateHashEntry(&dispPtr->slaveTable, (char *) tkwin, &new); if (new) { slavePtr = (Slave *) ckalloc(sizeof(Slave)); slavePtr->tkwin = tkwin; @@ -441,8 +448,9 @@ FindMaster(tkwin) Tcl_HashEntry *hPtr; register Master *masterPtr; int new; + TkDisplay * dispPtr = ((TkWindow *) tkwin)->dispPtr; - hPtr = Tcl_CreateHashEntry(&masterTable, (char *) tkwin, &new); + hPtr = Tcl_CreateHashEntry(&dispPtr->masterTable, (char *) tkwin, &new); if (new) { masterPtr = (Master *) ckalloc(sizeof(Master)); masterPtr->tkwin = tkwin; @@ -467,7 +475,7 @@ FindMaster(tkwin) * * Results: * A standard Tcl result. If an error occurs then a message is - * left in interp->result. + * left in the interp's result. * * Side effects: * Information in slavePtr may change, and slavePtr's master is @@ -843,7 +851,7 @@ RecomputePlacement(clientData) /* * Step 5: reconfigure the window and map it if needed. If the * slave is a child of the master, we do this ourselves. If the - * slave isn't a child of the master, let Tk_MaintainWindow do + * slave isn't a child of the master, let Tk_MaintainGeometry do * the work (it will re-adjust things as relevant windows map, * unmap, and move). */ @@ -902,6 +910,7 @@ MasterStructureProc(clientData, eventPtr) { register Master *masterPtr = (Master *) clientData; register Slave *slavePtr, *nextPtr; + TkDisplay *dispPtr = ((TkWindow *) masterPtr->tkwin)->dispPtr; if (eventPtr->type == ConfigureNotify) { if ((masterPtr->slavePtr != NULL) @@ -916,7 +925,7 @@ MasterStructureProc(clientData, eventPtr) nextPtr = slavePtr->nextPtr; slavePtr->nextPtr = NULL; } - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&masterTable, + Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->masterTable, (char *) masterPtr->tkwin)); if (masterPtr->flags & PARENT_RECONFIG_PENDING) { Tcl_CancelIdleCall(RecomputePlacement, (ClientData) masterPtr); @@ -971,10 +980,11 @@ SlaveStructureProc(clientData, eventPtr) XEvent *eventPtr; /* Describes what just happened. */ { register Slave *slavePtr = (Slave *) clientData; + TkDisplay * dispPtr = ((TkWindow *) slavePtr->tkwin)->dispPtr; if (eventPtr->type == DestroyNotify) { UnlinkSlave(slavePtr); - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&slaveTable, + Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->slaveTable, (char *) slavePtr->tkwin)); ckfree((char *) slavePtr); } @@ -1047,14 +1057,18 @@ PlaceLostSlaveProc(clientData, tkwin) Tk_Window tkwin; /* Tk's handle for the slave window. */ { register Slave *slavePtr = (Slave *) clientData; + TkDisplay * dispPtr = ((TkWindow *) slavePtr->tkwin)->dispPtr; if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) { Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin); } Tk_UnmapWindow(tkwin); UnlinkSlave(slavePtr); - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&slaveTable, (char *) tkwin)); + Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->slaveTable, + (char *) tkwin)); Tk_DeleteEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc, (ClientData) slavePtr); ckfree((char *) slavePtr); } + + diff --git a/tk/generic/tkPlatDecls.h b/tk/generic/tkPlatDecls.h new file mode 100644 index 00000000000..f2c31235b2a --- /dev/null +++ b/tk/generic/tkPlatDecls.h @@ -0,0 +1,208 @@ +/* + * tkPlatDecls.h -- + * + * Declarations of functions in the platform-specific public Tcl API. + * + * Copyright (c) 1998-1999 by Scriptics Corporation. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +#ifndef _TKPLATDECLS +#define _TKPLATDECLS + +#ifdef BUILD_tk +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLEXPORT +#endif + +/* + * WARNING: This file is automatically generated by the tools/genStubs.tcl + * script. Any modifications to the function declarations below should be made + * in the generic/tk.decls script. + */ + + +/* !BEGIN!: Do not edit below this line. */ + +/* + * Exported function declarations: + */ + +#ifdef __WIN32__ +/* 0 */ +EXTERN Window Tk_AttachHWND _ANSI_ARGS_((Tk_Window tkwin, + HWND hwnd)); +/* 1 */ +EXTERN HINSTANCE Tk_GetHINSTANCE _ANSI_ARGS_((void)); +/* 2 */ +EXTERN HWND Tk_GetHWND _ANSI_ARGS_((Window window)); +/* 3 */ +EXTERN Tk_Window Tk_HWNDToWindow _ANSI_ARGS_((HWND hwnd)); +/* 4 */ +EXTERN void Tk_PointerEvent _ANSI_ARGS_((HWND hwnd, int x, int y)); +/* 5 */ +EXTERN int Tk_TranslateWinEvent _ANSI_ARGS_((HWND hwnd, + UINT message, WPARAM wParam, LPARAM lParam, + LRESULT * result)); +#endif /* __WIN32__ */ +#ifdef MAC_TCL +/* 0 */ +EXTERN void Tk_MacSetEmbedHandler _ANSI_ARGS_(( + Tk_MacEmbedRegisterWinProc * registerWinProcPtr, + Tk_MacEmbedGetGrafPortProc * getPortProcPtr, + Tk_MacEmbedMakeContainerExistProc * containerExistProcPtr, + Tk_MacEmbedGetClipProc * getClipProc, + Tk_MacEmbedGetOffsetInParentProc * getOffsetProc)); +/* 1 */ +EXTERN void Tk_MacTurnOffMenus _ANSI_ARGS_((void)); +/* 2 */ +EXTERN void Tk_MacTkOwnsCursor _ANSI_ARGS_((int tkOwnsIt)); +/* 3 */ +EXTERN void TkMacInitMenus _ANSI_ARGS_((Tcl_Interp * interp)); +/* 4 */ +EXTERN void TkMacInitAppleEvents _ANSI_ARGS_(( + Tcl_Interp * interp)); +/* 5 */ +EXTERN int TkMacConvertEvent _ANSI_ARGS_(( + EventRecord * eventPtr)); +/* 6 */ +EXTERN int TkMacConvertTkEvent _ANSI_ARGS_(( + EventRecord * eventPtr, Window window)); +/* 7 */ +EXTERN void TkGenWMConfigureEvent _ANSI_ARGS_((Tk_Window tkwin, + int x, int y, int width, int height, + int flags)); +/* 8 */ +EXTERN void TkMacInvalClipRgns _ANSI_ARGS_((TkWindow * winPtr)); +/* 9 */ +EXTERN int TkMacHaveAppearance _ANSI_ARGS_((void)); +/* 10 */ +EXTERN GWorldPtr TkMacGetDrawablePort _ANSI_ARGS_((Drawable drawable)); +#endif /* MAC_TCL */ + +typedef struct TkPlatStubs { + int magic; + struct TkPlatStubHooks *hooks; + +#ifdef __WIN32__ + Window (*tk_AttachHWND) _ANSI_ARGS_((Tk_Window tkwin, HWND hwnd)); /* 0 */ + HINSTANCE (*tk_GetHINSTANCE) _ANSI_ARGS_((void)); /* 1 */ + HWND (*tk_GetHWND) _ANSI_ARGS_((Window window)); /* 2 */ + Tk_Window (*tk_HWNDToWindow) _ANSI_ARGS_((HWND hwnd)); /* 3 */ + void (*tk_PointerEvent) _ANSI_ARGS_((HWND hwnd, int x, int y)); /* 4 */ + int (*tk_TranslateWinEvent) _ANSI_ARGS_((HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT * result)); /* 5 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tk_MacSetEmbedHandler) _ANSI_ARGS_((Tk_MacEmbedRegisterWinProc * registerWinProcPtr, Tk_MacEmbedGetGrafPortProc * getPortProcPtr, Tk_MacEmbedMakeContainerExistProc * containerExistProcPtr, Tk_MacEmbedGetClipProc * getClipProc, Tk_MacEmbedGetOffsetInParentProc * getOffsetProc)); /* 0 */ + void (*tk_MacTurnOffMenus) _ANSI_ARGS_((void)); /* 1 */ + void (*tk_MacTkOwnsCursor) _ANSI_ARGS_((int tkOwnsIt)); /* 2 */ + void (*tkMacInitMenus) _ANSI_ARGS_((Tcl_Interp * interp)); /* 3 */ + void (*tkMacInitAppleEvents) _ANSI_ARGS_((Tcl_Interp * interp)); /* 4 */ + int (*tkMacConvertEvent) _ANSI_ARGS_((EventRecord * eventPtr)); /* 5 */ + int (*tkMacConvertTkEvent) _ANSI_ARGS_((EventRecord * eventPtr, Window window)); /* 6 */ + void (*tkGenWMConfigureEvent) _ANSI_ARGS_((Tk_Window tkwin, int x, int y, int width, int height, int flags)); /* 7 */ + void (*tkMacInvalClipRgns) _ANSI_ARGS_((TkWindow * winPtr)); /* 8 */ + int (*tkMacHaveAppearance) _ANSI_ARGS_((void)); /* 9 */ + GWorldPtr (*tkMacGetDrawablePort) _ANSI_ARGS_((Drawable drawable)); /* 10 */ +#endif /* MAC_TCL */ +} TkPlatStubs; + +#ifdef __cplusplus +extern "C" { +#endif +extern TkPlatStubs *tkPlatStubsPtr; +#ifdef __cplusplus +} +#endif + +#if defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) + +/* + * Inline function declarations: + */ + +#ifdef __WIN32__ +#ifndef Tk_AttachHWND +#define Tk_AttachHWND \ + (tkPlatStubsPtr->tk_AttachHWND) /* 0 */ +#endif +#ifndef Tk_GetHINSTANCE +#define Tk_GetHINSTANCE \ + (tkPlatStubsPtr->tk_GetHINSTANCE) /* 1 */ +#endif +#ifndef Tk_GetHWND +#define Tk_GetHWND \ + (tkPlatStubsPtr->tk_GetHWND) /* 2 */ +#endif +#ifndef Tk_HWNDToWindow +#define Tk_HWNDToWindow \ + (tkPlatStubsPtr->tk_HWNDToWindow) /* 3 */ +#endif +#ifndef Tk_PointerEvent +#define Tk_PointerEvent \ + (tkPlatStubsPtr->tk_PointerEvent) /* 4 */ +#endif +#ifndef Tk_TranslateWinEvent +#define Tk_TranslateWinEvent \ + (tkPlatStubsPtr->tk_TranslateWinEvent) /* 5 */ +#endif +#endif /* __WIN32__ */ +#ifdef MAC_TCL +#ifndef Tk_MacSetEmbedHandler +#define Tk_MacSetEmbedHandler \ + (tkPlatStubsPtr->tk_MacSetEmbedHandler) /* 0 */ +#endif +#ifndef Tk_MacTurnOffMenus +#define Tk_MacTurnOffMenus \ + (tkPlatStubsPtr->tk_MacTurnOffMenus) /* 1 */ +#endif +#ifndef Tk_MacTkOwnsCursor +#define Tk_MacTkOwnsCursor \ + (tkPlatStubsPtr->tk_MacTkOwnsCursor) /* 2 */ +#endif +#ifndef TkMacInitMenus +#define TkMacInitMenus \ + (tkPlatStubsPtr->tkMacInitMenus) /* 3 */ +#endif +#ifndef TkMacInitAppleEvents +#define TkMacInitAppleEvents \ + (tkPlatStubsPtr->tkMacInitAppleEvents) /* 4 */ +#endif +#ifndef TkMacConvertEvent +#define TkMacConvertEvent \ + (tkPlatStubsPtr->tkMacConvertEvent) /* 5 */ +#endif +#ifndef TkMacConvertTkEvent +#define TkMacConvertTkEvent \ + (tkPlatStubsPtr->tkMacConvertTkEvent) /* 6 */ +#endif +#ifndef TkGenWMConfigureEvent +#define TkGenWMConfigureEvent \ + (tkPlatStubsPtr->tkGenWMConfigureEvent) /* 7 */ +#endif +#ifndef TkMacInvalClipRgns +#define TkMacInvalClipRgns \ + (tkPlatStubsPtr->tkMacInvalClipRgns) /* 8 */ +#endif +#ifndef TkMacHaveAppearance +#define TkMacHaveAppearance \ + (tkPlatStubsPtr->tkMacHaveAppearance) /* 9 */ +#endif +#ifndef TkMacGetDrawablePort +#define TkMacGetDrawablePort \ + (tkPlatStubsPtr->tkMacGetDrawablePort) /* 10 */ +#endif +#endif /* MAC_TCL */ + +#endif /* defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) */ + +/* !END!: Do not edit above this line. */ + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLIMPORT + +#endif /* _TKPLATDECLS */ diff --git a/tk/generic/tkPointer.c b/tk/generic/tkPointer.c index 85a6af87811..f51e82b7506 100644 --- a/tk/generic/tkPointer.c +++ b/tk/generic/tkPointer.c @@ -16,6 +16,10 @@ #include "tkInt.h" +#ifdef __WIN32__ +#include "tkWinInt.h" +#endif + #ifdef MAC_TCL #define Cursor XCursor #endif @@ -32,19 +36,18 @@ static unsigned int buttonMasks[] = { }; #define ButtonMask(b) (buttonMasks[(b)-Button1]) -/* - * Declarations of static variables used in the pointer module. - */ - -static TkWindow *cursorWinPtr = NULL; /* Window that is currently - * controlling the global cursor. */ -static TkWindow *grabWinPtr = NULL; /* Window that defines the top of the +typedef struct ThreadSpecificData { + TkWindow *grabWinPtr; /* Window that defines the top of the * grab tree in a global grab. */ -static XPoint lastPos = { 0, 0}; /* Last reported mouse position. */ -static int lastState = 0; /* Last known state flags. */ -static TkWindow *lastWinPtr = NULL; /* Last reported mouse window. */ -static TkWindow *restrictWinPtr = NULL; /* Window to which all mouse events + int lastState; /* Last known state flags. */ + XPoint lastPos; /* Last reported mouse position. */ + TkWindow *lastWinPtr; /* Last reported mouse window. */ + TkWindow *restrictWinPtr; /* Window to which all mouse events * will be reported. */ + TkWindow *cursorWinPtr; /* Window that is currently + * controlling the global cursor. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; /* * Forward declarations of procedures used in this file. @@ -137,8 +140,12 @@ GenerateEnterLeave(winPtr, x, y, state) int state; /* State flags. */ { int crossed = 0; /* 1 if mouse crossed a window boundary */ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + TkWindow *restrictWinPtr = tsdPtr->restrictWinPtr; + TkWindow *lastWinPtr = tsdPtr->lastWinPtr; - if (winPtr != lastWinPtr) { + if (winPtr != tsdPtr->lastWinPtr) { if (restrictWinPtr) { int newPos, oldPos; @@ -196,7 +203,7 @@ GenerateEnterLeave(winPtr, x, y, state) crossed = 1; } } - lastWinPtr = winPtr; + tsdPtr->lastWinPtr = winPtr; } return crossed; @@ -226,11 +233,13 @@ Tk_UpdatePointer(tkwin, x, y, state) int x, y; /* Pointer location in root coords. */ int state; /* Modifier state mask. */ { + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); TkWindow *winPtr = (TkWindow *)tkwin; TkWindow *targetWinPtr; XPoint pos; XEvent event; - int changes = (state ^ lastState) & ALL_BUTTONS; + int changes = (state ^ tsdPtr->lastState) & ALL_BUTTONS; int type, b, mask; pos.x = x; @@ -241,7 +250,8 @@ Tk_UpdatePointer(tkwin, x, y, state) * state since we haven't generated the button events yet. */ - lastState = (state & ~ALL_BUTTONS) | (lastState & ALL_BUTTONS); + tsdPtr->lastState = (state & ~ALL_BUTTONS) | (tsdPtr->lastState + & ALL_BUTTONS); /* * Generate Enter/Leave events. If the pointer has crossed window @@ -249,8 +259,8 @@ Tk_UpdatePointer(tkwin, x, y, state) * redundant motion events. */ - if (GenerateEnterLeave(winPtr, x, y, lastState)) { - lastPos = pos; + if (GenerateEnterLeave(winPtr, x, y, tsdPtr->lastState)) { + tsdPtr->lastPos = pos; } /* @@ -269,30 +279,30 @@ Tk_UpdatePointer(tkwin, x, y, state) * if this is the first button down. */ - if (!restrictWinPtr) { - if (!grabWinPtr) { + if (!tsdPtr->restrictWinPtr) { + if (!tsdPtr->grabWinPtr) { /* * Mouse is not grabbed, so set a button grab. */ - restrictWinPtr = winPtr; - TkpSetCapture(restrictWinPtr); + tsdPtr->restrictWinPtr = winPtr; + TkpSetCapture(tsdPtr->restrictWinPtr); - } else if ((lastState & ALL_BUTTONS) == 0) { + } else if ((tsdPtr->lastState & ALL_BUTTONS) == 0) { /* * Mouse is in a non-button grab, so ensure * the button grab is inside the grab tree. */ - if (TkPositionInTree(winPtr, grabWinPtr) + if (TkPositionInTree(winPtr, tsdPtr->grabWinPtr) == TK_GRAB_IN_TREE) { - restrictWinPtr = winPtr; + tsdPtr->restrictWinPtr = winPtr; } else { - restrictWinPtr = grabWinPtr; + tsdPtr->restrictWinPtr = tsdPtr->grabWinPtr; } - TkpSetCapture(restrictWinPtr); + TkpSetCapture(tsdPtr->restrictWinPtr); } } @@ -305,8 +315,8 @@ Tk_UpdatePointer(tkwin, x, y, state) * aren't in a global grab. */ - if ((lastState & ALL_BUTTONS) == mask) { - if (!grabWinPtr) { + if ((tsdPtr->lastState & ALL_BUTTONS) == mask) { + if (!tsdPtr->grabWinPtr) { TkpSetCapture(NULL); } } @@ -317,16 +327,16 @@ Tk_UpdatePointer(tkwin, x, y, state) * the restrict window to the current mouse position. */ - if (restrictWinPtr) { - InitializeEvent(&event, restrictWinPtr, type, x, y, - lastState, b); + if (tsdPtr->restrictWinPtr) { + InitializeEvent(&event, tsdPtr->restrictWinPtr, type, x, y, + tsdPtr->lastState, b); Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); - lastState &= ~mask; - lastWinPtr = restrictWinPtr; - restrictWinPtr = NULL; + tsdPtr->lastState &= ~mask; + tsdPtr->lastWinPtr = tsdPtr->restrictWinPtr; + tsdPtr->restrictWinPtr = NULL; - GenerateEnterLeave(winPtr, x, y, lastState); - lastPos = pos; + GenerateEnterLeave(winPtr, x, y, tsdPtr->lastState); + tsdPtr->lastPos = pos; continue; } } @@ -338,10 +348,10 @@ Tk_UpdatePointer(tkwin, x, y, state) * managed by Tk should be reported to the grab window. */ - if (restrictWinPtr) { - targetWinPtr = restrictWinPtr; - } else if (grabWinPtr && !winPtr) { - targetWinPtr = grabWinPtr; + if (tsdPtr->restrictWinPtr) { + targetWinPtr = tsdPtr->restrictWinPtr; + } else if (tsdPtr->grabWinPtr && !winPtr) { + targetWinPtr = tsdPtr->grabWinPtr; } else { targetWinPtr = winPtr; } @@ -352,7 +362,7 @@ Tk_UpdatePointer(tkwin, x, y, state) if (winPtr != NULL) { InitializeEvent(&event, targetWinPtr, type, x, y, - lastState, b); + tsdPtr->lastState, b); Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); } @@ -360,9 +370,9 @@ Tk_UpdatePointer(tkwin, x, y, state) * Update the state for the next iteration. */ - lastState = (type == ButtonPress) - ? (lastState | mask) : (lastState & ~mask); - lastPos = pos; + tsdPtr->lastState = (type == ButtonPress) + ? (tsdPtr->lastState | mask) : (tsdPtr->lastState & ~mask); + tsdPtr->lastPos = pos; } } @@ -370,11 +380,11 @@ Tk_UpdatePointer(tkwin, x, y, state) * Make sure the cursor window is up to date. */ - if (restrictWinPtr) { - targetWinPtr = restrictWinPtr; - } else if (grabWinPtr) { - targetWinPtr = (TkPositionInTree(winPtr, grabWinPtr) - == TK_GRAB_IN_TREE) ? winPtr : grabWinPtr; + if (tsdPtr->restrictWinPtr) { + targetWinPtr = tsdPtr->restrictWinPtr; + } else if (tsdPtr->grabWinPtr) { + targetWinPtr = (TkPositionInTree(winPtr, tsdPtr->grabWinPtr) + == TK_GRAB_IN_TREE) ? winPtr : tsdPtr->grabWinPtr; } else { targetWinPtr = winPtr; } @@ -385,19 +395,19 @@ Tk_UpdatePointer(tkwin, x, y, state) * generate a motion event. */ - if (lastPos.x != pos.x || lastPos.y != pos.y) { - if (restrictWinPtr) { - targetWinPtr = restrictWinPtr; - } else if (grabWinPtr && !winPtr) { - targetWinPtr = grabWinPtr; + if (tsdPtr->lastPos.x != pos.x || tsdPtr->lastPos.y != pos.y) { + if (tsdPtr->restrictWinPtr) { + targetWinPtr = tsdPtr->restrictWinPtr; + } else if (tsdPtr->grabWinPtr && !winPtr) { + targetWinPtr = tsdPtr->grabWinPtr; } if (targetWinPtr != NULL) { InitializeEvent(&event, targetWinPtr, MotionNotify, x, y, - lastState, NotifyNormal); + tsdPtr->lastState, NotifyNormal); Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); } - lastPos = pos; + tsdPtr->lastPos = pos; } } @@ -433,12 +443,16 @@ XGrabPointer(display, grab_window, owner_events, event_mask, pointer_mode, Cursor cursor; Time time; { + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + display->request++; - grabWinPtr = (TkWindow *) Tk_IdToWindow(display, grab_window); - restrictWinPtr = NULL; - TkpSetCapture(grabWinPtr); - if (TkPositionInTree(lastWinPtr, grabWinPtr) != TK_GRAB_IN_TREE) { - UpdateCursor(grabWinPtr); + tsdPtr->grabWinPtr = (TkWindow *) Tk_IdToWindow(display, grab_window); + tsdPtr->restrictWinPtr = NULL; + TkpSetCapture(tsdPtr->grabWinPtr); + if (TkPositionInTree(tsdPtr->lastWinPtr, tsdPtr->grabWinPtr) + != TK_GRAB_IN_TREE) { + UpdateCursor(tsdPtr->grabWinPtr); } return GrabSuccess; } @@ -464,11 +478,14 @@ XUngrabPointer(display, time) Display* display; Time time; { + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + display->request++; - grabWinPtr = NULL; - restrictWinPtr = NULL; + tsdPtr->grabWinPtr = NULL; + tsdPtr->restrictWinPtr = NULL; TkpSetCapture(NULL); - UpdateCursor(lastWinPtr); + UpdateCursor(tsdPtr->lastWinPtr); } /* @@ -491,16 +508,19 @@ void TkPointerDeadWindow(winPtr) TkWindow *winPtr; { - if (winPtr == lastWinPtr) { - lastWinPtr = NULL; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + if (winPtr == tsdPtr->lastWinPtr) { + tsdPtr->lastWinPtr = NULL; } - if (winPtr == grabWinPtr) { - grabWinPtr = NULL; + if (winPtr == tsdPtr->grabWinPtr) { + tsdPtr->grabWinPtr = NULL; } - if (winPtr == restrictWinPtr) { - restrictWinPtr = NULL; + if (winPtr == tsdPtr->restrictWinPtr) { + tsdPtr->restrictWinPtr = NULL; } - if (!(restrictWinPtr || grabWinPtr)) { + if (!(tsdPtr->restrictWinPtr || tsdPtr->grabWinPtr)) { TkpSetCapture(NULL); } } @@ -527,6 +547,8 @@ UpdateCursor(winPtr) TkWindow *winPtr; { Cursor cursor = None; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * A window inherits its cursor from its parent if it doesn't @@ -534,7 +556,7 @@ UpdateCursor(winPtr) * cursor. */ - cursorWinPtr = winPtr; + tsdPtr->cursorWinPtr = winPtr; while (winPtr != NULL) { if (winPtr->atts.cursor != None) { cursor = winPtr->atts.cursor; @@ -573,8 +595,10 @@ XDefineCursor(display, w, cursor) Cursor cursor; { TkWindow *winPtr = (TkWindow *)Tk_IdToWindow(display, w); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - if (cursorWinPtr == winPtr) { + if (tsdPtr->cursorWinPtr == winPtr) { UpdateCursor(winPtr); } display->request++; @@ -621,3 +645,4 @@ TkGenerateActivateEvents(winPtr, active) TkQueueEventForAllChildren(winPtr, &event); } + diff --git a/tk/generic/tkPort.h b/tk/generic/tkPort.h index ab9f28b15f8..aef9026bcc6 100644 --- a/tk/generic/tkPort.h +++ b/tk/generic/tkPort.h @@ -34,3 +34,4 @@ #endif #endif /* _TKPORT */ + diff --git a/tk/generic/tkRectOval.c b/tk/generic/tkRectOval.c index daa39dafbdf..0bb54885371 100644 --- a/tk/generic/tkRectOval.c +++ b/tk/generic/tkRectOval.c @@ -5,7 +5,7 @@ * widgets. * * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -17,6 +17,7 @@ #include "tk.h" #include "tkInt.h" #include "tkPort.h" +#include "tkCanvas.h" /* * The structure below defines the record for each rectangle/oval item. @@ -25,14 +26,17 @@ typedef struct RectOvalItem { Tk_Item header; /* Generic stuff that's the same for all * types. MUST BE FIRST IN STRUCTURE. */ + Tk_Outline outline; /* Outline structure */ double bbox[4]; /* Coordinates of bounding box for rectangle * or oval (x1, y1, x2, y2). Item includes * x1 and x2 but not y1 and y2. */ - int width; /* Width of outline. */ - XColor *outlineColor; /* Color for outline. */ + Tk_TSOffset tsoffset; XColor *fillColor; /* Color for filling rectangle/oval. */ + XColor *activeFillColor; /* Color for filling rectangle/oval if state is active. */ + XColor *disabledFillColor; /* Color for filling rectangle/oval if state is disabled. */ Pixmap fillStipple; /* Stipple bitmap for filling item. */ - GC outlineGC; /* Graphics context for outline. */ + Pixmap activeFillStipple; /* Stipple bitmap for filling item if state is active. */ + Pixmap disabledFillStipple; /* Stipple bitmap for filling item if state is disabled. */ GC fillGC; /* Graphics context for filling item. */ } RectOvalItem; @@ -40,21 +44,93 @@ typedef struct RectOvalItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; +static Tk_CustomOption dashOption = { + (Tk_OptionParseProc *) TkCanvasDashParseProc, + TkCanvasDashPrintProc, (ClientData) NULL +}; +static Tk_CustomOption offsetOption = { + (Tk_OptionParseProc *) TkOffsetParseProc, + TkOffsetPrintProc, (ClientData) TK_OFFSET_RELATIVE +}; +static Tk_CustomOption pixelOption = { + (Tk_OptionParseProc *) TkPixelParseProc, + TkPixelPrintProc, (ClientData) NULL +}; static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_CUSTOM, "-activedash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.activeDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, activeFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-activeoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.activeColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activeoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.activeStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, activeFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-activewidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(RectOvalItem, outline.activeWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, + {TK_CONFIG_CUSTOM, "-dash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.dash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_PIXELS, "-dashoffset", (char *) NULL, (char *) NULL, + "0", Tk_Offset(RectOvalItem, outline.offset), + TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-disableddash", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.disabledDash), + TK_CONFIG_NULL_OK, &dashOption}, + {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, disabledFillColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_COLOR, "-disabledoutline", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.disabledColor), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledoutlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.disabledStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, disabledFillStipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_PIXELS, "-disabledwidth", (char *) NULL, (char *) NULL, + "0.0", Tk_Offset(RectOvalItem, outline.disabledWidth), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(RectOvalItem, fillColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(RectOvalItem, tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, - "black", Tk_Offset(RectOvalItem, outlineColor), TK_CONFIG_NULL_OK}, + "black", Tk_Offset(RectOvalItem, outline.color), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-outlineoffset", (char *) NULL, (char *) NULL, + "0,0", Tk_Offset(RectOvalItem, outline.tsoffset), + TK_CONFIG_DONT_SET_DEFAULT, &offsetOption}, + {TK_CONFIG_BITMAP, "-outlinestipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(RectOvalItem, outline.stipple), + TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state),TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(RectOvalItem, fillStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, - {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, - "1", Tk_Offset(RectOvalItem, width), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-width", (char *) NULL, (char *) NULL, + "1.0", Tk_Offset(RectOvalItem, outline.width), + TK_CONFIG_DONT_SET_DEFAULT, &pixelOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; @@ -67,10 +143,10 @@ static void ComputeRectOvalBbox _ANSI_ARGS_((Tk_Canvas canvas, RectOvalItem *rectOvalPtr)); static int ConfigureRectOval _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateRectOval _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteRectOval _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayRectOval _ANSI_ARGS_((Tk_Canvas canvas, @@ -82,7 +158,7 @@ static double OvalToPoint _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr)); static int RectOvalCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); + Tcl_Obj *CONST argv[])); static int RectOvalToPostscript _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); static int RectToArea _ANSI_ARGS_((Tk_Canvas canvas, @@ -109,7 +185,7 @@ Tk_ItemType tkRectangleType = { RectOvalCoords, /* coordProc */ DeleteRectOval, /* deleteProc */ DisplayRectOval, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ RectToPoint, /* pointProc */ RectToArea, /* areaProc */ RectOvalToPostscript, /* postscriptProc */ @@ -120,7 +196,7 @@ Tk_ItemType tkRectangleType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; Tk_ItemType tkOvalType = { @@ -132,7 +208,7 @@ Tk_ItemType tkOvalType = { RectOvalCoords, /* coordProc */ DeleteRectOval, /* deleteProc */ DisplayRectOval, /* displayProc */ - 0, /* alwaysRedraw */ + TK_CONFIG_OBJS, /* flags */ OvalToPoint, /* pointProc */ OvalToArea, /* areaProc */ RectOvalToPostscript, /* postscriptProc */ @@ -143,7 +219,7 @@ Tk_ItemType tkOvalType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; /* @@ -157,7 +233,7 @@ Tk_ItemType tkOvalType = { * Results: * A standard Tcl return value. If an error occurred in * creating the item, then an error message is left in - * interp->result; in this case itemPtr is left uninitialized, + * the interp's result; in this case itemPtr is left uninitialized, * so it can be safely freed by the caller. * * Side effects: @@ -173,11 +249,25 @@ CreateRectOval(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ + Tcl_Obj *CONST argv[]; /* Arguments describing rectangle. */ { RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; + int i; + + + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj(argv[1], NULL); + if ((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z')) { + i = 1; + } else { + i = 4; + } + } - if (argc < 4) { + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?\"", @@ -190,34 +280,33 @@ CreateRectOval(interp, canvas, itemPtr, argc, argv) * up after errors during the the remainder of this procedure. */ - rectOvalPtr->width = 1; - rectOvalPtr->outlineColor = NULL; + Tk_CreateOutline(&(rectOvalPtr->outline)); + rectOvalPtr->tsoffset.flags = 0; + rectOvalPtr->tsoffset.xoffset = 0; + rectOvalPtr->tsoffset.yoffset = 0; rectOvalPtr->fillColor = NULL; + rectOvalPtr->activeFillColor = NULL; + rectOvalPtr->disabledFillColor = NULL; rectOvalPtr->fillStipple = None; - rectOvalPtr->outlineGC = None; + rectOvalPtr->activeFillStipple = None; + rectOvalPtr->disabledFillStipple = None; rectOvalPtr->fillGC = None; /* * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], - &rectOvalPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &rectOvalPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], - &rectOvalPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], - &rectOvalPtr->bbox[3]) != TCL_OK)) { - return TCL_ERROR; + if ((RectOvalCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureRectOval(interp, canvas, itemPtr, argc-4, argv+4, 0) - != TCL_OK) { - DeleteRectOval(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureRectOval(interp, canvas, itemPtr, argc-i, argv+i, 0) + == TCL_OK) { + return TCL_OK; } - return TCL_OK; + + error: + DeleteRectOval(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -230,7 +319,7 @@ CreateRectOval(interp, canvas, itemPtr, argc, argv) * for details on what it does. * * Results: - * Returns TCL_OK or TCL_ERROR, and sets interp->result. + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. * * Side effects: * The coordinates for the given item may be changed. @@ -246,36 +335,51 @@ RectOvalCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - char c0[TCL_DOUBLE_SPACE], c1[TCL_DOUBLE_SPACE]; - char c2[TCL_DOUBLE_SPACE], c3[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, rectOvalPtr->bbox[0], c0); - Tcl_PrintDouble(interp, rectOvalPtr->bbox[1], c1); - Tcl_PrintDouble(interp, rectOvalPtr->bbox[2], c2); - Tcl_PrintDouble(interp, rectOvalPtr->bbox[3], c3); - Tcl_AppendResult(interp, c0, " ", c1, " ", c2, " ", c3, - (char *) NULL); - } else if (argc == 4) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], - &rectOvalPtr->bbox[0]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(rectOvalPtr->bbox[0]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(rectOvalPtr->bbox[1]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(rectOvalPtr->bbox[2]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(rectOvalPtr->bbox[3]); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if ((argc == 1)||(argc == 4)) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 4) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 4, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], + &rectOvalPtr->bbox[0]) != TCL_OK) + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], &rectOvalPtr->bbox[1]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[2], + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[2], &rectOvalPtr->bbox[2]) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[3], + || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[3], &rectOvalPtr->bbox[3]) != TCL_OK)) { return TCL_ERROR; } ComputeRectOvalBbox(canvas, rectOvalPtr); } else { - sprintf(interp->result, - "wrong # coordinates: expected 0 or 4, got %d", - argc); + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 4, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; @@ -292,7 +396,7 @@ RectOvalCoords(interp, canvas, itemPtr, argc, argv) * * Results: * A standard Tcl result code. If an error occurs, then - * an error message is left in interp->result. + * an error message is left in the interp's result. * * Side effects: * Configuration information, such as colors and stipple @@ -307,7 +411,7 @@ ConfigureRectOval(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Rectangle item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; @@ -315,54 +419,136 @@ ConfigureRectOval(interp, canvas, itemPtr, argc, argv, flags) GC newGC; unsigned long mask; Tk_Window tkwin; + Tk_TSOffset *tsoffset; + XColor *color; + Pixmap stipple; + Tk_State state; tkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, - (char *) rectOvalPtr, flags) != TCL_OK) { + + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv, + (char *) rectOvalPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } + state = itemPtr->state; /* * A few of the options require additional processing, such as * graphics contexts. */ - if (rectOvalPtr->width < 1) { - rectOvalPtr->width = 1; - } - if (rectOvalPtr->outlineColor == NULL) { - newGC = None; + if (rectOvalPtr->outline.activeWidth > rectOvalPtr->outline.width || + rectOvalPtr->outline.activeDash.number != 0 || + rectOvalPtr->outline.activeColor != NULL || + rectOvalPtr->outline.activeStipple != None || + rectOvalPtr->activeFillColor != NULL || + rectOvalPtr->activeFillStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; } else { - gcValues.foreground = rectOvalPtr->outlineColor->pixel; + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + tsoffset = &rectOvalPtr->outline.tsoffset; + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) ((rectOvalPtr->bbox[0]+rectOvalPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) ((rectOvalPtr->bbox[1]+rectOvalPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[2] + 0.5); + } + + /* + * Configure the outline graphics context. If mask is non-zero, + * the gc has changed and must be reallocated, provided that the + * new settings specify a valid outline (non-zero width and non-NULL + * color) + */ + + mask = Tk_ConfigOutlineGC(&gcValues, canvas, itemPtr, + &(rectOvalPtr->outline)); + if (mask && \ + rectOvalPtr->outline.width != 0 && \ + rectOvalPtr->outline.color != NULL) { gcValues.cap_style = CapProjecting; - gcValues.line_width = rectOvalPtr->width; - mask = GCForeground|GCCapStyle|GCLineWidth; - newGC = Tk_GetGCColor(tkwin, mask, &gcValues, - rectOvalPtr->outlineColor, NULL); + mask |= GCCapStyle; + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = None; + } + if (rectOvalPtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->outline.gc); } - if (rectOvalPtr->outlineGC != None) { - Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->outlineGC); + rectOvalPtr->outline.gc = newGC; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (state==TK_STATE_HIDDEN) { + ComputeRectOvalBbox(canvas, rectOvalPtr); + return TCL_OK; } - rectOvalPtr->outlineGC = newGC; - if (rectOvalPtr->fillColor == NULL) { + color = rectOvalPtr->fillColor; + stipple = rectOvalPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectOvalPtr->activeFillColor!=NULL) { + color = rectOvalPtr->activeFillColor; + } + if (rectOvalPtr->activeFillStipple!=None) { + stipple = rectOvalPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (rectOvalPtr->disabledFillColor!=NULL) { + color = rectOvalPtr->disabledFillColor; + } + if (rectOvalPtr->disabledFillStipple!=None) { + stipple = rectOvalPtr->disabledFillStipple; + } + } + + if (color == NULL) { newGC = None; } else { - gcValues.foreground = rectOvalPtr->fillColor->pixel; - if (rectOvalPtr->fillStipple != None) { - gcValues.stipple = rectOvalPtr->fillStipple; + gcValues.foreground = color->pixel; + if (stipple != None) { + gcValues.stipple = stipple; gcValues.fill_style = FillStippled; mask = GCForeground|GCStipple|GCFillStyle; } else { mask = GCForeground; } - newGC = Tk_GetGCColor(tkwin, mask, &gcValues, rectOvalPtr->fillColor, - NULL); + newGC = Tk_GetGC(tkwin, mask, &gcValues); } if (rectOvalPtr->fillGC != None) { Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->fillGC); } rectOvalPtr->fillGC = newGC; + + tsoffset = &rectOvalPtr->tsoffset; + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) ((rectOvalPtr->bbox[0]+rectOvalPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) ((rectOvalPtr->bbox[1]+rectOvalPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[3] + 0.5); + } + ComputeRectOvalBbox(canvas, rectOvalPtr); return TCL_OK; @@ -394,17 +580,24 @@ DeleteRectOval(canvas, itemPtr, display) { RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; - if (rectOvalPtr->outlineColor != NULL) { - Tk_FreeColor(rectOvalPtr->outlineColor); - } + Tk_DeleteOutline(display, &(rectOvalPtr->outline)); if (rectOvalPtr->fillColor != NULL) { Tk_FreeColor(rectOvalPtr->fillColor); } + if (rectOvalPtr->activeFillColor != NULL) { + Tk_FreeColor(rectOvalPtr->activeFillColor); + } + if (rectOvalPtr->disabledFillColor != NULL) { + Tk_FreeColor(rectOvalPtr->disabledFillColor); + } if (rectOvalPtr->fillStipple != None) { Tk_FreeBitmap(display, rectOvalPtr->fillStipple); } - if (rectOvalPtr->outlineGC != None) { - Tk_FreeGC(display, rectOvalPtr->outlineGC); + if (rectOvalPtr->activeFillStipple != None) { + Tk_FreeBitmap(display, rectOvalPtr->activeFillStipple); + } + if (rectOvalPtr->disabledFillStipple != None) { + Tk_FreeBitmap(display, rectOvalPtr->disabledFillStipple); } if (rectOvalPtr->fillGC != None) { Tk_FreeGC(display, rectOvalPtr->fillGC); @@ -438,7 +631,28 @@ ComputeRectOvalBbox(canvas, rectOvalPtr) * recomputed. */ { int bloat, tmp; - double dtmp; + double dtmp, width; + Tk_State state = rectOvalPtr->header.state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = rectOvalPtr->outline.width; + if (state==TK_STATE_HIDDEN) { + rectOvalPtr->header.x1 = rectOvalPtr->header.y1 = + rectOvalPtr->header.x2 = rectOvalPtr->header.y2 = -1; + return; + } + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)rectOvalPtr) { + if (rectOvalPtr->outline.activeWidth>width) { + width = rectOvalPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (rectOvalPtr->outline.disabledWidth>0) { + width = rectOvalPtr->outline.disabledWidth; + } + } /* * Make sure that the first coordinates are the lowest ones. @@ -457,10 +671,19 @@ ComputeRectOvalBbox(canvas, rectOvalPtr) rectOvalPtr->bbox[0] = tmp; } - if (rectOvalPtr->outlineColor == NULL) { + if (rectOvalPtr->outline.gc == None) { + /* + * The Win32 switch was added for 8.3 to solve a problem + * with ovals leaving traces on bottom and right of 1 pixel. + * This may not be the correct place to solve it, but it works. + */ +#ifdef __WIN32__ + bloat = 1; +#else bloat = 0; +#endif } else { - bloat = (rectOvalPtr->width+1)/2; + bloat = (int) (width+1)/2; } /* @@ -519,6 +742,8 @@ DisplayRectOval(canvas, itemPtr, display, drawable, x, y, width, height) { RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; short x1, y1, x2, y2; + Pixmap fillStipple; + Tk_State state = itemPtr->state; /* * Compute the screen coordinates of the bounding box for the item. @@ -544,9 +769,48 @@ DisplayRectOval(canvas, itemPtr, display, drawable, x, y, width, height) * read-only. */ + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + fillStipple = rectOvalPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)rectOvalPtr) { + if (rectOvalPtr->activeFillStipple!=None) { + fillStipple = rectOvalPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (rectOvalPtr->disabledFillStipple!=None) { + fillStipple = rectOvalPtr->disabledFillStipple; + } + } + if (rectOvalPtr->fillGC != None) { - if (rectOvalPtr->fillStipple != None) { - Tk_CanvasSetStippleOrigin(canvas, rectOvalPtr->fillGC); + if (fillStipple != None) { + Tk_TSOffset *tsoffset; + int w=0; int h=0; + tsoffset = &rectOvalPtr->tsoffset; + if (tsoffset) { + int flags = tsoffset->flags; + if (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE)) { + Tk_SizeOfBitmap(display, fillStipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset->xoffset -= w; + tsoffset->yoffset -= h; + } + Tk_CanvasSetOffset(canvas, rectOvalPtr->fillGC, tsoffset); + if (tsoffset) { + tsoffset->xoffset += w; + tsoffset->yoffset += h; + } } if (rectOvalPtr->header.typePtr == &tkRectangleType) { XFillRectangle(display, drawable, rectOvalPtr->fillGC, @@ -556,18 +820,20 @@ DisplayRectOval(canvas, itemPtr, display, drawable, x, y, width, height) x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), 0, 360*64); } - if (rectOvalPtr->fillStipple != None) { + if (fillStipple != None) { XSetTSOrigin(display, rectOvalPtr->fillGC, 0, 0); } } - if (rectOvalPtr->outlineGC != None) { + if (rectOvalPtr->outline.gc != None) { + Tk_ChangeOutlineGC(canvas, itemPtr, &(rectOvalPtr->outline)); if (rectOvalPtr->header.typePtr == &tkRectangleType) { - XDrawRectangle(display, drawable, rectOvalPtr->outlineGC, + XDrawRectangle(display, drawable, rectOvalPtr->outline.gc, x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1)); } else { - XDrawArc(display, drawable, rectOvalPtr->outlineGC, + XDrawArc(display, drawable, rectOvalPtr->outline.gc, x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), 0, 360*64); } + Tk_ResetOutlineGC(canvas, itemPtr, &(rectOvalPtr->outline)); } } @@ -603,6 +869,23 @@ RectToPoint(canvas, itemPtr, pointPtr) { RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; double xDiff, yDiff, x1, y1, x2, y2, inc, tmp; + double width; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = rectPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectPtr->outline.activeWidth>width) { + width = rectPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (rectPtr->outline.disabledWidth>0) { + width = rectPtr->outline.disabledWidth; + } + } /* * Generate a new larger rectangle that includes the border @@ -613,8 +896,8 @@ RectToPoint(canvas, itemPtr, pointPtr) y1 = rectPtr->bbox[1]; x2 = rectPtr->bbox[2]; y2 = rectPtr->bbox[3]; - if (rectPtr->outlineGC != None) { - inc = rectPtr->width/2.0; + if (rectPtr->outline.gc != None) { + inc = width/2.0; x1 -= inc; y1 -= inc; x2 += inc; @@ -630,7 +913,7 @@ RectToPoint(canvas, itemPtr, pointPtr) if ((pointPtr[0] >= x1) && (pointPtr[0] < x2) && (pointPtr[1] >= y1) && (pointPtr[1] < y2)) { - if ((rectPtr->fillGC != None) || (rectPtr->outlineGC == None)) { + if ((rectPtr->fillGC != None) || (rectPtr->outline.gc == None)) { return 0.0; } xDiff = pointPtr[0] - x1; @@ -646,7 +929,7 @@ RectToPoint(canvas, itemPtr, pointPtr) if (yDiff < xDiff) { xDiff = yDiff; } - xDiff -= rectPtr->width; + xDiff -= width; if (xDiff < 0.0) { return 0.0; } @@ -709,10 +992,26 @@ OvalToPoint(canvas, itemPtr, pointPtr) RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; double width; int filled; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = (double) ovalPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (ovalPtr->outline.activeWidth>width) { + width = (double) ovalPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (ovalPtr->outline.disabledWidth>0) { + width = (double) ovalPtr->outline.disabledWidth; + } + } + - width = ovalPtr->width; filled = ovalPtr->fillGC != None; - if (ovalPtr->outlineGC == None) { + if (ovalPtr->outline.gc == None) { width = 0.0; filled = 1; } @@ -750,9 +1049,26 @@ RectToArea(canvas, itemPtr, areaPtr) { RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; double halfWidth; + double width; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } - halfWidth = rectPtr->width/2.0; - if (rectPtr->outlineGC == None) { + width = rectPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectPtr->outline.activeWidth>width) { + width = rectPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (rectPtr->outline.disabledWidth>0) { + width = rectPtr->outline.disabledWidth; + } + } + + halfWidth = width/2.0; + if (rectPtr->outline.gc == None) { halfWidth = 0.0; } @@ -762,7 +1078,7 @@ RectToArea(canvas, itemPtr, areaPtr) || (areaPtr[1] >= (rectPtr->bbox[3] + halfWidth))) { return -1; } - if ((rectPtr->fillGC == None) && (rectPtr->outlineGC != None) + if ((rectPtr->fillGC == None) && (rectPtr->outline.gc != None) && (areaPtr[0] >= (rectPtr->bbox[0] + halfWidth)) && (areaPtr[1] >= (rectPtr->bbox[1] + halfWidth)) && (areaPtr[2] <= (rectPtr->bbox[2] - halfWidth)) @@ -810,13 +1126,30 @@ OvalToArea(canvas, itemPtr, areaPtr) RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; double oval[4], halfWidth; int result; + double width; + Tk_State state = itemPtr->state; + + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + + width = ovalPtr->outline.width; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (ovalPtr->outline.activeWidth>width) { + width = ovalPtr->outline.activeWidth; + } + } else if (state==TK_STATE_DISABLED) { + if (ovalPtr->outline.disabledWidth>0) { + width = ovalPtr->outline.disabledWidth; + } + } /* * Expand the oval to include the width of the outline, if any. */ - halfWidth = ovalPtr->width/2.0; - if (ovalPtr->outlineGC == None) { + halfWidth = width/2.0; + if (ovalPtr->outline.gc == None) { halfWidth = 0.0; } oval[0] = ovalPtr->bbox[0] - halfWidth; @@ -833,9 +1166,9 @@ OvalToArea(canvas, itemPtr, areaPtr) * unfilled center, in which case we should return "outside". */ - if ((result == 0) && (ovalPtr->outlineGC != None) + if ((result == 0) && (ovalPtr->outline.gc != None) && (ovalPtr->fillGC == None)) { - double centerX, centerY, width, height; + double centerX, centerY, height; double xDelta1, yDelta1, xDelta2, yDelta2; centerX = (ovalPtr->bbox[0] + ovalPtr->bbox[2])/2.0; @@ -944,7 +1277,7 @@ TranslateRectOval(canvas, itemPtr, deltaX, deltaY) * Results: * The return value is a standard Tcl result. If an error * occurs in generating Postscript then an error message is - * left in interp->result, replacing whatever used to be there. + * left in the interp's result, replacing whatever used to be there. * If no error occurs, then Postscript for the rectangle is * appended to the result. * @@ -964,9 +1297,13 @@ RectOvalToPostscript(interp, canvas, itemPtr, prepass) * collect font information; 0 means * final Postscript is being created. */ { - char pathCmd[500], string[100]; + char pathCmd[500]; RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; double y1, y2; + XColor *color; + XColor *fillColor; + Pixmap fillStipple; + Tk_State state = itemPtr->state; y1 = Tk_CanvasPsY(canvas, rectOvalPtr->bbox[1]); y2 = Tk_CanvasPsY(canvas, rectOvalPtr->bbox[3]); @@ -989,23 +1326,51 @@ RectOvalToPostscript(interp, canvas, itemPtr, prepass) (rectOvalPtr->bbox[2] - rectOvalPtr->bbox[0])/2, (y1 - y2)/2); } + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + color = rectOvalPtr->outline.color; + fillColor = rectOvalPtr->fillColor; + fillStipple = rectOvalPtr->fillStipple; + if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectOvalPtr->outline.activeColor!=NULL) { + color = rectOvalPtr->outline.activeColor; + } + if (rectOvalPtr->activeFillColor!=NULL) { + fillColor = rectOvalPtr->activeFillColor; + } + if (rectOvalPtr->activeFillStipple!=None) { + fillStipple = rectOvalPtr->activeFillStipple; + } + } else if (state==TK_STATE_DISABLED) { + if (rectOvalPtr->outline.disabledColor!=NULL) { + color = rectOvalPtr->outline.disabledColor; + } + if (rectOvalPtr->disabledFillColor!=NULL) { + fillColor = rectOvalPtr->disabledFillColor; + } + if (rectOvalPtr->disabledFillStipple!=None) { + fillStipple = rectOvalPtr->disabledFillStipple; + } + } + /* * First draw the filled area of the rectangle. */ - if (rectOvalPtr->fillColor != NULL) { + if (fillColor != NULL) { Tcl_AppendResult(interp, pathCmd, (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, rectOvalPtr->fillColor) + if (Tk_CanvasPsColor(interp, canvas, fillColor) != TCL_OK) { return TCL_ERROR; } - if (rectOvalPtr->fillStipple != None) { + if (fillStipple != None) { Tcl_AppendResult(interp, "clip ", (char *) NULL); - if (Tk_CanvasPsStipple(interp, canvas, rectOvalPtr->fillStipple) + if (Tk_CanvasPsStipple(interp, canvas, fillStipple) != TCL_OK) { return TCL_ERROR; } - if (rectOvalPtr->outlineColor != NULL) { + if (color != NULL) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } } else { @@ -1017,16 +1382,15 @@ RectOvalToPostscript(interp, canvas, itemPtr, prepass) * Now draw the outline, if there is one. */ - if (rectOvalPtr->outlineColor != NULL) { - Tcl_AppendResult(interp, pathCmd, (char *) NULL); - sprintf(string, "%d setlinewidth", rectOvalPtr->width); - Tcl_AppendResult(interp, string, - " 0 setlinejoin 2 setlinecap\n", (char *) NULL); - if (Tk_CanvasPsColor(interp, canvas, rectOvalPtr->outlineColor) - != TCL_OK) { + if (color != NULL) { + Tcl_AppendResult(interp, pathCmd, "0 setlinejoin 2 setlinecap\n", + (char *) NULL); + if (Tk_CanvasPsOutline(canvas, itemPtr, + &(rectOvalPtr->outline))!= TCL_OK) { return TCL_ERROR; } - Tcl_AppendResult(interp, "stroke\n", (char *) NULL); } return TCL_OK; } + + diff --git a/tk/generic/tkScale.c b/tk/generic/tkScale.c index ea579f587d3..fb88fc3da7f 100644 --- a/tk/generic/tkScale.c +++ b/tk/generic/tkScale.c @@ -12,7 +12,8 @@ * permission. * * Copyright (c) 1990-1994 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-2000 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -26,96 +27,133 @@ #include "tclMath.h" #include "tkScale.h" -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_SCALE_ACTIVE_BG_COLOR, Tk_Offset(TkScale, activeBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", - DEF_SCALE_ACTIVE_BG_MONO, Tk_Offset(TkScale, activeBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_SCALE_BG_COLOR, Tk_Offset(TkScale, bgBorder), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - DEF_SCALE_BG_MONO, Tk_Offset(TkScale, bgBorder), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_DOUBLE, "-bigincrement", "bigIncrement", "BigIncrement", - DEF_SCALE_BIG_INCREMENT, Tk_Offset(TkScale, bigIncrement), 0}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_SCALE_BORDER_WIDTH, Tk_Offset(TkScale, borderWidth), 0}, - {TK_CONFIG_STRING, "-command", "command", "Command", - DEF_SCALE_COMMAND, Tk_Offset(TkScale, command), TK_CONFIG_NULL_OK}, - {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", - DEF_SCALE_CURSOR, Tk_Offset(TkScale, cursor), TK_CONFIG_NULL_OK}, - {TK_CONFIG_INT, "-digits", "digits", "Digits", - DEF_SCALE_DIGITS, Tk_Offset(TkScale, digits), 0}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_FONT, "-font", "font", "Font", - DEF_SCALE_FONT, Tk_Offset(TkScale, tkfont), - 0}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_SCALE_FG_COLOR, Tk_Offset(TkScale, textColorPtr), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_SCALE_FG_MONO, Tk_Offset(TkScale, textColorPtr), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_DOUBLE, "-from", "from", "From", - DEF_SCALE_FROM, Tk_Offset(TkScale, fromValue), 0}, - {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", - "HighlightBackground", DEF_SCALE_HIGHLIGHT_BG, - Tk_Offset(TkScale, highlightBgColorPtr), 0}, - {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", - DEF_SCALE_HIGHLIGHT, Tk_Offset(TkScale, highlightColorPtr), 0}, - {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", - DEF_SCALE_HIGHLIGHT_WIDTH, Tk_Offset(TkScale, highlightWidth), 0}, - {TK_CONFIG_STRING, "-label", "label", "Label", - DEF_SCALE_LABEL, Tk_Offset(TkScale, label), TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-length", "length", "Length", - DEF_SCALE_LENGTH, Tk_Offset(TkScale, length), 0}, - {TK_CONFIG_UID, "-orient", "orient", "Orient", - DEF_SCALE_ORIENT, Tk_Offset(TkScale, orientUid), 0}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - DEF_SCALE_RELIEF, Tk_Offset(TkScale, relief), 0}, - {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay", - DEF_SCALE_REPEAT_DELAY, Tk_Offset(TkScale, repeatDelay), 0}, - {TK_CONFIG_INT, "-repeatinterval", "repeatInterval", "RepeatInterval", - DEF_SCALE_REPEAT_INTERVAL, Tk_Offset(TkScale, repeatInterval), 0}, - {TK_CONFIG_DOUBLE, "-resolution", "resolution", "Resolution", - DEF_SCALE_RESOLUTION, Tk_Offset(TkScale, resolution), 0}, - {TK_CONFIG_BOOLEAN, "-showvalue", "showValue", "ShowValue", - DEF_SCALE_SHOW_VALUE, Tk_Offset(TkScale, showValue), 0}, - {TK_CONFIG_PIXELS, "-sliderlength", "sliderLength", "SliderLength", - DEF_SCALE_SLIDER_LENGTH, Tk_Offset(TkScale, sliderLength), 0}, - {TK_CONFIG_RELIEF, "-sliderrelief", "sliderRelief", "SliderRelief", - DEF_SCALE_SLIDER_RELIEF, Tk_Offset(TkScale, sliderRelief), - TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_UID, "-state", "state", "State", - DEF_SCALE_STATE, Tk_Offset(TkScale, state), 0}, - {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_SCALE_TAKE_FOCUS, Tk_Offset(TkScale, takeFocus), - TK_CONFIG_NULL_OK}, - {TK_CONFIG_DOUBLE, "-tickinterval", "tickInterval", "TickInterval", - DEF_SCALE_TICK_INTERVAL, Tk_Offset(TkScale, tickInterval), 0}, - {TK_CONFIG_DOUBLE, "-to", "to", "To", - DEF_SCALE_TO, Tk_Offset(TkScale, toValue), 0}, - {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", - DEF_SCALE_TROUGH_COLOR, Tk_Offset(TkScale, troughColorPtr), - TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background", - DEF_SCALE_TROUGH_MONO, Tk_Offset(TkScale, troughColorPtr), - TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_STRING, "-variable", "variable", "Variable", - DEF_SCALE_VARIABLE, Tk_Offset(TkScale, varName), TK_CONFIG_NULL_OK}, - {TK_CONFIG_PIXELS, "-width", "width", "Width", - DEF_SCALE_WIDTH, Tk_Offset(TkScale, width), 0}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} +/* + * The following table defines the legal values for the -orient option. + * It is used together with the "enum orient" declaration in tkScale.h. + */ + +static char *orientStrings[] = { + "horizontal", "vertical", (char *) NULL +}; + +/* + * The following table defines the legal values for the -state option. + * It is used together with the "enum state" declaration in tkScale.h. + */ + +static char *stateStrings[] = { + "active", "disabled", "normal", (char *) NULL +}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground", + DEF_SCALE_ACTIVE_BG_COLOR, -1, Tk_Offset(TkScale, activeBorder), + 0, (ClientData) DEF_SCALE_ACTIVE_BG_MONO, 0}, + {TK_OPTION_BORDER, "-background", "background", "Background", + DEF_SCALE_BG_COLOR, -1, Tk_Offset(TkScale, bgBorder), + 0, (ClientData) DEF_SCALE_BG_MONO, 0}, + {TK_OPTION_DOUBLE, "-bigincrement", "bigIncrement", "BigIncrement", + DEF_SCALE_BIG_INCREMENT, -1, Tk_Offset(TkScale, bigIncrement), + 0, 0, 0}, + {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + DEF_SCALE_BORDER_WIDTH, -1, Tk_Offset(TkScale, borderWidth), + 0, 0, 0}, + {TK_OPTION_STRING, "-command", "command", "Command", + DEF_SCALE_COMMAND, -1, Tk_Offset(TkScale, command), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + DEF_SCALE_CURSOR, -1, Tk_Offset(TkScale, cursor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_INT, "-digits", "digits", "Digits", + DEF_SCALE_DIGITS, -1, Tk_Offset(TkScale, digits), + 0, 0, 0}, + {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + DEF_SCALE_FONT, -1, Tk_Offset(TkScale, tkfont), 0, 0, 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + DEF_SCALE_FG_COLOR, -1, Tk_Offset(TkScale, textColorPtr), 0, + (ClientData) DEF_SCALE_FG_MONO, 0}, + {TK_OPTION_DOUBLE, "-from", "from", "From", DEF_SCALE_FROM, -1, + Tk_Offset(TkScale, fromValue), 0, 0, 0}, + {TK_OPTION_BORDER, "-highlightbackground", "highlightBackground", + "HighlightBackground", DEF_SCALE_HIGHLIGHT_BG_COLOR, + -1, Tk_Offset(TkScale, highlightBorder), + 0, (ClientData) DEF_SCALE_HIGHLIGHT_BG_MONO, 0}, + {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", + DEF_SCALE_HIGHLIGHT, -1, Tk_Offset(TkScale, highlightColorPtr), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", + "HighlightThickness", DEF_SCALE_HIGHLIGHT_WIDTH, -1, + Tk_Offset(TkScale, highlightWidth), 0, 0, 0}, + {TK_OPTION_STRING, "-label", "label", "Label", + DEF_SCALE_LABEL, -1, Tk_Offset(TkScale, label), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-length", "length", "Length", + DEF_SCALE_LENGTH, -1, Tk_Offset(TkScale, length), 0, 0, 0}, + {TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient", + DEF_SCALE_ORIENT, -1, Tk_Offset(TkScale, orient), + 0, (ClientData) orientStrings, 0}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + DEF_SCALE_RELIEF, -1, Tk_Offset(TkScale, relief), 0, 0, 0}, + {TK_OPTION_INT, "-repeatdelay", "repeatDelay", "RepeatDelay", + DEF_SCALE_REPEAT_DELAY, -1, Tk_Offset(TkScale, repeatDelay), + 0, 0, 0}, + {TK_OPTION_INT, "-repeatinterval", "repeatInterval", "RepeatInterval", + DEF_SCALE_REPEAT_INTERVAL, -1, Tk_Offset(TkScale, repeatInterval), + 0, 0, 0}, + {TK_OPTION_DOUBLE, "-resolution", "resolution", "Resolution", + DEF_SCALE_RESOLUTION, -1, Tk_Offset(TkScale, resolution), + 0, 0, 0}, + {TK_OPTION_BOOLEAN, "-showvalue", "showValue", "ShowValue", + DEF_SCALE_SHOW_VALUE, -1, Tk_Offset(TkScale, showValue), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-sliderlength", "sliderLength", "SliderLength", + DEF_SCALE_SLIDER_LENGTH, -1, Tk_Offset(TkScale, sliderLength), + 0, 0, 0}, + {TK_OPTION_RELIEF, "-sliderrelief", "sliderRelief", "SliderRelief", + DEF_SCALE_SLIDER_RELIEF, -1, Tk_Offset(TkScale, sliderRelief), + 0, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", "state", "State", + DEF_SCALE_STATE, -1, Tk_Offset(TkScale, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + DEF_SCALE_TAKE_FOCUS, Tk_Offset(TkScale, takeFocusPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_DOUBLE, "-tickinterval", "tickInterval", "TickInterval", + DEF_SCALE_TICK_INTERVAL, -1, Tk_Offset(TkScale, tickInterval), + 0, 0, 0}, + {TK_OPTION_DOUBLE, "-to", "to", "To", + DEF_SCALE_TO, -1, Tk_Offset(TkScale, toValue), 0, 0, 0}, + {TK_OPTION_COLOR, "-troughcolor", "troughColor", "Background", + DEF_SCALE_TROUGH_COLOR, -1, Tk_Offset(TkScale, troughColorPtr), + 0, (ClientData) DEF_SCALE_TROUGH_MONO, 0}, + {TK_OPTION_STRING, "-variable", "variable", "Variable", + DEF_SCALE_VARIABLE, Tk_Offset(TkScale, varNamePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-width", "width", "Width", + DEF_SCALE_WIDTH, -1, Tk_Offset(TkScale, width), 0, 0, 0}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, 0, 0} +}; + +/* + * The following tables define the scale widget commands and map the + * indexes into the string tables into a single enumerated type used + * to dispatch the scale widget command. + */ + +static char *commandNames[] = { + "cget", "configure", "coords", "get", "identify", "set", (char *) NULL +}; + +enum command { + COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_COORDS, COMMAND_GET, + COMMAND_IDENTIFY, COMMAND_SET }; /* @@ -125,8 +163,8 @@ static Tk_ConfigSpec configSpecs[] = { static void ComputeFormat _ANSI_ARGS_((TkScale *scalePtr)); static void ComputeScaleGeometry _ANSI_ARGS_((TkScale *scalePtr)); static int ConfigureScale _ANSI_ARGS_((Tcl_Interp *interp, - TkScale *scalePtr, int argc, char **argv, - int flags)); + TkScale *scalePtr, int objc, + Tcl_Obj *CONST objv[])); static void DestroyScale _ANSI_ARGS_((char *memPtr)); static void ScaleCmdDeletedProc _ANSI_ARGS_(( ClientData clientData)); @@ -135,10 +173,12 @@ static void ScaleEventProc _ANSI_ARGS_((ClientData clientData, static char * ScaleVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)); -static int ScaleWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); +static int ScaleWidgetObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); static void ScaleWorldChanged _ANSI_ARGS_(( ClientData instanceData)); +static void ScaleSetVariable _ANSI_ARGS_((TkScale *scalePtr)); /* * The structure below defines scale class behavior by means of procedures @@ -155,7 +195,7 @@ static TkClassProcs scaleClass = { /* *-------------------------------------------------------------- * - * Tk_ScaleCmd -- + * Tk_ScaleObjCmd -- * * This procedure is invoked to process the "scale" Tcl * command. See the user documentation for details on what @@ -171,28 +211,48 @@ static TkClassProcs scaleClass = { */ int -Tk_ScaleCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window associated with - * interpreter. */ +Tk_ScaleObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Either NULL or pointer to option table. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument values. */ { - Tk_Window tkwin = (Tk_Window) clientData; register TkScale *scalePtr; - Tk_Window new; + Tk_OptionTable optionTable; + Tk_Window tkwin; + + optionTable = (Tk_OptionTable) clientData; + if (optionTable == NULL) { + Tcl_CmdInfo info; + char *name; + + /* + * We haven't created the option table for this widget class + * yet. Do it now and save the table as the clientData for + * the command, so we'll have access to it in future + * invocations of the command. + */ - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + name = Tcl_GetString(objv[0]); + Tcl_GetCommandInfo(interp, name, &info); + info.objClientData = (ClientData) optionTable; + Tcl_SetCommandInfo(interp, name, &info); + } + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } - new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); - if (new == NULL) { + tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), + Tcl_GetString(objv[1]), (char *) NULL); + if (tkwin == NULL) { return TCL_ERROR; } - scalePtr = TkpCreateScale(new); + + Tk_SetClass(tkwin, "Scale"); + scalePtr = TkpCreateScale(tkwin); /* * Initialize fields that won't be initialized by ConfigureScale, @@ -200,79 +260,80 @@ Tk_ScaleCmd(clientData, interp, argc, argv) * (e.g. resource pointers). */ - scalePtr->tkwin = new; - scalePtr->display = Tk_Display(new); - scalePtr->interp = interp; - scalePtr->widgetCmd = Tcl_CreateCommand(interp, - Tk_PathName(scalePtr->tkwin), ScaleWidgetCmd, + scalePtr->tkwin = tkwin; + scalePtr->display = Tk_Display(tkwin); + scalePtr->interp = interp; + scalePtr->widgetCmd = Tcl_CreateObjCommand(interp, + Tk_PathName(scalePtr->tkwin), ScaleWidgetObjCmd, (ClientData) scalePtr, ScaleCmdDeletedProc); - scalePtr->orientUid = NULL; - scalePtr->vertical = 0; - scalePtr->width = 0; - scalePtr->length = 0; - scalePtr->value = 0; - scalePtr->varName = NULL; - scalePtr->fromValue = 0; - scalePtr->toValue = 0; - scalePtr->tickInterval = 0; - scalePtr->resolution = 1; - scalePtr->bigIncrement = 0.0; - scalePtr->command = NULL; - scalePtr->repeatDelay = 0; - scalePtr->repeatInterval = 0; - scalePtr->label = NULL; - scalePtr->labelLength = 0; - scalePtr->state = tkNormalUid; - scalePtr->borderWidth = 0; - scalePtr->bgBorder = NULL; - scalePtr->activeBorder = NULL; - scalePtr->sliderRelief = TK_RELIEF_RAISED; - scalePtr->troughColorPtr = NULL; - scalePtr->troughGC = None; - scalePtr->copyGC = None; - scalePtr->tkfont = NULL; - scalePtr->textColorPtr = NULL; - scalePtr->textGC = None; - scalePtr->relief = TK_RELIEF_FLAT; - scalePtr->highlightWidth = 0; - scalePtr->highlightBgColorPtr = NULL; - scalePtr->highlightColorPtr = NULL; - scalePtr->inset = 0; - scalePtr->sliderLength = 0; - scalePtr->showValue = 0; - scalePtr->horizLabelY = 0; - scalePtr->horizValueY = 0; - scalePtr->horizTroughY = 0; - scalePtr->horizTickY = 0; - scalePtr->vertTickRightX = 0; - scalePtr->vertValueRightX = 0; - scalePtr->vertTroughX = 0; - scalePtr->vertLabelX = 0; - scalePtr->cursor = None; - scalePtr->takeFocus = NULL; - scalePtr->flags = NEVER_SET; - - Tk_SetClass(scalePtr->tkwin, "Scale"); + scalePtr->optionTable = optionTable; + scalePtr->orient = ORIENT_VERTICAL; + scalePtr->width = 0; + scalePtr->length = 0; + scalePtr->value = 0.0; + scalePtr->varNamePtr = NULL; + scalePtr->fromValue = 0.0; + scalePtr->toValue = 0.0; + scalePtr->tickInterval = 0.0; + scalePtr->resolution = 1.0; + scalePtr->digits = 0; + scalePtr->bigIncrement = 0.0; + scalePtr->command = NULL; + scalePtr->repeatDelay = 0; + scalePtr->repeatInterval = 0; + scalePtr->label = NULL; + scalePtr->labelLength = 0; + scalePtr->state = STATE_NORMAL; + scalePtr->borderWidth = 0; + scalePtr->bgBorder = NULL; + scalePtr->activeBorder = NULL; + scalePtr->sliderRelief = TK_RELIEF_RAISED; + scalePtr->troughColorPtr = NULL; + scalePtr->troughGC = None; + scalePtr->copyGC = None; + scalePtr->tkfont = NULL; + scalePtr->textColorPtr = NULL; + scalePtr->textGC = None; + scalePtr->relief = TK_RELIEF_FLAT; + scalePtr->highlightWidth = 0; + scalePtr->highlightBorder = NULL; + scalePtr->highlightColorPtr = NULL; + scalePtr->inset = 0; + scalePtr->sliderLength = 0; + scalePtr->showValue = 0; + scalePtr->horizLabelY = 0; + scalePtr->horizValueY = 0; + scalePtr->horizTroughY = 0; + scalePtr->horizTickY = 0; + scalePtr->vertTickRightX = 0; + scalePtr->vertValueRightX = 0; + scalePtr->vertTroughX = 0; + scalePtr->vertLabelX = 0; + scalePtr->fontHeight = 0; + scalePtr->cursor = None; + scalePtr->takeFocusPtr = NULL; + scalePtr->flags = NEVER_SET; + TkSetClassProcs(scalePtr->tkwin, &scaleClass, (ClientData) scalePtr); Tk_CreateEventHandler(scalePtr->tkwin, ExposureMask|StructureNotifyMask|FocusChangeMask, ScaleEventProc, (ClientData) scalePtr); - if (ConfigureScale(interp, scalePtr, argc-2, argv+2, 0) != TCL_OK) { - goto error; + + if ((Tk_InitOptions(interp, (char *) scalePtr, optionTable, tkwin) + != TCL_OK) || + (ConfigureScale(interp, scalePtr, objc - 2, objv + 2) != TCL_OK)) { + Tk_DestroyWindow(scalePtr->tkwin); + return TCL_ERROR; } - interp->result = Tk_PathName(scalePtr->tkwin); + Tcl_SetResult(interp, Tk_PathName(scalePtr->tkwin), TCL_STATIC); return TCL_OK; - - error: - Tk_DestroyWindow(scalePtr->tkwin); - return TCL_ERROR; } /* *-------------------------------------------------------------- * - * ScaleWidgetCmd -- + * ScaleWidgetObjCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a widget managed by this module. @@ -288,131 +349,152 @@ Tk_ScaleCmd(clientData, interp, argc, argv) */ static int -ScaleWidgetCmd(clientData, interp, argc, argv) +ScaleWidgetObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about scale * widget. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument strings. */ { - register TkScale *scalePtr = (TkScale *) clientData; - int result = TCL_OK; - size_t length; - int c; + TkScale *scalePtr = (TkScale *) clientData; + Tcl_Obj *objPtr; + int index, result; - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } + result = Tcl_GetIndexFromObj(interp, objv[1], commandNames, + "option", 0, &index); + if (result != TCL_OK) { + return result; + } Tcl_Preserve((ClientData) scalePtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, scalePtr->tkwin, configSpecs, - (char *) scalePtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 3)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, scalePtr->tkwin, configSpecs, - (char *) scalePtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, scalePtr->tkwin, configSpecs, - (char *) scalePtr, argv[2], 0); - } else { - result = ConfigureScale(interp, scalePtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0) - && (length >= 3)) { - int x, y ; - double value; - - if ((argc != 2) && (argc != 3)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " coords ?value?\"", (char *) NULL); - goto error; - } - if (argc == 3) { - if (Tcl_GetDouble(interp, argv[2], &value) != TCL_OK) { + + switch (index) { + case COMMAND_CGET: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "cget option"); goto error; } - } else { - value = scalePtr->value; - } - if (scalePtr->vertical) { - x = scalePtr->vertTroughX + scalePtr->width/2 - + scalePtr->borderWidth; - y = TkpValueToPixel(scalePtr, value); - } else { - x = TkpValueToPixel(scalePtr, value); - y = scalePtr->horizTroughY + scalePtr->width/2 - + scalePtr->borderWidth; + objPtr = Tk_GetOptionValue(interp, (char *) scalePtr, + scalePtr->optionTable, objv[2], scalePtr->tkwin); + if (objPtr == NULL) { + goto error; + } else { + Tcl_SetObjResult(interp, objPtr); + } + break; } - sprintf(interp->result, "%d %d", x, y); - } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { - double value; - int x, y; - - if ((argc != 2) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " get ?x y?\"", (char *) NULL); - goto error; + case COMMAND_CONFIGURE: { + if (objc <= 3) { + objPtr = Tk_GetOptionInfo(interp, (char *) scalePtr, + scalePtr->optionTable, + (objc == 3) ? objv[2] : (Tcl_Obj *) NULL, + scalePtr->tkwin); + if (objPtr == NULL) { + goto error; + } else { + Tcl_SetObjResult(interp, objPtr); + } + } else { + result = ConfigureScale(interp, scalePtr, objc-2, objv+2); + } + break; } - if (argc == 2) { - value = scalePtr->value; - } else { - if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { + case COMMAND_COORDS: { + int x, y ; + double value; + char buf[TCL_INTEGER_SPACE * 2]; + + if ((objc != 2) && (objc != 3)) { + Tcl_WrongNumArgs(interp, 1, objv, "coords ?value?"); goto error; } - value = TkpPixelToValue(scalePtr, x, y); - } - sprintf(interp->result, scalePtr->format, value); - } else if ((c == 'i') && (strncmp(argv[1], "identify", length) == 0)) { - int x, y, thing; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " identify x y\"", (char *) NULL); - goto error; - } - if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) - || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { - goto error; - } - thing = TkpScaleElement(scalePtr, x,y); - switch (thing) { - case TROUGH1: interp->result = "trough1"; break; - case SLIDER: interp->result = "slider"; break; - case TROUGH2: interp->result = "trough2"; break; - } - } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) { - double value; + if (objc == 3) { + if (Tcl_GetDoubleFromObj(interp, objv[2], &value) + != TCL_OK) { + goto error; + } + } else { + value = scalePtr->value; + } + if (scalePtr->orient == ORIENT_VERTICAL) { + x = scalePtr->vertTroughX + scalePtr->width/2 + + scalePtr->borderWidth; + y = TkScaleValueToPixel(scalePtr, value); + } else { + x = TkScaleValueToPixel(scalePtr, value); + y = scalePtr->horizTroughY + scalePtr->width/2 + + scalePtr->borderWidth; + } + sprintf(buf, "%d %d", x, y); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + break; + } + case COMMAND_GET: { + double value; + int x, y; + char buf[TCL_DOUBLE_SPACE]; + + if ((objc != 2) && (objc != 4)) { + Tcl_WrongNumArgs(interp, 1, objv, "get ?x y?"); + goto error; + } + if (objc == 2) { + value = scalePtr->value; + } else { + if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) + || (Tcl_GetIntFromObj(interp, objv[3], &y) + != TCL_OK)) { + goto error; + } + value = TkScalePixelToValue(scalePtr, x, y); + } + sprintf(buf, scalePtr->format, value); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + break; + } + case COMMAND_IDENTIFY: { + int x, y, thing; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, "identify x y"); + goto error; + } + if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) + || (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) { + goto error; + } + thing = TkpScaleElement(scalePtr, x,y); + switch (thing) { + case TROUGH1: + Tcl_SetResult(interp, "trough1", TCL_STATIC); + break; + case SLIDER: + Tcl_SetResult(interp, "slider", TCL_STATIC); + break; + case TROUGH2: + Tcl_SetResult(interp, "trough2", TCL_STATIC); + break; + } + break; + } + case COMMAND_SET: { + double value; - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " set value\"", (char *) NULL); - goto error; - } - if (Tcl_GetDouble(interp, argv[2], &value) != TCL_OK) { - goto error; - } - if (scalePtr->state != tkDisabledUid) { - TkpSetScaleValue(scalePtr, value, 1, 1); - } - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget, configure, coords, get, identify, or set", - (char *) NULL); - goto error; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "set value"); + goto error; + } + if (Tcl_GetDoubleFromObj(interp, objv[2], &value) != TCL_OK) { + goto error; + } + if (scalePtr->state != STATE_DISABLED) { + TkScaleSetValue(scalePtr, value, 1, 1); + } + break; + } } Tcl_Release((ClientData) scalePtr); return result; @@ -446,14 +528,21 @@ DestroyScale(memPtr) { register TkScale *scalePtr = (TkScale *) memPtr; + scalePtr->flags |= SCALE_DELETED; + + Tcl_DeleteCommandFromToken(scalePtr->interp, scalePtr->widgetCmd); + if (scalePtr->flags & REDRAW_PENDING) { + Tcl_CancelIdleCall(TkpDisplayScale, (ClientData) scalePtr); + } + /* * Free up all the stuff that requires special handling, then * let Tk_FreeOptions handle all the standard option-related * stuff. */ - if (scalePtr->varName != NULL) { - Tcl_UntraceVar(scalePtr->interp, scalePtr->varName, + if (scalePtr->varNamePtr != NULL) { + Tcl_UntraceVar(scalePtr->interp, Tcl_GetString(scalePtr->varNamePtr), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ScaleVarProc, (ClientData) scalePtr); } @@ -466,7 +555,9 @@ DestroyScale(memPtr) if (scalePtr->textGC != None) { Tk_FreeGC(scalePtr->display, scalePtr->textGC); } - Tk_FreeOptions(configSpecs, (char *) scalePtr, scalePtr->display, 0); + Tk_FreeConfigOptions((char *) scalePtr, scalePtr->optionTable, + scalePtr->tkwin); + scalePtr->tkwin = NULL; TkpDestroyScale(scalePtr); } @@ -481,7 +572,7 @@ DestroyScale(memPtr) * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as colors, border width, @@ -492,118 +583,144 @@ DestroyScale(memPtr) */ static int -ConfigureScale(interp, scalePtr, argc, argv, flags) +ConfigureScale(interp, scalePtr, objc, objv) Tcl_Interp *interp; /* Used for error reporting. */ register TkScale *scalePtr; /* Information about widget; may or may * not already have values for some fields. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to Tk_ConfigureWidget. */ + int objc; /* Number of valid entries in objv. */ + Tcl_Obj *CONST objv[]; /* Argument values. */ { - size_t length; + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int error; + double oldValue = scalePtr->value; /* * Eliminate any existing trace on a variable monitored by the scale. */ - if (scalePtr->varName != NULL) { - Tcl_UntraceVar(interp, scalePtr->varName, + if (scalePtr->varNamePtr != NULL) { + Tcl_UntraceVar(interp, Tcl_GetString(scalePtr->varNamePtr), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ScaleVarProc, (ClientData) scalePtr); } - if (Tk_ConfigureWidget(interp, scalePtr->tkwin, configSpecs, - argc, argv, (char *) scalePtr, flags) != TCL_OK) { - return TCL_ERROR; - } + for (error = 0; error <= 1; error++) { + if (!error) { + /* + * First pass: set options to new values. + */ - /* - * If the scale is tied to the value of a variable, then set up - * a trace on the variable's value and set the scale's value from - * the value of the variable, if it exists. - */ + if (Tk_SetOptions(interp, (char *) scalePtr, + scalePtr->optionTable, objc, objv, + scalePtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) { + continue; + } + } else { + /* + * Second pass: restore options to old values. + */ - if (scalePtr->varName != NULL) { - char *stringValue, *end; - double value; + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + /* + * If the scale is tied to the value of a variable, then set + * the scale's value from the value of the variable, if it exists + * and it holds a valid double value. + */ - stringValue = Tcl_GetVar(interp, scalePtr->varName, TCL_GLOBAL_ONLY); - if (stringValue != NULL) { - value = strtod(stringValue, &end); - if ((end != stringValue) && (*end == 0)) { + if (scalePtr->varNamePtr != NULL) { + double value; + Tcl_Obj *valuePtr; + + valuePtr = Tcl_ObjGetVar2(interp, scalePtr->varNamePtr, NULL, + TCL_GLOBAL_ONLY); + if ((valuePtr != NULL) && + (Tcl_GetDoubleFromObj(NULL, valuePtr, &value) == TCL_OK)) { scalePtr->value = TkRoundToResolution(scalePtr, value); } } - Tcl_TraceVar(interp, scalePtr->varName, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - ScaleVarProc, (ClientData) scalePtr); - } - /* - * Several options need special processing, such as parsing the - * orientation and creating GCs. - */ + /* + * Several options need special processing, such as parsing the + * orientation and creating GCs. + */ - length = strlen(scalePtr->orientUid); - if (strncmp(scalePtr->orientUid, "vertical", length) == 0) { - scalePtr->vertical = 1; - } else if (strncmp(scalePtr->orientUid, "horizontal", length) == 0) { - scalePtr->vertical = 0; - } else { - Tcl_AppendResult(interp, "bad orientation \"", scalePtr->orientUid, - "\": must be vertical or horizontal", (char *) NULL); - return TCL_ERROR; - } + scalePtr->fromValue = TkRoundToResolution(scalePtr, + scalePtr->fromValue); + scalePtr->toValue = TkRoundToResolution(scalePtr, scalePtr->toValue); + scalePtr->tickInterval = TkRoundToResolution(scalePtr, + scalePtr->tickInterval); - scalePtr->fromValue = TkRoundToResolution(scalePtr, scalePtr->fromValue); - scalePtr->toValue = TkRoundToResolution(scalePtr, scalePtr->toValue); - scalePtr->tickInterval = TkRoundToResolution(scalePtr, - scalePtr->tickInterval); + /* + * Make sure that the tick interval has the right sign so that + * addition moves from fromValue to toValue. + */ - /* - * Make sure that the tick interval has the right sign so that - * addition moves from fromValue to toValue. - */ + if ((scalePtr->tickInterval < 0) + ^ ((scalePtr->toValue - scalePtr->fromValue) < 0)) { + scalePtr->tickInterval = -scalePtr->tickInterval; + } + + ComputeFormat(scalePtr); - if ((scalePtr->tickInterval < 0) - ^ ((scalePtr->toValue - scalePtr->fromValue) < 0)) { - scalePtr->tickInterval = -scalePtr->tickInterval; + scalePtr->labelLength = scalePtr->label ? strlen(scalePtr->label) : 0; + + Tk_SetBackgroundFromBorder(scalePtr->tkwin, scalePtr->bgBorder); + + if (scalePtr->highlightWidth < 0) { + scalePtr->highlightWidth = 0; + } + scalePtr->inset = scalePtr->highlightWidth + scalePtr->borderWidth; + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); } /* * Set the scale value to itself; all this does is to make sure * that the scale's value is within the new acceptable range for - * the scale and reflect the value in the associated variable, - * if any. + * the scale. We don't set the var here because we need to make + * special checks for possibly changed varNamePtr. */ - ComputeFormat(scalePtr); - TkpSetScaleValue(scalePtr, scalePtr->value, 1, 0); - - if (scalePtr->label != NULL) { - scalePtr->labelLength = strlen(scalePtr->label); - } else { - scalePtr->labelLength = 0; - } + TkScaleSetValue(scalePtr, scalePtr->value, 0, 1); - if ((scalePtr->state != tkNormalUid) - && (scalePtr->state != tkDisabledUid) - && (scalePtr->state != tkActiveUid)) { - Tcl_AppendResult(interp, "bad state value \"", scalePtr->state, - "\": must be normal, active, or disabled", (char *) NULL); - scalePtr->state = tkNormalUid; - return TCL_ERROR; - } + /* + * Reestablish the variable trace, if it is needed. + */ - Tk_SetBackgroundFromBorder(scalePtr->tkwin, scalePtr->bgBorder); + if (scalePtr->varNamePtr != NULL) { + Tcl_Obj *valuePtr; - if (scalePtr->highlightWidth < 0) { - scalePtr->highlightWidth = 0; + /* + * Set the associated variable only when the new value differs + * from the current value, or the variable doesn't yet exist + */ + valuePtr = Tcl_ObjGetVar2(interp, scalePtr->varNamePtr, NULL, + TCL_GLOBAL_ONLY); + if ((valuePtr == NULL) || (scalePtr->value != oldValue) + || (Tcl_GetDoubleFromObj(NULL, valuePtr, &oldValue) != TCL_OK) + || (scalePtr->value != oldValue)) { + ScaleSetVariable(scalePtr); + } + Tcl_TraceVar(interp, Tcl_GetString(scalePtr->varNamePtr), + TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, + ScaleVarProc, (ClientData) scalePtr); } - scalePtr->inset = scalePtr->highlightWidth + scalePtr->borderWidth; ScaleWorldChanged((ClientData) scalePtr); - return TCL_OK; + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + return TCL_OK; + } } /* @@ -635,8 +752,7 @@ ScaleWorldChanged(instanceData) scalePtr = (TkScale *) instanceData; gcValues.foreground = scalePtr->troughColorPtr->pixel; - gc = Tk_GetGCColor(scalePtr->tkwin, GCForeground, &gcValues, - scalePtr->troughColorPtr, NULL); + gc = Tk_GetGC(scalePtr->tkwin, GCForeground, &gcValues); if (scalePtr->troughGC != None) { Tk_FreeGC(scalePtr->display, scalePtr->troughGC); } @@ -644,8 +760,7 @@ ScaleWorldChanged(instanceData) gcValues.font = Tk_FontId(scalePtr->tkfont); gcValues.foreground = scalePtr->textColorPtr->pixel; - gc = Tk_GetGCColor(scalePtr->tkwin, GCForeground | GCFont, &gcValues, - scalePtr->textColorPtr, NULL); + gc = Tk_GetGC(scalePtr->tkwin, GCForeground | GCFont, &gcValues); if (scalePtr->textGC != None) { Tk_FreeGC(scalePtr->display, scalePtr->textGC); } @@ -804,24 +919,26 @@ ComputeScaleGeometry(scalePtr) int tmp, valuePixels, x, y, extraSpace; Tk_FontMetrics fm; + Tk_GetFontMetrics(scalePtr->tkfont, &fm); + scalePtr->fontHeight = fm.linespace + SPACING; + /* * Horizontal scales are simpler than vertical ones because * all sizes are the same (the height of a line of text); * handle them first and then quit. */ - Tk_GetFontMetrics(scalePtr->tkfont, &fm); - if (!scalePtr->vertical) { + if (scalePtr->orient == ORIENT_HORIZONTAL) { y = scalePtr->inset; extraSpace = 0; if (scalePtr->labelLength != 0) { scalePtr->horizLabelY = y + SPACING; - y += fm.linespace + SPACING; + y += scalePtr->fontHeight; extraSpace = SPACING; } if (scalePtr->showValue) { scalePtr->horizValueY = y + SPACING; - y += fm.linespace + SPACING; + y += scalePtr->fontHeight; extraSpace = SPACING; } else { scalePtr->horizValueY = y; @@ -831,7 +948,7 @@ ComputeScaleGeometry(scalePtr) y += scalePtr->width + 2*scalePtr->borderWidth; if (scalePtr->tickInterval != 0) { scalePtr->horizTickY = y + SPACING; - y += fm.linespace + 2*SPACING; + y += scalePtr->fontHeight + SPACING; } Tk_GeometryRequest(scalePtr->tkwin, scalePtr->length + 2*scalePtr->inset, y + scalePtr->inset); @@ -884,8 +1001,8 @@ ComputeScaleGeometry(scalePtr) } else { scalePtr->vertLabelX = x + fm.ascent/2; x = scalePtr->vertLabelX + fm.ascent/2 - + Tk_TextWidth(scalePtr->tkfont, scalePtr->label, - scalePtr->labelLength); + + Tk_TextWidth(scalePtr->tkfont, scalePtr->label, + scalePtr->labelLength); } Tk_GeometryRequest(scalePtr->tkwin, x + scalePtr->inset, scalePtr->length + 2*scalePtr->inset); @@ -920,14 +1037,7 @@ ScaleEventProc(clientData, eventPtr) if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { TkEventuallyRedrawScale(scalePtr, REDRAW_ALL); } else if (eventPtr->type == DestroyNotify) { - if (scalePtr->tkwin != NULL) { - scalePtr->tkwin = NULL; - Tcl_DeleteCommandFromToken(scalePtr->interp, scalePtr->widgetCmd); - } - if (scalePtr->flags & REDRAW_ALL) { - Tcl_CancelIdleCall(TkpDisplayScale, (ClientData) scalePtr); - } - Tcl_EventuallyFree((ClientData) scalePtr, DestroyScale); + DestroyScale((char *) clientData); } else if (eventPtr->type == ConfigureNotify) { ComputeScaleGeometry(scalePtr); TkEventuallyRedrawScale(scalePtr, REDRAW_ALL); @@ -980,8 +1090,8 @@ ScaleCmdDeletedProc(clientData) * destroys the widget. */ - if (tkwin != NULL) { - scalePtr->tkwin = NULL; + if (!(scalePtr->flags & SCALE_DELETED)) { + scalePtr->flags |= SCALE_DELETED; Tk_DestroyWindow(tkwin); } } @@ -1015,7 +1125,8 @@ TkEventuallyRedrawScale(scalePtr, what) || !Tk_IsMapped(scalePtr->tkwin)) { return; } - if ((scalePtr->flags & REDRAW_ALL) == 0) { + if (!(scalePtr->flags & REDRAW_PENDING)) { + scalePtr->flags |= REDRAW_PENDING; Tcl_DoWhenIdle(TkpDisplayScale, (ClientData) scalePtr); } scalePtr->flags |= what; @@ -1043,20 +1154,21 @@ TkRoundToResolution(scalePtr, value) TkScale *scalePtr; /* Information about scale widget. */ double value; /* Value to round. */ { - double rem, new; + double rem, new, tick; if (scalePtr->resolution <= 0) { return value; } - new = scalePtr->resolution * floor(value/scalePtr->resolution); + tick = floor(value/scalePtr->resolution); + new = scalePtr->resolution * tick; rem = value - new; if (rem < 0) { if (rem <= -scalePtr->resolution/2) { - new -= scalePtr->resolution; + new = (tick - 1.0) * scalePtr->resolution; } } else { if (rem >= scalePtr->resolution/2) { - new += scalePtr->resolution; + new = (tick + 1.0) * scalePtr->resolution; } } return new; @@ -1091,8 +1203,10 @@ ScaleVarProc(clientData, interp, name1, name2, flags) int flags; /* Information about what happened. */ { register TkScale *scalePtr = (TkScale *) clientData; - char *stringValue, *end, *result; + char *resultStr; double value; + Tcl_Obj *valuePtr; + int result; /* * If the variable is unset, then immediately recreate it unless @@ -1101,17 +1215,17 @@ ScaleVarProc(clientData, interp, name1, name2, flags) if (flags & TCL_TRACE_UNSETS) { if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { - Tcl_TraceVar(interp, scalePtr->varName, + Tcl_TraceVar(interp, Tcl_GetString(scalePtr->varNamePtr), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ScaleVarProc, clientData); scalePtr->flags |= NEVER_SET; - TkpSetScaleValue(scalePtr, scalePtr->value, 1, 0); + TkScaleSetValue(scalePtr, scalePtr->value, 1, 0); } return (char *) NULL; } /* - * If we came here because we updated the variable (in TkpSetScaleValue), + * If we came here because we updated the variable (in TkScaleSetValue), * then ignore the trace. Otherwise update the scale with the value * of the variable. */ @@ -1119,27 +1233,216 @@ ScaleVarProc(clientData, interp, name1, name2, flags) if (scalePtr->flags & SETTING_VAR) { return (char *) NULL; } - result = NULL; - stringValue = Tcl_GetVar(interp, scalePtr->varName, TCL_GLOBAL_ONLY); - if (stringValue != NULL) { - value = strtod(stringValue, &end); - if ((end == stringValue) || (*end != 0)) { - result = "can't assign non-numeric value to scale variable"; - } else { - scalePtr->value = TkRoundToResolution(scalePtr, value); - } + resultStr = NULL; + valuePtr = Tcl_ObjGetVar2(interp, scalePtr->varNamePtr, NULL, + TCL_GLOBAL_ONLY); + result = Tcl_GetDoubleFromObj(interp, valuePtr, &value); + if (result != TCL_OK) { + resultStr = "can't assign non-numeric value to scale variable"; + ScaleSetVariable(scalePtr); + } else { + scalePtr->value = TkRoundToResolution(scalePtr, value); /* * This code is a bit tricky because it sets the scale's value before - * calling TkpSetScaleValue. This way, TkpSetScaleValue won't bother + * calling TkScaleSetValue. This way, TkScaleSetValue won't bother * to set the variable again or to invoke the -command. However, it * also won't redisplay the scale, so we have to ask for that * explicitly. */ - TkpSetScaleValue(scalePtr, scalePtr->value, 1, 0); - TkEventuallyRedrawScale(scalePtr, REDRAW_SLIDER); + TkScaleSetValue(scalePtr, scalePtr->value, 1, 0); } + TkEventuallyRedrawScale(scalePtr, REDRAW_SLIDER); - return result; + return resultStr; +} + +/* + *-------------------------------------------------------------- + * + * TkScaleSetValue -- + * + * This procedure changes the value of a scale and invokes + * a Tcl command to reflect the current position of a scale + * + * Results: + * None. + * + * Side effects: + * A Tcl command is invoked, and an additional error-processing + * command may also be invoked. The scale's slider is redrawn. + * + *-------------------------------------------------------------- + */ + +void +TkScaleSetValue(scalePtr, value, setVar, invokeCommand) + register TkScale *scalePtr; /* Info about widget. */ + double value; /* New value for scale. Gets adjusted + * if it's off the scale. */ + int setVar; /* Non-zero means reflect new value through + * to associated variable, if any. */ + int invokeCommand; /* Non-zero means invoked -command option + * to notify of new value, 0 means don't. */ +{ + value = TkRoundToResolution(scalePtr, value); + if ((value < scalePtr->fromValue) + ^ (scalePtr->toValue < scalePtr->fromValue)) { + value = scalePtr->fromValue; + } + if ((value > scalePtr->toValue) + ^ (scalePtr->toValue < scalePtr->fromValue)) { + value = scalePtr->toValue; + } + if (scalePtr->flags & NEVER_SET) { + scalePtr->flags &= ~NEVER_SET; + } else if (scalePtr->value == value) { + return; + } + scalePtr->value = value; + if (invokeCommand) { + scalePtr->flags |= INVOKE_COMMAND; + } + TkEventuallyRedrawScale(scalePtr, REDRAW_SLIDER); + + if (setVar && scalePtr->varNamePtr) { + ScaleSetVariable(scalePtr); + } +} + +/* + *-------------------------------------------------------------- + * + * ScaleSetVariable -- + * + * This procedure sets the variable associated with a scale, if any. + * + * Results: + * None. + * + * Side effects: + * Other write traces on the variable will trigger. + * + *-------------------------------------------------------------- + */ + +static void +ScaleSetVariable(scalePtr) + register TkScale *scalePtr; /* Info about widget. */ +{ + if (scalePtr->varNamePtr != NULL) { + char string[PRINT_CHARS]; + sprintf(string, scalePtr->format, scalePtr->value); + scalePtr->flags |= SETTING_VAR; + Tcl_ObjSetVar2(scalePtr->interp, scalePtr->varNamePtr, NULL, + Tcl_NewStringObj(string, -1), TCL_GLOBAL_ONLY); + scalePtr->flags &= ~SETTING_VAR; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkScalePixelToValue -- + * + * Given a pixel within a scale window, return the scale + * reading corresponding to that pixel. + * + * Results: + * A double-precision scale reading. If the value is outside + * the legal range for the scale then it's rounded to the nearest + * end of the scale. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +double +TkScalePixelToValue(scalePtr, x, y) + register TkScale *scalePtr; /* Information about widget. */ + int x, y; /* Coordinates of point within + * window. */ +{ + double value, pixelRange; + + if (scalePtr->orient == ORIENT_VERTICAL) { + pixelRange = Tk_Height(scalePtr->tkwin) - scalePtr->sliderLength + - 2*scalePtr->inset - 2*scalePtr->borderWidth; + value = y; + } else { + pixelRange = Tk_Width(scalePtr->tkwin) - scalePtr->sliderLength + - 2*scalePtr->inset - 2*scalePtr->borderWidth; + value = x; + } + + if (pixelRange <= 0) { + /* + * Not enough room for the slider to actually slide: just return + * the scale's current value. + */ + + return scalePtr->value; + } + value -= scalePtr->sliderLength/2 + scalePtr->inset + + scalePtr->borderWidth; + value /= pixelRange; + if (value < 0) { + value = 0; + } + if (value > 1) { + value = 1; + } + value = scalePtr->fromValue + + value * (scalePtr->toValue - scalePtr->fromValue); + return TkRoundToResolution(scalePtr, value); +} + +/* + *---------------------------------------------------------------------- + * + * TkScaleValueToPixel -- + * + * Given a reading of the scale, return the x-coordinate or + * y-coordinate corresponding to that reading, depending on + * whether the scale is vertical or horizontal, respectively. + * + * Results: + * An integer value giving the pixel location corresponding + * to reading. The value is restricted to lie within the + * defined range for the scale. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkScaleValueToPixel(scalePtr, value) + register TkScale *scalePtr; /* Information about widget. */ + double value; /* Reading of the widget. */ +{ + int y, pixelRange; + double valueRange; + + valueRange = scalePtr->toValue - scalePtr->fromValue; + pixelRange = ((scalePtr->orient == ORIENT_VERTICAL) + ? Tk_Height(scalePtr->tkwin) : Tk_Width(scalePtr->tkwin)) + - scalePtr->sliderLength - 2*scalePtr->inset - 2*scalePtr->borderWidth; + if (valueRange == 0) { + y = 0; + } else { + y = (int) ((value - scalePtr->fromValue) * pixelRange + / valueRange + 0.5); + if (y < 0) { + y = 0; + } else if (y > pixelRange) { + y = pixelRange; + } + } + y += scalePtr->sliderLength/2 + scalePtr->inset + scalePtr->borderWidth; + return y; } diff --git a/tk/generic/tkScale.h b/tk/generic/tkScale.h index ee676f3a903..8168aa7171f 100644 --- a/tk/generic/tkScale.h +++ b/tk/generic/tkScale.h @@ -5,6 +5,7 @@ * the scale widget. * * Copyright (c) 1996 by Sun Microsystems, Inc. + * Copyright (c) 1999-2000 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -25,6 +26,22 @@ #endif /* + * Legal values for the "orient" field of TkScale records. + */ + +enum orient { + ORIENT_HORIZONTAL, ORIENT_VERTICAL +}; + +/* + * Legal values for the "state" field of TkScale records. + */ + +enum state { + STATE_ACTIVE, STATE_DISABLED, STATE_NORMAL +}; + +/* * A data structure of the following type is kept for each scale * widget managed by this file: */ @@ -39,16 +56,16 @@ typedef struct TkScale { * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with scale. */ Tcl_Command widgetCmd; /* Token for scale's widget command. */ - Tk_Uid orientUid; /* Orientation for window ("vertical" or - * "horizontal"). */ - int vertical; /* Non-zero means vertical orientation, - * zero means horizontal. */ + Tk_OptionTable optionTable; /* Table that defines configuration options + * available for this widget. */ + enum orient orient; /* Orientation for window (vertical or + * horizontal). */ int width; /* Desired narrow dimension of scale, * in pixels. */ int length; /* Desired long dimension of scale, * in pixels. */ double value; /* Current value of scale. */ - char *varName; /* Name of variable (malloc'ed) or NULL. + Tcl_Obj *varNamePtr; /* Name of variable or NULL. * If non-NULL, scale's value tracks * the contents of this variable and * vice versa. */ @@ -56,8 +73,8 @@ typedef struct TkScale { * scale. */ double toValue; /* Value corresponding to right or bottom * of scale. */ - double tickInterval; /* Distance between tick marks; 0 means - * don't display any tick marks. */ + double tickInterval; /* Distance between tick marks; + * 0 means don't display any tick marks. */ double resolution; /* If > 0, all values are rounded to an * even multiple of this value. */ int digits; /* Number of significant digits to print @@ -67,20 +84,19 @@ typedef struct TkScale { char format[10]; /* Sprintf conversion specifier computed from * digits and other information. */ double bigIncrement; /* Amount to use for large increments to - * scale value. (0 means we pick a value). */ + * scale value. (0 means we pick a value). */ char *command; /* Command prefix to use when invoking Tcl * commands because the scale value changed. - * NULL means don't invoke commands. - * Malloc'ed. */ + * NULL means don't invoke commands. */ int repeatDelay; /* How long to wait before auto-repeating * on scrolling actions (in ms). */ int repeatInterval; /* Interval between autorepeats (in ms). */ char *label; /* Label to display above or to right of - * scale; NULL means don't display a - * label. Malloc'ed. */ + * scale; NULL means don't display a label. */ int labelLength; /* Number of non-NULL chars. in label. */ - Tk_Uid state; /* Normal or disabled. Value cannot be - * changed when scale is disabled. */ + enum state state; /* Values are active, normal, or disabled. + * Value of scale cannot be changed when + * disabled. */ /* * Information used when displaying widget: @@ -90,7 +106,8 @@ typedef struct TkScale { Tk_3DBorder bgBorder; /* Used for drawing slider and other * background areas. */ Tk_3DBorder activeBorder; /* For drawing the slider when active. */ - int sliderRelief; /* Is slider to be drawn raised, sunken, etc. */ + int sliderRelief; /* Is slider to be drawn raised, sunken, + * etc. */ XColor *troughColorPtr; /* Color for drawing trough. */ GC troughGC; /* For drawing trough. */ GC copyGC; /* Used for copying from pixmap onto screen. */ @@ -102,9 +119,10 @@ typedef struct TkScale { int highlightWidth; /* Width in pixels of highlight to draw * around widget when it has the focus. * <= 0 means don't draw a highlight. */ - XColor *highlightBgColorPtr; - /* Color for drawing traversal highlight - * area when highlight is off. */ + Tk_3DBorder highlightBorder;/* Value of -highlightbackground option: + * specifies background with which to draw 3-D + * default ring and focus highlight area when + * highlight is off. */ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ int inset; /* Total width of all borders, including * traversal highlight and 3-D border. @@ -114,7 +132,7 @@ typedef struct TkScale { int sliderLength; /* Length of slider, measured in pixels along * long dimension of scale. */ int showValue; /* Non-zero means to display the scale value - * below or to the left of the slider; zero + * below or to the left of the slider; zero * means don't display the value. */ /* @@ -140,10 +158,11 @@ typedef struct TkScale { * Miscellaneous information: */ + int fontHeight; /* Height of scale font. */ Tk_Cursor cursor; /* Current cursor for window, or None. */ - char *takeFocus; /* Value of -takefocus option; not used in + Tcl_Obj *takeFocusPtr; /* Value of -takefocus option; not used in * the C code, but used by keyboard traversal - * scripts. Malloc'ed, but may be NULL. */ + * scripts. May be NULL. */ int flags; /* Various flags; see below for * definitions. */ } TkScale; @@ -156,6 +175,7 @@ typedef struct TkScale { * REDRAW_OTHER - 1 means other stuff besides slider and value * need to be redrawn. * REDRAW_ALL - 1 means the entire widget needs to be redrawn. + * REDRAW_PENDING - 1 means any sort of redraw is pending * ACTIVE - 1 means the widget is active (the mouse is * in its window). * INVOKE_COMMAND - 1 means the scale's command needs to be @@ -171,16 +191,19 @@ typedef struct TkScale { * doesn't appear to have changed). * GOT_FOCUS - 1 means that the focus is currently in * this widget. + * SCALE_DELETED - 1 means the scale widget is being deleted */ -#define REDRAW_SLIDER 1 -#define REDRAW_OTHER 2 -#define REDRAW_ALL 3 -#define ACTIVE 4 -#define INVOKE_COMMAND 0x10 -#define SETTING_VAR 0x20 -#define NEVER_SET 0x40 -#define GOT_FOCUS 0x80 +#define REDRAW_SLIDER (1<<0) +#define REDRAW_OTHER (1<<1) +#define REDRAW_ALL (REDRAW_OTHER|REDRAW_SLIDER) +#define REDRAW_PENDING (1<<2) +#define ACTIVE (1<<3) +#define INVOKE_COMMAND (1<<4) +#define SETTING_VAR (1<<5) +#define NEVER_SET (1<<6) +#define GOT_FOCUS (1<<7) +#define SCALE_DELETED (1<<8) /* * Symbolic values for the active parts of a slider. These are @@ -207,7 +230,7 @@ typedef struct TkScale { #define PRINT_CHARS 150 /* - * Declaration of procedures used in the implementation of the scrollbar + * Declaration of procedures used in the implementation of the scale * widget. */ @@ -218,16 +241,18 @@ EXTERN double TkRoundToResolution _ANSI_ARGS_((TkScale *scalePtr, EXTERN TkScale * TkpCreateScale _ANSI_ARGS_((Tk_Window tkwin)); EXTERN void TkpDestroyScale _ANSI_ARGS_((TkScale *scalePtr)); EXTERN void TkpDisplayScale _ANSI_ARGS_((ClientData clientData)); -EXTERN double TkpPixelToValue _ANSI_ARGS_((TkScale *scalePtr, - int x, int y)); EXTERN int TkpScaleElement _ANSI_ARGS_((TkScale *scalePtr, int x, int y)); -EXTERN void TkpSetScaleValue _ANSI_ARGS_((TkScale *scalePtr, +EXTERN void TkScaleSetValue _ANSI_ARGS_((TkScale *scalePtr, double value, int setVar, int invokeCommand)); -EXTERN int TkpValueToPixel _ANSI_ARGS_((TkScale *scalePtr, +EXTERN double TkScalePixelToValue _ANSI_ARGS_((TkScale *scalePtr, + int x, int y)); +EXTERN int TkScaleValueToPixel _ANSI_ARGS_((TkScale *scalePtr, double value)); # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TKSCALE */ + + diff --git a/tk/generic/tkScrollbar.c b/tk/generic/tkScrollbar.c index b49069a0a8a..d0f07c59000 100644 --- a/tk/generic/tkScrollbar.c +++ b/tk/generic/tkScrollbar.c @@ -20,6 +20,16 @@ #include "default.h" /* + * Custom option for handling "-orient" + */ + +static Tk_CustomOption orientOption = { + (Tk_OptionParseProc *) TkOrientParseProc, + TkOrientPrintProc, + (ClientData) NULL +}; + +/* * Information used for argv parsing. */ @@ -63,8 +73,9 @@ Tk_ConfigSpec tkpScrollbarConfigSpecs[] = { DEF_SCROLLBAR_HIGHLIGHT_WIDTH, Tk_Offset(TkScrollbar, highlightWidth), 0}, {TK_CONFIG_BOOLEAN, "-jump", "jump", "Jump", DEF_SCROLLBAR_JUMP, Tk_Offset(TkScrollbar, jump), 0}, - {TK_CONFIG_UID, "-orient", "orient", "Orient", - DEF_SCROLLBAR_ORIENT, Tk_Offset(TkScrollbar, orientUid), 0}, + {TK_CONFIG_CUSTOM, "-orient", "orient", "Orient", + DEF_SCROLLBAR_ORIENT, Tk_Offset(TkScrollbar, vertical), 0, + &orientOption}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_SCROLLBAR_RELIEF, Tk_Offset(TkScrollbar, relief), 0}, {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay", @@ -156,7 +167,6 @@ Tk_ScrollbarCmd(clientData, interp, argc, argv) scrollPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(scrollPtr->tkwin), ScrollbarWidgetCmd, (ClientData) scrollPtr, ScrollbarCmdDeletedProc); - scrollPtr->orientUid = NULL; scrollPtr->vertical = 0; scrollPtr->width = 0; scrollPtr->command = NULL; @@ -193,7 +203,7 @@ Tk_ScrollbarCmd(clientData, interp, argc, argv) return TCL_ERROR; } - interp->result = Tk_PathName(scrollPtr->tkwin); + Tcl_SetResult(interp, Tk_PathName(scrollPtr->tkwin), TCL_STATIC); return TCL_OK; } @@ -240,9 +250,15 @@ ScrollbarWidgetCmd(clientData, interp, argc, argv) int oldActiveField; if (argc == 2) { switch (scrollPtr->activeField) { - case TOP_ARROW: interp->result = "arrow1"; break; - case SLIDER: interp->result = "slider"; break; - case BOTTOM_ARROW: interp->result = "arrow2"; break; + case TOP_ARROW: + Tcl_SetResult(interp, "arrow1", TCL_STATIC); + break; + case SLIDER: + Tcl_SetResult(interp, "slider", TCL_STATIC); + break; + case BOTTOM_ARROW: + Tcl_SetResult(interp, "arrow2", TCL_STATIC); + break; } goto done; } @@ -292,6 +308,7 @@ ScrollbarWidgetCmd(clientData, interp, argc, argv) } else if ((c == 'd') && (strncmp(argv[1], "delta", length) == 0)) { int xDelta, yDelta, pixels, length; double fraction; + char buf[TCL_DOUBLE_SPACE]; if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", @@ -316,10 +333,12 @@ ScrollbarWidgetCmd(clientData, interp, argc, argv) } else { fraction = ((double) pixels / (double) length); } - sprintf(interp->result, "%g", fraction); + sprintf(buf, "%g", fraction); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if ((c == 'f') && (strncmp(argv[1], "fraction", length) == 0)) { int x, y, pos, length; double fraction; + char buf[TCL_DOUBLE_SPACE]; if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", @@ -349,7 +368,8 @@ ScrollbarWidgetCmd(clientData, interp, argc, argv) } else if (fraction > 1.0) { fraction = 1.0; } - sprintf(interp->result, "%g", fraction); + sprintf(buf, "%g", fraction); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", @@ -363,9 +383,12 @@ ScrollbarWidgetCmd(clientData, interp, argc, argv) Tcl_PrintDouble(interp, scrollPtr->lastFraction, last); Tcl_AppendResult(interp, first, " ", last, (char *) NULL); } else { - sprintf(interp->result, "%d %d %d %d", scrollPtr->totalUnits, + char buf[TCL_INTEGER_SPACE * 4]; + + sprintf(buf, "%d %d %d %d", scrollPtr->totalUnits, scrollPtr->windowUnits, scrollPtr->firstUnit, scrollPtr->lastUnit); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } } else if ((c == 'i') && (strncmp(argv[1], "identify", length) == 0)) { int x, y, thing; @@ -381,11 +404,21 @@ ScrollbarWidgetCmd(clientData, interp, argc, argv) } thing = TkpScrollbarPosition(scrollPtr, x,y); switch (thing) { - case TOP_ARROW: interp->result = "arrow1"; break; - case TOP_GAP: interp->result = "trough1"; break; - case SLIDER: interp->result = "slider"; break; - case BOTTOM_GAP: interp->result = "trough2"; break; - case BOTTOM_ARROW: interp->result = "arrow2"; break; + case TOP_ARROW: + Tcl_SetResult(interp, "arrow1", TCL_STATIC); + break; + case TOP_GAP: + Tcl_SetResult(interp, "trough1", TCL_STATIC); + break; + case SLIDER: + Tcl_SetResult(interp, "slider", TCL_STATIC); + break; + case BOTTOM_GAP: + Tcl_SetResult(interp, "trough2", TCL_STATIC); + break; + case BOTTOM_ARROW: + Tcl_SetResult(interp, "arrow2", TCL_STATIC); + break; } } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) { int totalUnits, windowUnits, firstUnit, lastUnit; @@ -488,7 +521,7 @@ ScrollbarWidgetCmd(clientData, interp, argc, argv) * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as colors, border width, @@ -509,29 +542,16 @@ ConfigureScrollbar(interp, scrollPtr, argc, argv, flags) int flags; /* Flags to pass to * Tk_ConfigureWidget. */ { - size_t length; - if (Tk_ConfigureWidget(interp, scrollPtr->tkwin, tkpScrollbarConfigSpecs, argc, argv, (char *) scrollPtr, flags) != TCL_OK) { return TCL_ERROR; } /* - * A few options need special processing, such as parsing the - * orientation or setting the background from a 3-D border. + * A few options need special processing, such as setting the + * background from a 3-D border. */ - length = strlen(scrollPtr->orientUid); - if (strncmp(scrollPtr->orientUid, "vertical", length) == 0) { - scrollPtr->vertical = 1; - } else if (strncmp(scrollPtr->orientUid, "horizontal", length) == 0) { - scrollPtr->vertical = 0; - } else { - Tcl_AppendResult(interp, "bad orientation \"", scrollPtr->orientUid, - "\": must be vertical or horizontal", (char *) NULL); - return TCL_ERROR; - } - if (scrollPtr->command != NULL) { scrollPtr->commandSize = strlen(scrollPtr->command); } else { @@ -689,3 +709,4 @@ TkScrollbarEventuallyRedraw(scrollPtr) scrollPtr->flags |= REDRAW_PENDING; } } + diff --git a/tk/generic/tkScrollbar.h b/tk/generic/tkScrollbar.h index fea8ea6b093..c6580640434 100644 --- a/tk/generic/tkScrollbar.h +++ b/tk/generic/tkScrollbar.h @@ -39,8 +39,6 @@ typedef struct TkScrollbar { * freed even after tkwin has gone away. */ Tcl_Interp *interp; /* Interpreter associated with scrollbar. */ Tcl_Command widgetCmd; /* Token for scrollbar's widget command. */ - Tk_Uid orientUid; /* Orientation for window ("vertical" or - * "horizontal"). */ int vertical; /* Non-zero means vertical orientation * requested, zero means horizontal. */ int width; /* Desired narrow dimension of scrollbar, @@ -206,3 +204,4 @@ EXTERN int TkpScrollbarPosition _ANSI_ARGS_(( # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TKSCROLLBAR */ + diff --git a/tk/generic/tkSelect.c b/tk/generic/tkSelect.c index f97d5e411fe..45821e1e3b4 100644 --- a/tk/generic/tkSelect.c +++ b/tk/generic/tkSelect.c @@ -6,7 +6,7 @@ * and Tcl commands. * * Copyright (c) 1990-1993 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -26,6 +26,11 @@ typedef struct { Tcl_Interp *interp; /* Interpreter in which to invoke command. */ int cmdLength; /* # of non-NULL bytes in command. */ + int charOffset; /* The offset of the next char to retrieve. */ + int byteOffset; /* The expected byte offset of the next + * chunk. */ + char buffer[TCL_UTF_MAX]; /* A buffer to hold part of a UTF character + * that is split across chunks.*/ char command[4]; /* Command to invoke. Actual space is * allocated as large as necessary. This * must be the last entry in the structure. */ @@ -45,12 +50,16 @@ typedef struct LostCommand { } LostCommand; /* - * Shared variables: + * The structure below is used to keep each thread's pending list + * separate. */ -TkSelInProgress *pendingPtr = NULL; +typedef struct ThreadSpecificData { + TkSelInProgress *pendingPtr; /* Topmost search in progress, or * NULL if none. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; /* * Forward declarations for procedures defined in this file: @@ -199,6 +208,8 @@ Tk_DeleteSelHandler(tkwin, selection, target) TkWindow *winPtr = (TkWindow *) tkwin; register TkSelHandler *selPtr, *prevPtr; register TkSelInProgress *ipPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * Find the selection handler to be deleted, or return if it doesn't @@ -220,7 +231,8 @@ Tk_DeleteSelHandler(tkwin, selection, target) * handler is dead. */ - for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { + for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; + ipPtr = ipPtr->nextPtr) { if (ipPtr->selPtr == selPtr) { ipPtr->selPtr = NULL; } @@ -236,7 +248,12 @@ Tk_DeleteSelHandler(tkwin, selection, target) prevPtr->nextPtr = selPtr->nextPtr; } if (selPtr->proc == HandleTclCommand) { - ckfree((char *) selPtr->clientData); + /* + * Mark the CommandInfo as deleted and free it if we can. + */ + + ((CommandInfo*)selPtr->clientData)->interp = NULL; + Tcl_EventuallyFree(selPtr->clientData, Tcl_Free); } ckfree((char *) selPtr); } @@ -431,7 +448,7 @@ Tk_ClearSelection(tkwin, selection) * Results: * The return value is a standard Tcl return value. * If an error occurs (such as no selection exists) - * then an error message is left in interp->result. + * then an error message is left in the interp's result. * * Side effects: * The standard X11 protocols are used to retrieve the @@ -457,7 +474,7 @@ Tk_ClearSelection(tkwin, selection) * the "portion" arguments in separate calls will contain * successive parts of the selection. Proc should normally * return TCL_OK. If it detects an error then it should return - * TCL_ERROR and leave an error message in interp->result; the + * TCL_ERROR and leave an error message in the interp's result; the * remainder of the selection retrieval will be aborted. * *-------------------------------------------------------------- @@ -480,6 +497,8 @@ Tk_GetSelection(interp, tkwin, selection, target, proc, clientData) TkWindow *winPtr = (TkWindow *) tkwin; TkDisplay *dispPtr = winPtr->dispPtr; TkSelectionInfo *infoPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (dispPtr->multipleAtom == None) { TkSelInit(tkwin); @@ -528,13 +547,13 @@ Tk_GetSelection(interp, tkwin, selection, target, proc, clientData) offset = 0; result = TCL_OK; ip.selPtr = selPtr; - ip.nextPtr = pendingPtr; - pendingPtr = &ip; + ip.nextPtr = tsdPtr->pendingPtr; + tsdPtr->pendingPtr = &ip; while (1) { count = (selPtr->proc)(selPtr->clientData, offset, buffer, TK_SEL_BYTES_AT_ONCE); if ((count < 0) || (ip.selPtr == NULL)) { - pendingPtr = ip.nextPtr; + tsdPtr->pendingPtr = ip.nextPtr; goto cantget; } if (count > TK_SEL_BYTES_AT_ONCE) { @@ -548,7 +567,7 @@ Tk_GetSelection(interp, tkwin, selection, target, proc, clientData) } offset += count; } - pendingPtr = ip.nextPtr; + tsdPtr->pendingPtr = ip.nextPtr; } return result; } @@ -602,9 +621,8 @@ Tk_SelectionCmd(clientData, interp, argc, argv) char **args; if (argc < 2) { - sprintf(interp->result, - "wrong # args: should be \"%.50s option ?arg arg ...?\"", - argv[0]); + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " option ?arg arg ...?\"", (char *) NULL); return TCL_ERROR; } c = argv[1][0]; @@ -785,6 +803,9 @@ Tk_SelectionCmd(clientData, interp, argc, argv) cmdInfoPtr = (CommandInfo *) ckalloc((unsigned) ( sizeof(CommandInfo) - 3 + cmdLength)); cmdInfoPtr->interp = interp; + cmdInfoPtr->charOffset = 0; + cmdInfoPtr->byteOffset = 0; + cmdInfoPtr->buffer[0] = '\0'; cmdInfoPtr->cmdLength = cmdLength; strcpy(cmdInfoPtr->command, args[1]); Tk_CreateSelHandler(tkwin, selection, target, HandleTclCommand, @@ -854,7 +875,7 @@ Tk_SelectionCmd(clientData, interp, argc, argv) if ((infoPtr != NULL) && (infoPtr->owner != winPtr->dispPtr->clipWindow)) { - interp->result = Tk_PathName(infoPtr->owner); + Tcl_SetResult(interp, Tk_PathName(infoPtr->owner), TCL_STATIC); } return TCL_OK; } @@ -878,9 +899,8 @@ Tk_SelectionCmd(clientData, interp, argc, argv) Tk_OwnSelection(tkwin, selection, LostSelection, (ClientData) lostPtr); return TCL_OK; } else { - sprintf(interp->result, - "bad option \"%.50s\": must be clear, get, handle, or own", - argv[1]); + Tcl_AppendResult(interp, "bad option \"", argv[1], + "\": must be clear, get, handle, or own", (char *) NULL); return TCL_ERROR; } } @@ -888,6 +908,60 @@ Tk_SelectionCmd(clientData, interp, argc, argv) /* *---------------------------------------------------------------------- * + * TkSelGetInProgress -- + * + * This procedure returns a pointer to the thread-local + * list of pending searches. + * + * Results: + * The return value is a pointer to the first search in progress, + * or NULL if there are none. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TkSelInProgress * +TkSelGetInProgress _ANSI_ARGS_((void)) +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + return tsdPtr->pendingPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkSelSetInProgress -- + * + * This procedure is used to set the thread-local list of pending + * searches. It is required because the pending list is kept + * in thread local storage. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void +TkSelSetInProgress(pendingPtr) + TkSelInProgress *pendingPtr; +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + tsdPtr->pendingPtr = pendingPtr; +} + +/* + *---------------------------------------------------------------------- + * * TkSelDeadWindow -- * * This procedure is invoked just before a TkWindow is deleted. @@ -909,6 +983,8 @@ TkSelDeadWindow(winPtr) register TkSelHandler *selPtr; register TkSelInProgress *ipPtr; TkSelectionInfo *infoPtr, *prevPtr, *nextPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * While deleting all the handlers, be careful to check whether @@ -919,13 +995,19 @@ TkSelDeadWindow(winPtr) while (winPtr->selHandlerList != NULL) { selPtr = winPtr->selHandlerList; winPtr->selHandlerList = selPtr->nextPtr; - for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { + for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; + ipPtr = ipPtr->nextPtr) { if (ipPtr->selPtr == selPtr) { ipPtr->selPtr = NULL; } } if (selPtr->proc == HandleTclCommand) { - ckfree((char *) selPtr->clientData); + /* + * Mark the CommandInfo as deleted and free it if we can. + */ + + ((CommandInfo*)selPtr->clientData)->interp = NULL; + Tcl_EventuallyFree(selPtr->clientData, Tcl_Free); } ckfree((char *) selPtr); } @@ -1120,21 +1202,42 @@ HandleTclCommand(clientData, offset, buffer, maxBytes) int spaceNeeded, length; #define MAX_STATIC_SIZE 100 char staticSpace[MAX_STATIC_SIZE]; - char *command; - Tcl_Interp *interp; + char *command, *string; + Tcl_Interp *interp = cmdInfoPtr->interp; Tcl_DString oldResult; + Tcl_Obj *objPtr; + int extraBytes, charOffset, count, numChars; + char *p; /* - * We must copy the interpreter pointer from CommandInfo because the - * command could delete the handler, freeing the CommandInfo data before we - * are done using it. We must also protect the interpreter from being - * deleted too soo. + * We must also protect the interpreter and the command from being + * deleted too soon. */ - interp = cmdInfoPtr->interp; + Tcl_Preserve(clientData); Tcl_Preserve((ClientData) interp); /* + * Compute the proper byte offset in the case where the last chunk + * split a character. + */ + + if (offset == cmdInfoPtr->byteOffset) { + charOffset = cmdInfoPtr->charOffset; + extraBytes = strlen(cmdInfoPtr->buffer); + if (extraBytes > 0) { + strcpy(buffer, cmdInfoPtr->buffer); + maxBytes -= extraBytes; + buffer += extraBytes; + } + } else { + cmdInfoPtr->byteOffset = 0; + cmdInfoPtr->charOffset = 0; + extraBytes = 0; + charOffset = 0; + } + + /* * First, generate a command by taking the command string * and appending the offset and maximum # of bytes. */ @@ -1145,7 +1248,7 @@ HandleTclCommand(clientData, offset, buffer, maxBytes) } else { command = (char *) ckalloc((unsigned) spaceNeeded); } - sprintf(command, "%s %d %d", cmdInfoPtr->command, offset, maxBytes); + sprintf(command, "%s %d %d", cmdInfoPtr->command, charOffset, maxBytes); /* * Execute the command. Be sure to restore the state of the @@ -1155,14 +1258,41 @@ HandleTclCommand(clientData, offset, buffer, maxBytes) Tcl_DStringInit(&oldResult); Tcl_DStringGetResult(interp, &oldResult); if (TkCopyAndGlobalEval(interp, command) == TCL_OK) { - length = strlen(interp->result); - if (length > maxBytes) { - length = maxBytes; + objPtr = Tcl_GetObjResult(interp); + string = Tcl_GetStringFromObj(objPtr, &length); + count = (length > maxBytes) ? maxBytes : length; + memcpy((VOID *) buffer, (VOID *) string, (size_t) count); + buffer[count] = '\0'; + + /* + * Update the partial character information for the next + * retrieval if the command has not been deleted. + */ + + if (cmdInfoPtr->interp != NULL) { + if (length <= maxBytes) { + cmdInfoPtr->charOffset += Tcl_NumUtfChars(string, -1); + cmdInfoPtr->buffer[0] = '\0'; + } else { + p = string; + string += count; + numChars = 0; + while (p < string) { + p = Tcl_UtfNext(p); + numChars++; + } + cmdInfoPtr->charOffset += numChars; + length = p - string; + if (length > 0) { + strncpy(cmdInfoPtr->buffer, string, (size_t) length); + } + cmdInfoPtr->buffer[length] = '\0'; + } + cmdInfoPtr->byteOffset += count + extraBytes; } - memcpy((VOID *) buffer, (VOID *) interp->result, (size_t) length); - buffer[length] = '\0'; + count += extraBytes; } else { - length = -1; + count = -1; } Tcl_DStringResult(interp, &oldResult); @@ -1170,8 +1300,10 @@ HandleTclCommand(clientData, offset, buffer, maxBytes) ckfree(command); } + + Tcl_Release(clientData); Tcl_Release((ClientData) interp); - return length; + return count; } /* @@ -1299,11 +1431,10 @@ TkSelDefaultSelection(infoPtr, target, buffer, maxBytes, typePtr) static void LostSelection(clientData) - ClientData clientData; /* Pointer to CommandInfo structure. */ + ClientData clientData; /* Pointer to LostCommand structure. */ { LostCommand *lostPtr = (LostCommand *) clientData; - char *oldResultString; - Tcl_FreeProc *oldFreeProc; + Tcl_Obj *objPtr; Tcl_Interp *interp; interp = lostPtr->interp; @@ -1314,22 +1445,16 @@ LostSelection(clientData) * restore it after executing the command. */ - oldFreeProc = interp->freeProc; - if (oldFreeProc != TCL_STATIC) { - oldResultString = interp->result; - } else { - oldResultString = (char *) ckalloc((unsigned) - (strlen(interp->result) + 1)); - strcpy(oldResultString, interp->result); - oldFreeProc = TCL_DYNAMIC; - } - interp->freeProc = TCL_STATIC; + objPtr = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(objPtr); + Tcl_ResetResult(interp); + if (TkCopyAndGlobalEval(interp, lostPtr->command) != TCL_OK) { Tcl_BackgroundError(interp); } - Tcl_FreeResult(interp); - interp->result = oldResultString; - interp->freeProc = oldFreeProc; + + Tcl_SetObjResult(interp, objPtr); + Tcl_DecrRefCount(objPtr); Tcl_Release((ClientData) interp); @@ -1339,3 +1464,4 @@ LostSelection(clientData) ckfree((char *) lostPtr); } + diff --git a/tk/generic/tkSelect.h b/tk/generic/tkSelect.h index 6065aa4b07d..7cce9bbc290 100644 --- a/tk/generic/tkSelect.h +++ b/tk/generic/tkSelect.h @@ -95,6 +95,10 @@ typedef struct TkSelRetrievalInfo { int idleTime; /* Number of seconds that have gone by * without hearing anything from the * selection owner. */ + Tcl_EncodingState encState; /* Holds intermediate state during translations + * of data that cross buffer boundaries. */ + int encFlags; /* Encoding translation state flags. */ + Tcl_DString buf; /* Buffer to hold translation data. */ struct TkSelRetrievalInfo *nextPtr; /* Next in list of all pending * selection retrievals. NULL means @@ -146,14 +150,6 @@ typedef struct TkSelInProgress { } TkSelInProgress; /* - * Declarations for variables shared among the selection-related files: - */ - -extern TkSelInProgress *pendingPtr; - /* Topmost search in progress, or - * NULL if none. */ - -/* * Chunk size for retrieving selection. It's defined both in * words and in bytes; the word size is used to allocate * buffer space that's guaranteed to be word-aligned and that @@ -168,6 +164,11 @@ extern TkSelInProgress *pendingPtr; * but shouldn't be used anywhere else in Tk (or by Tk clients): */ +extern TkSelInProgress * + TkSelGetInProgress _ANSI_ARGS_((void)); +extern void TkSelSetInProgress _ANSI_ARGS_(( + TkSelInProgress *pendingPtr)); + extern void TkSelClearSelection _ANSI_ARGS_((Tk_Window tkwin, XEvent *eventPtr)); extern int TkSelDefaultSelection _ANSI_ARGS_(( @@ -182,3 +183,4 @@ extern void TkSelUpdateClipboard _ANSI_ARGS_((TkWindow *winPtr, #endif #endif /* _TKSELECT */ + diff --git a/tk/generic/tkSend.c b/tk/generic/tkSend.c new file mode 100644 index 00000000000..074ce5a33d7 --- /dev/null +++ b/tk/generic/tkSend.c @@ -0,0 +1,1867 @@ +/* + * tkSend.c -- + * + * This file provides procedures that implement the "send" + * command, allowing commands to be passed from interpreter + * to interpreter. + * + * Copyright (c) 1989-1994 The Regents of the University of California. + * Copyright (c) 1994-1996 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: @(#) tkSend.c 1.64 96/07/20 17:38:32 + */ + +#include "tkPort.h" +#include "tkInt.h" + +/* + * The following structure is used to keep track of the interpreters + * registered by this process. + */ + +typedef struct RegisteredInterp { + char *name; /* Interpreter's name (malloc-ed). */ + Tcl_Interp *interp; /* Interpreter associated with name. NULL + * means that the application was unregistered + * or deleted while a send was in progress + * to it. */ + TkDisplay *dispPtr; /* Display for the application. Needed + * because we may need to unregister the + * interpreter after its main window has + * been deleted. */ + struct RegisteredInterp *nextPtr; + /* Next in list of names associated + * with interps in this process. + * NULL means end of list. */ +} RegisteredInterp; + +static RegisteredInterp *registry = NULL; + /* List of all interpreters + * registered by this process. */ + +/* + * A registry of all interpreters for a display is kept in a + * property "InterpRegistry" on the root window of the display. + * It is organized as a series of zero or more concatenated strings + * (in no particular order), each of the form + * window space name '\0' + * where "window" is the hex id of the comm. window to use to talk + * to an interpreter named "name". + * + * When the registry is being manipulated by an application (e.g. to + * add or remove an entry), it is loaded into memory using a structure + * of the following type: + */ + +typedef struct NameRegistry { + TkDisplay *dispPtr; /* Display from which the registry was + * read. */ + int locked; /* Non-zero means that the display was + * locked when the property was read in. */ + int modified; /* Non-zero means that the property has + * been modified, so it needs to be written + * out when the NameRegistry is closed. */ + unsigned long propLength; /* Length of the property, in bytes. */ + char *property; /* The contents of the property, or NULL + * if none. See format description above; + * this is *not* terminated by the first + * null character. Dynamically allocated. */ + int allocedByX; /* Non-zero means must free property with + * XFree; zero means use ckfree. */ +} NameRegistry; + +/* + * When a result is being awaited from a sent command, one of + * the following structures is present on a list of all outstanding + * sent commands. The information in the structure is used to + * process the result when it arrives. You're probably wondering + * how there could ever be multiple outstanding sent commands. + * This could happen if interpreters invoke each other recursively. + * It's unlikely, but possible. + */ + +typedef struct PendingCommand { + int serial; /* Serial number expected in + * result. */ + TkDisplay *dispPtr; /* Display being used for communication. */ + char *target; /* Name of interpreter command is + * being sent to. */ + Window commWindow; /* Target's communication window. */ + Tcl_Interp *interp; /* Interpreter from which the send + * was invoked. */ + int code; /* Tcl return code for command + * will be stored here. */ + char *result; /* String result for command (malloc'ed), + * or NULL. */ + char *errorInfo; /* Information for "errorInfo" variable, + * or NULL (malloc'ed). */ + char *errorCode; /* Information for "errorCode" variable, + * or NULL (malloc'ed). */ + int gotResponse; /* 1 means a response has been received, + * 0 means the command is still outstanding. */ + struct PendingCommand *nextPtr; + /* Next in list of all outstanding + * commands. NULL means end of + * list. */ +} PendingCommand; + +static PendingCommand *pendingCommands = NULL; + /* List of all commands currently + * being waited for. */ + +/* + * The information below is used for communication between processes + * during "send" commands. Each process keeps a private window, never + * even mapped, with one property, "Comm". When a command is sent to + * an interpreter, the command is appended to the comm property of the + * communication window associated with the interp's process. Similarly, + * when a result is returned from a sent command, it is also appended + * to the comm property. + * + * Each command and each result takes the form of ASCII text. For a + * command, the text consists of a zero character followed by several + * null-terminated ASCII strings. The first string consists of the + * single letter "c". Subsequent strings have the form "option value" + * where the following options are supported: + * + * -r commWindow serial + * + * This option means that a response should be sent to the window + * whose X identifier is "commWindow" (in hex), and the response should + * be identified with the serial number given by "serial" (in decimal). + * If this option isn't specified then the send is asynchronous and + * no response is sent. + * + * -n name + * "Name" gives the name of the application for which the command is + * intended. This option must be present. + * + * -s script + * + * "Script" is the script to be executed. This option must be present. + * + * The options may appear in any order. The -n and -s options must be + * present, but -r may be omitted for asynchronous RPCs. For compatibility + * with future releases that may add new features, there may be additional + * options present; as long as they start with a "-" character, they will + * be ignored. + * + * A result also consists of a zero character followed by several null- + * terminated ASCII strings. The first string consists of the single + * letter "r". Subsequent strings have the form "option value" where + * the following options are supported: + * + * -s serial + * + * Identifies the command for which this is the result. It is the + * same as the "serial" field from the -s option in the command. This + * option must be present. + * + * -c code + * + * "Code" is the completion code for the script, in decimal. If the + * code is omitted it defaults to TCL_OK. + * + * -r result + * + * "Result" is the result string for the script, which may be either + * a result or an error message. If this field is omitted then it + * defaults to an empty string. + * + * -i errorInfo + * + * "ErrorInfo" gives a string with which to initialize the errorInfo + * variable. This option may be omitted; it is ignored unless the + * completion code is TCL_ERROR. + * + * -e errorCode + * + * "ErrorCode" gives a string with with to initialize the errorCode + * variable. This option may be omitted; it is ignored unless the + * completion code is TCL_ERROR. + * + * Options may appear in any order, and only the -s option must be + * present. As with commands, there may be additional options besides + * these; unknown options are ignored. + */ + +/* + * The following variable is the serial number that was used in the + * last "send" command. It is exported only for testing purposes. + */ + +int tkSendSerial = 0; + +/* + * Maximum size property that can be read at one time by + * this module: + */ + +#define MAX_PROP_WORDS 100000 + +/* + * The following variable can be set while debugging to do things like + * skip locking the server. + */ + +static int sendDebug = 0; + +/* + * Forward declarations for procedures defined later in this file: + */ + +static int AppendErrorProc _ANSI_ARGS_((ClientData clientData, + XErrorEvent *errorPtr)); +static void AppendPropCarefully _ANSI_ARGS_((Display *display, + Window window, Atom property, char *value, + int length, PendingCommand *pendingPtr)); +static void DeleteProc _ANSI_ARGS_((ClientData clientData)); +static void RegAddName _ANSI_ARGS_((NameRegistry *regPtr, + char *name, Window commWindow)); +static void RegClose _ANSI_ARGS_((NameRegistry *regPtr)); +static void RegDeleteName _ANSI_ARGS_((NameRegistry *regPtr, + char *name)); +static Window RegFindName _ANSI_ARGS_((NameRegistry *regPtr, + char *name)); +static NameRegistry * RegOpen _ANSI_ARGS_((Tcl_Interp *interp, + TkDisplay *dispPtr, int lock)); +static void SendEventProc _ANSI_ARGS_((ClientData clientData, + XEvent *eventPtr)); +static int SendInit _ANSI_ARGS_((Tcl_Interp *interp, + TkDisplay *dispPtr)); +static Tk_RestrictAction SendRestrictProc _ANSI_ARGS_((ClientData clientData, + XEvent *eventPtr)); +static int ServerSecure _ANSI_ARGS_((TkDisplay *dispPtr)); +static void TimeoutProc _ANSI_ARGS_((ClientData clientData)); +static void UpdateCommWindow _ANSI_ARGS_((TkDisplay *dispPtr)); +static int ValidateName _ANSI_ARGS_((TkDisplay *dispPtr, + char *name, Window commWindow, int oldOK)); + +/* + *---------------------------------------------------------------------- + * + * RegOpen -- + * + * This procedure loads the name registry for a display into + * memory so that it can be manipulated. + * + * Results: + * The return value is a pointer to the loaded registry. + * + * Side effects: + * If "lock" is set then the server will be locked. It is the + * caller's responsibility to call RegClose when finished with + * the registry, so that we can write back the registry if + * neeeded, unlock the server if needed, and free memory. + * + *---------------------------------------------------------------------- + */ + +static NameRegistry * +RegOpen(interp, dispPtr, lock) + Tcl_Interp *interp; /* Interpreter to use for error reporting + * (errors cause a panic so in fact no + * error is ever returned, but the interpreter + * is needed anyway). */ + TkDisplay *dispPtr; /* Display whose name registry is to be + * opened. */ + int lock; /* Non-zero means lock the window server + * when opening the registry, so no-one + * else can use the registry until we + * close it. */ +{ + NameRegistry *regPtr; + int result, actualFormat; + unsigned long bytesAfter; + Atom actualType; + + if (dispPtr->commTkwin == NULL) { + SendInit(interp, dispPtr); + } + + regPtr = (NameRegistry *) ckalloc(sizeof(NameRegistry)); + regPtr->dispPtr = dispPtr; + regPtr->locked = 0; + regPtr->modified = 0; + regPtr->allocedByX = 1; + + if (lock && !sendDebug) { + XGrabServer(dispPtr->display); + regPtr->locked = 1; + } + + /* + * Read the registry property. + */ + + result = XGetWindowProperty(dispPtr->display, + RootWindow(dispPtr->display, 0), + dispPtr->registryProperty, 0, MAX_PROP_WORDS, + False, XA_STRING, &actualType, &actualFormat, + ®Ptr->propLength, &bytesAfter, + (unsigned char **) ®Ptr->property); + + if (actualType == None) { + regPtr->propLength = 0; + regPtr->property = NULL; + } else if ((result != Success) || (actualFormat != 8) + || (actualType != XA_STRING)) { + /* + * The property is improperly formed; delete it. + */ + + if (regPtr->property != NULL) { + XFree(regPtr->property); + regPtr->propLength = 0; + regPtr->property = NULL; + } + XDeleteProperty(dispPtr->display, + RootWindow(dispPtr->display, 0), + dispPtr->registryProperty); + } + + /* + * Xlib placed an extra null byte after the end of the property, just + * to make sure that it is always NULL-terminated. Be sure to include + * this byte in our count if it's needed to ensure null termination + * (note: as of 8/95 I'm no longer sure why this code is needed; seems + * like it shouldn't be). + */ + + if ((regPtr->propLength > 0) + && (regPtr->property[regPtr->propLength-1] != 0)) { + regPtr->propLength++; + } + return regPtr; +} + +/* + *---------------------------------------------------------------------- + * + * RegFindName -- + * + * Given an open name registry, this procedure finds an entry + * with a given name, if there is one, and returns information + * about that entry. + * + * Results: + * The return value is the X identifier for the comm window for + * the application named "name", or None if there is no such + * entry in the registry. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Window +RegFindName(regPtr, name) + NameRegistry *regPtr; /* Pointer to a registry opened with a + * previous call to RegOpen. */ + char *name; /* Name of an application. */ +{ + char *p, *entry; + Window commWindow; + + commWindow = None; + for (p = regPtr->property; (p-regPtr->property) < regPtr->propLength; ) { + entry = p; + while ((*p != 0) && (!isspace(UCHAR(*p)))) { + p++; + } + if ((*p != 0) && (strcmp(name, p+1) == 0)) { + if (sscanf(entry, "%x", (unsigned int *) &commWindow) == 1) { + return commWindow; + } + } + while (*p != 0) { + p++; + } + p++; + } + return None; +} + +/* + *---------------------------------------------------------------------- + * + * RegDeleteName -- + * + * This procedure deletes the entry for a given name from + * an open registry. + * + * Results: + * None. + * + * Side effects: + * If there used to be an entry named "name" in the registry, + * then it is deleted and the registry is marked as modified + * so it will be written back when closed. + * + *---------------------------------------------------------------------- + */ + +static void +RegDeleteName(regPtr, name) + NameRegistry *regPtr; /* Pointer to a registry opened with a + * previous call to RegOpen. */ + char *name; /* Name of an application. */ +{ + char *p, *entry, *entryName; + int count; + + for (p = regPtr->property; (p-regPtr->property) < regPtr->propLength; ) { + entry = p; + while ((*p != 0) && (!isspace(UCHAR(*p)))) { + p++; + } + if (*p != 0) { + p++; + } + entryName = p; + while (*p != 0) { + p++; + } + p++; + if ((strcmp(name, entryName) == 0)) { + /* + * Found the matching entry. Copy everything after it + * down on top of it. + */ + + count = regPtr->propLength - (p - regPtr->property); + if (count > 0) { + memmove((VOID *) entry, (VOID *) p, (size_t) count); + } + regPtr->propLength -= p - entry; + regPtr->modified = 1; + return; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * RegAddName -- + * + * Add a new entry to an open registry. + * + * Results: + * None. + * + * Side effects: + * The open registry is expanded; it is marked as modified so that + * it will be written back when closed. + * + *---------------------------------------------------------------------- + */ + +static void +RegAddName(regPtr, name, commWindow) + NameRegistry *regPtr; /* Pointer to a registry opened with a + * previous call to RegOpen. */ + char *name; /* Name of an application. The caller + * must ensure that this name isn't + * already registered. */ + Window commWindow; /* X identifier for comm. window of + * application. */ +{ + char id[30]; + char *newProp; + int idLength, newBytes; + + sprintf(id, "%x ", (unsigned int) commWindow); + idLength = strlen(id); + newBytes = idLength + strlen(name) + 1; + newProp = (char *) ckalloc((unsigned) (regPtr->propLength + newBytes)); + strcpy(newProp, id); + strcpy(newProp+idLength, name); + if (regPtr->property != NULL) { + memcpy((VOID *) (newProp + newBytes), (VOID *) regPtr->property, + regPtr->propLength); + if (regPtr->allocedByX) { + XFree(regPtr->property); + } else { + ckfree(regPtr->property); + } + } + regPtr->modified = 1; + regPtr->propLength += newBytes; + regPtr->property = newProp; + regPtr->allocedByX = 0; +} + +/* + *---------------------------------------------------------------------- + * + * RegClose -- + * + * This procedure is called to end a series of operations on + * a name registry. + * + * Results: + * None. + * + * Side effects: + * The registry is written back if it has been modified, and the + * X server is unlocked if it was locked. Memory for the + * registry is freed, so the caller should never use regPtr + * again. + * + *---------------------------------------------------------------------- + */ + +static void +RegClose(regPtr) + NameRegistry *regPtr; /* Pointer to a registry opened with a + * previous call to RegOpen. */ +{ + if (regPtr->modified) { + if (!regPtr->locked && !sendDebug) { + panic("The name registry was modified without being locked!"); + } + XChangeProperty(regPtr->dispPtr->display, + RootWindow(regPtr->dispPtr->display, 0), + regPtr->dispPtr->registryProperty, XA_STRING, 8, + PropModeReplace, (unsigned char *) regPtr->property, + (int) regPtr->propLength); + } + + if (regPtr->locked) { + XUngrabServer(regPtr->dispPtr->display); + } + XFlush(regPtr->dispPtr->display); + + if (regPtr->property != NULL) { + if (regPtr->allocedByX) { + XFree(regPtr->property); + } else { + ckfree(regPtr->property); + } + } + ckfree((char *) regPtr); +} + +/* + *---------------------------------------------------------------------- + * + * ValidateName -- + * + * This procedure checks to see if an entry in the registry + * is still valid. + * + * Results: + * The return value is 1 if the given commWindow exists and its + * name is "name". Otherwise 0 is returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +ValidateName(dispPtr, name, commWindow, oldOK) + TkDisplay *dispPtr; /* Display for which to perform the + * validation. */ + char *name; /* The name of an application. */ + Window commWindow; /* X identifier for the application's + * comm. window. */ + int oldOK; /* Non-zero means that we should consider + * an application to be valid even if it + * looks like an old-style (pre-4.0) one; + * 0 means consider these invalid. */ +{ + int result, actualFormat, argc, i; + unsigned long length, bytesAfter; + Atom actualType; + char *property; + Tk_ErrorHandler handler; + char **argv; + + property = NULL; + + /* + * Ignore X errors when reading the property (e.g., the window + * might not exist). If an error occurs, result will be some + * value other than Success. + */ + + handler = Tk_CreateErrorHandler(dispPtr->display, -1, -1, -1, + (Tk_ErrorProc *) NULL, (ClientData) NULL); + result = XGetWindowProperty(dispPtr->display, commWindow, + dispPtr->appNameProperty, 0, MAX_PROP_WORDS, + False, XA_STRING, &actualType, &actualFormat, + &length, &bytesAfter, (unsigned char **) &property); + + if ((result == Success) && (actualType == None)) { + XWindowAttributes atts; + + /* + * The comm. window exists but the property we're looking for + * doesn't exist. This probably means that the application + * comes from an older version of Tk (< 4.0) that didn't set the + * property; if this is the case, then assume for compatibility's + * sake that everything's OK. However, it's also possible that + * some random application has re-used the window id for something + * totally unrelated. Check a few characteristics of the window, + * such as its dimensions and mapped state, to be sure that it + * still "smells" like a commWindow. + */ + + if (!oldOK + || !XGetWindowAttributes(dispPtr->display, commWindow, &atts) + || (atts.width != 1) || (atts.height != 1) + || (atts.map_state != IsUnmapped)) { + result = 0; + } else { + result = 1; + } + } else if ((result == Success) && (actualFormat == 8) + && (actualType == XA_STRING)) { + result = 0; + if (Tcl_SplitList((Tcl_Interp *) NULL, property, &argc, &argv) + == TCL_OK) { + for (i = 0; i < argc; i++) { + if (strcmp(argv[i], name) == 0) { + result = 1; + break; + } + } + ckfree((char *) argv); + } + } else { + result = 0; + } + Tk_DeleteErrorHandler(handler); + if (property != NULL) { + XFree(property); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * ServerSecure -- + * + * Check whether a server is secure enough for us to trust + * Tcl scripts arriving via that server. + * + * Results: + * The return value is 1 if the server is secure, which means + * that host-style authentication is turned on but there are + * no hosts in the enabled list. This means that some other + * form of authorization (presumably more secure, such as xauth) + * is in use. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +ServerSecure(dispPtr) + TkDisplay *dispPtr; /* Display to check. */ +{ +#ifdef TK_NO_SECURITY + return 1; +#else + XHostAddress *addrPtr; + int numHosts, secure; + Bool enabled; + + secure = 0; + addrPtr = XListHosts(dispPtr->display, &numHosts, &enabled); + if (enabled && (numHosts == 0)) { + secure = 1; + } + if (addrPtr != NULL) { + XFree((char *) addrPtr); + } + return secure; +#endif /* TK_NO_SECURITY */ +} + +/* + *-------------------------------------------------------------- + * + * Tk_SetAppName -- + * + * This procedure is called to associate an ASCII name with a Tk + * application. If the application has already been named, the + * name replaces the old one. + * + * Results: + * The return value is the name actually given to the application. + * This will normally be the same as name, but if name was already + * in use for an application then a name of the form "name #2" will + * be chosen, with a high enough number to make the name unique. + * + * Side effects: + * Registration info is saved, thereby allowing the "send" command + * to be used later to invoke commands in the application. In + * addition, the "send" command is created in the application's + * interpreter. The registration will be removed automatically + * if the interpreter is deleted or the "send" command is removed. + * + *-------------------------------------------------------------- + */ + +char * +Tk_SetAppName(tkwin, name) + Tk_Window tkwin; /* Token for any window in the application + * to be named: it is just used to identify + * the application and the display. */ + char *name; /* The name that will be used to + * refer to the interpreter in later + * "send" commands. Must be globally + * unique. */ +{ + RegisteredInterp *riPtr, *riPtr2; + Window w; + TkWindow *winPtr = (TkWindow *) tkwin; + TkDisplay *dispPtr; + NameRegistry *regPtr; + Tcl_Interp *interp; + char *actualName; + Tcl_DString dString; + int offset, i; + +#ifdef __WIN32__ + return name; +#endif /* __WIN32__ */ + + dispPtr = winPtr->dispPtr; + interp = winPtr->mainPtr->interp; + if (dispPtr->commTkwin == NULL) { + SendInit(interp, winPtr->dispPtr); + } + + /* + * See if the application is already registered; if so, remove its + * current name from the registry. + */ + + regPtr = RegOpen(interp, winPtr->dispPtr, 1); + for (riPtr = registry; ; riPtr = riPtr->nextPtr) { + if (riPtr == NULL) { + /* + * This interpreter isn't currently registered; create + * the data structure that will be used to register it locally, + * plus add the "send" command to the interpreter. + */ + + riPtr = (RegisteredInterp *) ckalloc(sizeof(RegisteredInterp)); + riPtr->interp = interp; + riPtr->dispPtr = winPtr->dispPtr; + riPtr->nextPtr = registry; + registry = riPtr; + Tcl_CreateCommand(interp, "send", Tk_SendCmd, (ClientData) riPtr, + DeleteProc); + break; + } + if (riPtr->interp == interp) { + /* + * The interpreter is currently registered; remove it from + * the name registry. + */ + + RegDeleteName(regPtr, riPtr->name); + ckfree(riPtr->name); + break; + } + } + + /* + * Pick a name to use for the application. Use "name" if it's not + * already in use. Otherwise add a suffix such as " #2", trying + * larger and larger numbers until we eventually find one that is + * unique. + */ + + actualName = name; + offset = 0; /* Needed only to avoid "used before + * set" compiler warnings. */ + for (i = 1; ; i++) { + if (i > 1) { + if (i == 2) { + Tcl_DStringInit(&dString); + Tcl_DStringAppend(&dString, name, -1); + Tcl_DStringAppend(&dString, " #", 2); + offset = Tcl_DStringLength(&dString); + Tcl_DStringSetLength(&dString, offset+10); + actualName = Tcl_DStringValue(&dString); + } + sprintf(actualName + offset, "%d", i); + } + w = RegFindName(regPtr, actualName); + if (w == None) { + break; + } + + /* + * The name appears to be in use already, but double-check to + * be sure (perhaps the application died without removing its + * name from the registry?). + */ + + if (w == Tk_WindowId(dispPtr->commTkwin)) { + for (riPtr2 = registry; riPtr2 != NULL; riPtr2 = riPtr2->nextPtr) { + if ((riPtr2->interp != interp) && + (strcmp(riPtr2->name, actualName) == 0)) { + goto nextSuffix; + } + } + RegDeleteName(regPtr, actualName); + break; + } else if (!ValidateName(winPtr->dispPtr, actualName, w, 1)) { + RegDeleteName(regPtr, actualName); + break; + } + nextSuffix: + continue; + } + + /* + * We've now got a name to use. Store it in the name registry and + * in the local entry for this application, plus put it in a property + * on the commWindow. + */ + + RegAddName(regPtr, actualName, Tk_WindowId(dispPtr->commTkwin)); + RegClose(regPtr); + riPtr->name = (char *) ckalloc((unsigned) (strlen(actualName) + 1)); + strcpy(riPtr->name, actualName); + if (actualName != name) { + Tcl_DStringFree(&dString); + } + UpdateCommWindow(dispPtr); + + return riPtr->name; +} + +/* + *-------------------------------------------------------------- + * + * Tk_SendCmd -- + * + * This procedure is invoked to process the "send" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +int +Tk_SendCmd(clientData, interp, argc, argv) + ClientData clientData; /* Information about sender (only + * dispPtr field is used). */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + TkWindow *winPtr; + Window commWindow; + PendingCommand pending; + register RegisteredInterp *riPtr; + char *destName, buffer[30]; + int result, c, async, i, firstArg; + size_t length; + Tk_RestrictProc *prevRestrictProc; + ClientData prevArg; + TkDisplay *dispPtr; + NameRegistry *regPtr; + Tcl_DString request; + Tcl_Interp *localInterp; /* Used when the interpreter to + * send the command to is within + * the same process. */ + + /* + * Process options, if any. + */ + + async = 0; + winPtr = (TkWindow *) Tk_MainWindow(interp); + if (winPtr == NULL) { + return TCL_ERROR; + } + for (i = 1; i < (argc-1); ) { + if (argv[i][0] != '-') { + break; + } + c = argv[i][1]; + length = strlen(argv[i]); + if ((c == 'a') && (strncmp(argv[i], "-async", length) == 0)) { + async = 1; + i++; + } else if ((c == 'd') && (strncmp(argv[i], "-displayof", + length) == 0)) { + winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[i+1], + (Tk_Window) winPtr); + if (winPtr == NULL) { + return TCL_ERROR; + } + i += 2; + } else if (strcmp(argv[i], "--") == 0) { + i++; + break; + } else { + Tcl_AppendResult(interp, "bad option \"", argv[i], + "\": must be -async, -displayof, or --", (char *) NULL); + return TCL_ERROR; + } + } + + if (argc < (i+2)) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ?options? interpName arg ?arg ...?\"", (char *) NULL); + return TCL_ERROR; + } + destName = argv[i]; + firstArg = i+1; + + dispPtr = winPtr->dispPtr; + if (dispPtr->commTkwin == NULL) { + SendInit(interp, winPtr->dispPtr); + } + + /* + * See if the target interpreter is local. If so, execute + * the command directly without going through the X server. + * The only tricky thing is passing the result from the target + * interpreter to the invoking interpreter. Watch out: they + * could be the same! + */ + + for (riPtr = registry; riPtr != NULL; riPtr = riPtr->nextPtr) { + if ((riPtr->dispPtr != dispPtr) + || (strcmp(riPtr->name, destName) != 0)) { + continue; + } + Tcl_Preserve((ClientData) riPtr); + localInterp = riPtr->interp; + Tcl_Preserve((ClientData) localInterp); + if (firstArg == (argc-1)) { + result = Tcl_GlobalEval(localInterp, argv[firstArg]); + } else { + Tcl_DStringInit(&request); + Tcl_DStringAppend(&request, argv[firstArg], -1); + for (i = firstArg+1; i < argc; i++) { + Tcl_DStringAppend(&request, " ", 1); + Tcl_DStringAppend(&request, argv[i], -1); + } + result = Tcl_GlobalEval(localInterp, Tcl_DStringValue(&request)); + Tcl_DStringFree(&request); + } + if (interp != localInterp) { + if (result == TCL_ERROR) { + + /* + * An error occurred, so transfer error information from the + * destination interpreter back to our interpreter. Must clear + * interp's result before calling Tcl_AddErrorInfo, since + * Tcl_AddErrorInfo will store the interp's result in errorInfo + * before appending riPtr's $errorInfo; we've already got + * everything we need in riPtr's $errorInfo. + */ + + Tcl_ResetResult(interp); + Tcl_AddErrorInfo(interp, Tcl_GetVar2(localInterp, + "errorInfo", (char *) NULL, TCL_GLOBAL_ONLY)); + Tcl_SetVar2(interp, "errorCode", (char *) NULL, + Tcl_GetVar2(localInterp, "errorCode", (char *) NULL, + TCL_GLOBAL_ONLY), TCL_GLOBAL_ONLY); + } + if (localInterp->freeProc != TCL_STATIC) { + interp->result = localInterp->result; + interp->freeProc = localInterp->freeProc; + localInterp->freeProc = TCL_STATIC; + } else { + Tcl_SetResult(interp, localInterp->result, TCL_VOLATILE); + } + Tcl_ResetResult(localInterp); + } + Tcl_Release((ClientData) riPtr); + Tcl_Release((ClientData) localInterp); + return result; + } + + /* + * Bind the interpreter name to a communication window. + */ + + regPtr = RegOpen(interp, winPtr->dispPtr, 0); + commWindow = RegFindName(regPtr, destName); + RegClose(regPtr); + if (commWindow == None) { + Tcl_AppendResult(interp, "no application named \"", + destName, "\"", (char *) NULL); + return TCL_ERROR; + } + + /* + * Send the command to the target interpreter by appending it to the + * comm window in the communication window. + */ + + tkSendSerial++; + Tcl_DStringInit(&request); + Tcl_DStringAppend(&request, "\0c\0-n ", 6); + Tcl_DStringAppend(&request, destName, -1); + if (!async) { + sprintf(buffer, "%x %d", + (unsigned int) Tk_WindowId(dispPtr->commTkwin), + tkSendSerial); + Tcl_DStringAppend(&request, "\0-r ", 4); + Tcl_DStringAppend(&request, buffer, -1); + } + Tcl_DStringAppend(&request, "\0-s ", 4); + Tcl_DStringAppend(&request, argv[firstArg], -1); + for (i = firstArg+1; i < argc; i++) { + Tcl_DStringAppend(&request, " ", 1); + Tcl_DStringAppend(&request, argv[i], -1); + } + (void) AppendPropCarefully(dispPtr->display, commWindow, + dispPtr->commProperty, Tcl_DStringValue(&request), + Tcl_DStringLength(&request) + 1, + (async) ? (PendingCommand *) NULL : &pending); + Tcl_DStringFree(&request); + if (async) { + /* + * This is an asynchronous send: return immediately without + * waiting for a response. + */ + + return TCL_OK; + } + + /* + * Register the fact that we're waiting for a command to complete + * (this is needed by SendEventProc and by AppendErrorProc to pass + * back the command's results). Set up a timeout handler so that + * we can check during long sends to make sure that the destination + * application is still alive. + */ + + pending.serial = tkSendSerial; + pending.dispPtr = dispPtr; + pending.target = destName; + pending.commWindow = commWindow; + pending.interp = interp; + pending.result = NULL; + pending.errorInfo = NULL; + pending.errorCode = NULL; + pending.gotResponse = 0; + pending.nextPtr = pendingCommands; + pendingCommands = &pending; + + /* + * Enter a loop processing X events until the result comes + * in or the target is declared to be dead. While waiting + * for a result, look only at send-related events so that + * the send is synchronous with respect to other events in + * the application. + */ + + prevRestrictProc = Tk_RestrictEvents(SendRestrictProc, + (ClientData) NULL, &prevArg); + Tcl_CreateModalTimeout(1000, TimeoutProc, (ClientData) &pending); + while (!pending.gotResponse) { + Tcl_DoOneEvent(TCL_WINDOW_EVENTS); + } + Tcl_DeleteModalTimeout(TimeoutProc, (ClientData) &pending); + (void) Tk_RestrictEvents(prevRestrictProc, prevArg, &prevArg); + + /* + * Unregister the information about the pending command + * and return the result. + */ + + if (pendingCommands == &pending) { + pendingCommands = pending.nextPtr; + } else { + PendingCommand *pcPtr; + + for (pcPtr = pendingCommands; pcPtr != NULL; + pcPtr = pcPtr->nextPtr) { + if (pcPtr->nextPtr == &pending) { + pcPtr->nextPtr = pending.nextPtr; + break; + } + } + } + if (pending.errorInfo != NULL) { + /* + * Special trick: must clear the interp's result before calling + * Tcl_AddErrorInfo, since Tcl_AddErrorInfo will store the interp's + * result in errorInfo before appending pending.errorInfo; we've + * already got everything we need in pending.errorInfo. + */ + + Tcl_ResetResult(interp); + Tcl_AddErrorInfo(interp, pending.errorInfo); + ckfree(pending.errorInfo); + } + if (pending.errorCode != NULL) { + Tcl_SetVar2(interp, "errorCode", (char *) NULL, pending.errorCode, + TCL_GLOBAL_ONLY); + ckfree(pending.errorCode); + } + Tcl_SetResult(interp, pending.result, TCL_DYNAMIC); + return pending.code; +} + +/* + *---------------------------------------------------------------------- + * + * TkGetInterpNames -- + * + * This procedure is invoked to fetch a list of all the + * interpreter names currently registered for the display + * of a particular window. + * + * Results: + * A standard Tcl return value. Interp->result will be set + * to hold a list of all the interpreter names defined for + * tkwin's display. If an error occurs, then TCL_ERROR + * is returned and interp->result will hold an error message. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkGetInterpNames(interp, tkwin) + Tcl_Interp *interp; /* Interpreter for returning a result. */ + Tk_Window tkwin; /* Window whose display is to be used + * for the lookup. */ +{ + TkWindow *winPtr = (TkWindow *) tkwin; + char *p, *entry, *entryName; + NameRegistry *regPtr; + Window commWindow; + int count; + + /* + * Read the registry property, then scan through all of its entries. + * Validate each entry to be sure that its application still exists. + */ + + regPtr = RegOpen(interp, winPtr->dispPtr, 1); + for (p = regPtr->property; (p-regPtr->property) < regPtr->propLength; ) { + entry = p; + if (sscanf(p, "%x",(unsigned int *) &commWindow) != 1) { + commWindow = None; + } + while ((*p != 0) && (!isspace(UCHAR(*p)))) { + p++; + } + if (*p != 0) { + p++; + } + entryName = p; + while (*p != 0) { + p++; + } + p++; + if (ValidateName(winPtr->dispPtr, entryName, commWindow, 1)) { + /* + * The application still exists; add its name to the result. + */ + + Tcl_AppendElement(interp, entryName); + } else { + /* + * This name is bogus (perhaps the application died without + * cleaning up its entry in the registry?). Delete the name. + */ + + count = regPtr->propLength - (p - regPtr->property); + if (count > 0) { + memmove((VOID *) entry, (VOID *) p, (size_t) count); + } + regPtr->propLength -= p - entry; + regPtr->modified = 1; + p = entry; + } + } + RegClose(regPtr); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * SendInit -- + * + * This procedure is called to initialize the + * communication channels for sending commands and + * receiving results. + * + * Results: + * None. + * + * Side effects: + * Sets up various data structures and windows. + * + *-------------------------------------------------------------- + */ + +static int +SendInit(interp, dispPtr) + Tcl_Interp *interp; /* Interpreter to use for error reporting + * (no errors are ever returned, but the + * interpreter is needed anyway). */ + TkDisplay *dispPtr; /* Display to initialize. */ +{ + XSetWindowAttributes atts; + + /* + * Create the window used for communication, and set up an + * event handler for it. + */ + + dispPtr->commTkwin = Tk_CreateWindow(interp, (Tk_Window) NULL, + "_comm", DisplayString(dispPtr->display)); + if (dispPtr->commTkwin == NULL) { + panic("Tk_CreateWindow failed in SendInit!"); + } + atts.override_redirect = True; + Tk_ChangeWindowAttributes(dispPtr->commTkwin, + CWOverrideRedirect, &atts); + Tk_CreateEventHandler(dispPtr->commTkwin, PropertyChangeMask, + SendEventProc, (ClientData) dispPtr); + Tk_MakeWindowExist(dispPtr->commTkwin); + + /* + * Get atoms used as property names. + */ + + dispPtr->commProperty = Tk_InternAtom(dispPtr->commTkwin, "Comm"); + dispPtr->registryProperty = Tk_InternAtom(dispPtr->commTkwin, + "InterpRegistry"); + dispPtr->appNameProperty = Tk_InternAtom(dispPtr->commTkwin, + "TK_APPLICATION"); + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * SendEventProc -- + * + * This procedure is invoked automatically by the toolkit + * event manager when a property changes on the communication + * window. This procedure reads the property and handles + * command requests and responses. + * + * Results: + * None. + * + * Side effects: + * If there are command requests in the property, they + * are executed. If there are responses in the property, + * their information is saved for the (ostensibly waiting) + * "send" commands. The property is deleted. + * + *-------------------------------------------------------------- + */ + +static void +SendEventProc(clientData, eventPtr) + ClientData clientData; /* Display information. */ + XEvent *eventPtr; /* Information about event. */ +{ + TkDisplay *dispPtr = (TkDisplay *) clientData; + char *propInfo; + register char *p; + int result, actualFormat; + unsigned long numItems, bytesAfter; + Atom actualType; + Tcl_Interp *remoteInterp; /* Interp in which to execute the command. */ + + if ((eventPtr->xproperty.atom != dispPtr->commProperty) + || (eventPtr->xproperty.state != PropertyNewValue)) { + return; + } + + /* + * Read the comm property and delete it. + */ + + propInfo = NULL; + result = XGetWindowProperty(dispPtr->display, + Tk_WindowId(dispPtr->commTkwin), + dispPtr->commProperty, 0, MAX_PROP_WORDS, True, + XA_STRING, &actualType, &actualFormat, + &numItems, &bytesAfter, (unsigned char **) &propInfo); + + /* + * If the property doesn't exist or is improperly formed + * then ignore it. + */ + + if ((result != Success) || (actualType != XA_STRING) + || (actualFormat != 8)) { + if (propInfo != NULL) { + XFree(propInfo); + } + return; + } + + /* + * Several commands and results could arrive in the property at + * one time; each iteration through the outer loop handles a + * single command or result. + */ + + for (p = propInfo; (p-propInfo) < numItems; ) { + /* + * Ignore leading NULLs; each command or result starts with a + * NULL so that no matter how badly formed a preceding command + * is, we'll be able to tell that a new command/result is + * starting. + */ + + if (*p == 0) { + p++; + continue; + } + + if ((*p == 'c') && (p[1] == 0)) { + Window commWindow; + char *interpName, *script, *serial, *end; + Tcl_DString reply; + RegisteredInterp *riPtr; + + /* + *---------------------------------------------------------- + * This is an incoming command from some other application. + * Iterate over all of its options. Stop when we reach + * the end of the property or something that doesn't look + * like an option. + *---------------------------------------------------------- + */ + + p += 2; + interpName = NULL; + commWindow = None; + serial = ""; + script = NULL; + while (((p-propInfo) < numItems) && (*p == '-')) { + switch (p[1]) { + case 'r': + commWindow = (Window) strtoul(p+2, &end, 16); + if ((end == p+2) || (*end != ' ')) { + commWindow = None; + } else { + p = serial = end+1; + } + break; + case 'n': + if (p[2] == ' ') { + interpName = p+3; + } + break; + case 's': + if (p[2] == ' ') { + script = p+3; + } + break; + } + while (*p != 0) { + p++; + } + p++; + } + + if ((script == NULL) || (interpName == NULL)) { + continue; + } + + /* + * Initialize the result property, so that we're ready at any + * time if we need to return an error. + */ + + if (commWindow != None) { + Tcl_DStringInit(&reply); + Tcl_DStringAppend(&reply, "\0r\0-s ", 6); + Tcl_DStringAppend(&reply, serial, -1); + Tcl_DStringAppend(&reply, "\0-r ", 4); + } + + if (!ServerSecure(dispPtr)) { + if (commWindow != None) { + Tcl_DStringAppend(&reply, "X server insecure (must use xauth-style authorization); command ignored", -1); + } + result = TCL_ERROR; + goto returnResult; + } + + /* + * Locate the application, then execute the script. + */ + + for (riPtr = registry; ; riPtr = riPtr->nextPtr) { + if (riPtr == NULL) { + if (commWindow != None) { + Tcl_DStringAppend(&reply, + "receiver never heard of interpreter \"", -1); + Tcl_DStringAppend(&reply, interpName, -1); + Tcl_DStringAppend(&reply, "\"", 1); + } + result = TCL_ERROR; + goto returnResult; + } + if (strcmp(riPtr->name, interpName) == 0) { + break; + } + } + Tcl_Preserve((ClientData) riPtr); + + /* + * We must protect the interpreter because the script may + * enter another event loop, which might call Tcl_DeleteInterp. + */ + + remoteInterp = riPtr->interp; + Tcl_Preserve((ClientData) remoteInterp); + + result = Tcl_GlobalEval(remoteInterp, script); + + /* + * The call to Tcl_Release may have released the interpreter + * which will cause the "send" command for that interpreter + * to be deleted. The command deletion callback will set the + * riPtr->interp field to NULL, hence the check below for NULL. + */ + + if (commWindow != None) { + Tcl_DStringAppend(&reply, remoteInterp->result, -1); + if (result == TCL_ERROR) { + char *varValue; + + varValue = Tcl_GetVar2(remoteInterp, "errorInfo", + (char *) NULL, TCL_GLOBAL_ONLY); + if (varValue != NULL) { + Tcl_DStringAppend(&reply, "\0-i ", 4); + Tcl_DStringAppend(&reply, varValue, -1); + } + varValue = Tcl_GetVar2(remoteInterp, "errorCode", + (char *) NULL, TCL_GLOBAL_ONLY); + if (varValue != NULL) { + Tcl_DStringAppend(&reply, "\0-e ", 4); + Tcl_DStringAppend(&reply, varValue, -1); + } + } + } + Tcl_Release((ClientData) remoteInterp); + Tcl_Release((ClientData) riPtr); + + /* + * Return the result to the sender if a commWindow was + * specified (if none was specified then this is an asynchronous + * call). Right now reply has everything but the completion + * code, but it needs the NULL to terminate the current option. + */ + + returnResult: + if (commWindow != None) { + if (result != TCL_OK) { + char buffer[20]; + + sprintf(buffer, "%d", result); + Tcl_DStringAppend(&reply, "\0-c ", 4); + Tcl_DStringAppend(&reply, buffer, -1); + } + (void) AppendPropCarefully(dispPtr->display, commWindow, + dispPtr->commProperty, Tcl_DStringValue(&reply), + Tcl_DStringLength(&reply) + 1, + (PendingCommand *) NULL); + XFlush(dispPtr->display); + Tcl_DStringFree(&reply); + } + } else if ((*p == 'r') && (p[1] == 0)) { + int serial, code, gotSerial; + char *errorInfo, *errorCode, *resultString; + PendingCommand *pcPtr; + + /* + *---------------------------------------------------------- + * This is a reply to some command that we sent out. Iterate + * over all of its options. Stop when we reach the end of the + * property or something that doesn't look like an option. + *---------------------------------------------------------- + */ + + p += 2; + code = TCL_OK; + gotSerial = 0; + errorInfo = NULL; + errorCode = NULL; + resultString = ""; + while (((p-propInfo) < numItems) && (*p == '-')) { + switch (p[1]) { + case 'c': + if (sscanf(p+2, " %d", &code) != 1) { + code = TCL_OK; + } + break; + case 'e': + if (p[2] == ' ') { + errorCode = p+3; + } + break; + case 'i': + if (p[2] == ' ') { + errorInfo = p+3; + } + break; + case 'r': + if (p[2] == ' ') { + resultString = p+3; + } + break; + case 's': + if (sscanf(p+2, " %d", &serial) == 1) { + gotSerial = 1; + } + break; + } + while (*p != 0) { + p++; + } + p++; + } + + if (!gotSerial) { + continue; + } + + /* + * Give the result information to anyone who's + * waiting for it. + */ + + for (pcPtr = pendingCommands; pcPtr != NULL; + pcPtr = pcPtr->nextPtr) { + if ((serial != pcPtr->serial) || (pcPtr->result != NULL)) { + continue; + } + pcPtr->code = code; + if (resultString != NULL) { + pcPtr->result = (char *) ckalloc((unsigned) + (strlen(resultString) + 1)); + strcpy(pcPtr->result, resultString); + } + if (code == TCL_ERROR) { + if (errorInfo != NULL) { + pcPtr->errorInfo = (char *) ckalloc((unsigned) + (strlen(errorInfo) + 1)); + strcpy(pcPtr->errorInfo, errorInfo); + } + if (errorCode != NULL) { + pcPtr->errorCode = (char *) ckalloc((unsigned) + (strlen(errorCode) + 1)); + strcpy(pcPtr->errorCode, errorCode); + } + } + pcPtr->gotResponse = 1; + break; + } + } else { + /* + * Didn't recognize this thing. Just skip through the next + * null character and try again. + */ + + while (*p != 0) { + p++; + } + p++; + } + } + XFree(propInfo); +} + +/* + *-------------------------------------------------------------- + * + * AppendPropCarefully -- + * + * Append a given property to a given window, but set up + * an X error handler so that if the append fails this + * procedure can return an error code rather than having + * Xlib panic. + * + * Results: + * None. + * + * Side effects: + * The given property on the given window is appended to. + * If this operation fails and if pendingPtr is non-NULL, + * then the pending operation is marked as complete with + * an error. + * + *-------------------------------------------------------------- + */ + +static void +AppendPropCarefully(display, window, property, value, length, pendingPtr) + Display *display; /* Display on which to operate. */ + Window window; /* Window whose property is to + * be modified. */ + Atom property; /* Name of property. */ + char *value; /* Characters to append to property. */ + int length; /* Number of bytes to append. */ + PendingCommand *pendingPtr; /* Pending command to mark complete + * if an error occurs during the + * property op. NULL means just + * ignore the error. */ +{ + Tk_ErrorHandler handler; + + handler = Tk_CreateErrorHandler(display, -1, -1, -1, AppendErrorProc, + (ClientData) pendingPtr); + XChangeProperty(display, window, property, XA_STRING, 8, + PropModeAppend, (unsigned char *) value, length); + Tk_DeleteErrorHandler(handler); +} + +/* + * The procedure below is invoked if an error occurs during + * the XChangeProperty operation above. + */ + + /* ARGSUSED */ +static int +AppendErrorProc(clientData, errorPtr) + ClientData clientData; /* Command to mark complete, or NULL. */ + XErrorEvent *errorPtr; /* Information about error. */ +{ + PendingCommand *pendingPtr = (PendingCommand *) clientData; + register PendingCommand *pcPtr; + + if (pendingPtr == NULL) { + return 0; + } + + /* + * Make sure this command is still pending. + */ + + for (pcPtr = pendingCommands; pcPtr != NULL; + pcPtr = pcPtr->nextPtr) { + if ((pcPtr == pendingPtr) && (pcPtr->result == NULL)) { + pcPtr->result = (char *) ckalloc((unsigned) + (strlen(pcPtr->target) + 50)); + sprintf(pcPtr->result, "no application named \"%s\"", + pcPtr->target); + pcPtr->code = TCL_ERROR; + pcPtr->gotResponse = 1; + break; + } + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * TimeoutProc -- + * + * This procedure is invoked when an unusually long amout of + * time has elapsed during the processing of a sent command. + * It checks to make sure that the target application still + * exists, and reschedules itself to check again later. + * + * Results: + * None. + * + * Side effects: + * If the target application has gone away abort the send + * operation with an error. + * + *-------------------------------------------------------------- + */ + +static void +TimeoutProc(clientData) + ClientData clientData; /* Information about command that + * has been sent but not yet + * responded to. */ +{ + PendingCommand *pcPtr = (PendingCommand *) clientData; + register PendingCommand *pcPtr2; + + /* + * Make sure that the command is still in the pending list + * and that it hasn't already completed. Then validate the + * existence of the target application. + */ + + for (pcPtr2 = pendingCommands; pcPtr2 != NULL; + pcPtr2 = pcPtr2->nextPtr) { + char *msg; + if ((pcPtr2 != pcPtr) || (pcPtr2->result != NULL)) { + continue; + } + if (!ValidateName(pcPtr2->dispPtr, pcPtr2->target, + pcPtr2->commWindow, 0)) { + if (ValidateName(pcPtr2->dispPtr, pcPtr2->target, + pcPtr2->commWindow, 1)) { + msg = + "target application died or uses a Tk version before 4.0"; + } else { + msg = "target application died"; + } + pcPtr2->code = TCL_ERROR; + pcPtr2->result = (char *) ckalloc((unsigned) (strlen(msg) + 1)); + strcpy(pcPtr2->result, msg); + pcPtr2->gotResponse = 1; + } else { + Tcl_DeleteModalTimeout(TimeoutProc, clientData); + Tcl_CreateModalTimeout(2000, TimeoutProc, clientData); + } + } +} + +/* + *-------------------------------------------------------------- + * + * DeleteProc -- + * + * This procedure is invoked by Tcl when the "send" command + * is deleted in an interpreter. It unregisters the interpreter. + * + * Results: + * None. + * + * Side effects: + * The interpreter given by riPtr is unregistered. + * + *-------------------------------------------------------------- + */ + +static void +DeleteProc(clientData) + ClientData clientData; /* Info about registration, passed + * as ClientData. */ +{ + RegisteredInterp *riPtr = (RegisteredInterp *) clientData; + register RegisteredInterp *riPtr2; + NameRegistry *regPtr; + + regPtr = RegOpen(riPtr->interp, riPtr->dispPtr, 1); + RegDeleteName(regPtr, riPtr->name); + RegClose(regPtr); + + if (registry == riPtr) { + registry = riPtr->nextPtr; + } else { + for (riPtr2 = registry; riPtr2 != NULL; + riPtr2 = riPtr2->nextPtr) { + if (riPtr2->nextPtr == riPtr) { + riPtr2->nextPtr = riPtr->nextPtr; + break; + } + } + } + ckfree((char *) riPtr->name); + riPtr->interp = NULL; + UpdateCommWindow(riPtr->dispPtr); + Tcl_EventuallyFree((ClientData) riPtr, TCL_DYNAMIC); +} + +/* + *---------------------------------------------------------------------- + * + * SendRestrictProc -- + * + * This procedure filters incoming events when a "send" command + * is outstanding. It defers all events except those containing + * send commands and results. + * + * Results: + * False is returned except for property-change events on a + * commWindow. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static Tk_RestrictAction +SendRestrictProc(clientData, eventPtr) + ClientData clientData; /* Not used. */ + register XEvent *eventPtr; /* Event that just arrived. */ +{ + TkDisplay *dispPtr; + + if (eventPtr->type != PropertyNotify) { + return TK_DEFER_EVENT; + } + for (dispPtr = tkDisplayList; dispPtr != NULL; dispPtr = dispPtr->nextPtr) { + if ((eventPtr->xany.display == dispPtr->display) + && (eventPtr->xproperty.window + == Tk_WindowId(dispPtr->commTkwin))) { + return TK_PROCESS_EVENT; + } + } + return TK_DEFER_EVENT; +} + +/* + *---------------------------------------------------------------------- + * + * UpdateCommWindow -- + * + * This procedure updates the list of application names stored + * on our commWindow. It is typically called when interpreters + * are registered and unregistered. + * + * Results: + * None. + * + * Side effects: + * The TK_APPLICATION property on the comm window is updated. + * + *---------------------------------------------------------------------- + */ + +static void +UpdateCommWindow(dispPtr) + TkDisplay *dispPtr; /* Display whose commWindow is to be + * updated. */ +{ + Tcl_DString names; + RegisteredInterp *riPtr; + + Tcl_DStringInit(&names); + for (riPtr = registry; riPtr != NULL; riPtr = riPtr->nextPtr) { + Tcl_DStringAppendElement(&names, riPtr->name); + } + XChangeProperty(dispPtr->display, Tk_WindowId(dispPtr->commTkwin), + dispPtr->appNameProperty, XA_STRING, 8, PropModeReplace, + (unsigned char *) Tcl_DStringValue(&names), + Tcl_DStringLength(&names)); + Tcl_DStringFree(&names); +} diff --git a/tk/generic/tkSquare.c b/tk/generic/tkSquare.c index 50484528d30..983969c1f4d 100644 --- a/tk/generic/tkSquare.c +++ b/tk/generic/tkSquare.c @@ -1,14 +1,13 @@ /* * tkSquare.c -- * - * This module implements "square" widgets. A "square" is - * a widget that displays a single square that can be moved - * around and resized. This file is intended as an example + * This module implements "square" widgets that are object + * based. A "square" is a widget that displays a single square that can + * be moved around and resized. This file is intended as an example * of how to build a widget; it isn't included in the * normal wish, but it is included in "tktest". * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -17,7 +16,9 @@ */ #include "tkPort.h" +#define __NO_OLD_CONFIG #include "tk.h" +#include "tkInt.h" /* * A data structure of the following type is kept for each square @@ -31,22 +32,24 @@ typedef struct { Display *display; /* X's token for the window's display. */ Tcl_Interp *interp; /* Interpreter associated with widget. */ Tcl_Command widgetCmd; /* Token for square's widget command. */ - int x, y; /* Position of square's upper-left corner + Tk_OptionTable optionTable; /* Token representing the configuration + * specifications. */ + Tcl_Obj *xPtr, *yPtr; /* Position of square's upper-left corner * within widget. */ - int size; /* Width and height of square. */ + int x, y; + Tcl_Obj *sizeObjPtr; /* Width and height of square. */ /* * Information used when displaying widget: */ - int borderWidth; /* Width of 3-D border around whole widget. */ - Tk_3DBorder bgBorder; /* Used for drawing background. */ - Tk_3DBorder fgBorder; /* For drawing square. */ - int relief; /* Indicates whether window as a whole is - * raised, sunken, or flat. */ + Tcl_Obj *borderWidthPtr; /* Width of 3-D border around whole widget. */ + Tcl_Obj *bgBorderPtr; + Tcl_Obj *fgBorderPtr; + Tcl_Obj *reliefPtr; GC gc; /* Graphics context for copying from * off-screen pixmap onto screen. */ - int doubleBuffer; /* Non-zero means double-buffer redisplay + Tcl_Obj *doubleBufferPtr; /* Non-zero means double-buffer redisplay * with pixmap; zero means draw straight * onto the display. */ int updatePending; /* Non-zero means a call to SquareDisplay @@ -57,49 +60,52 @@ typedef struct { * Information used for argv parsing. */ -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_BORDER, "-background", "background", "Background", - "#d9d9d9", Tk_Offset(Square, bgBorder), TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-background", "background", "Background", - "white", Tk_Offset(Square, bgBorder), TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - "2", Tk_Offset(Square, borderWidth), 0}, - {TK_CONFIG_INT, "-dbl", "doubleBuffer", "DoubleBuffer", - "1", Tk_Offset(Square, doubleBuffer), 0}, - {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, 0}, - {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", - "#b03060", Tk_Offset(Square, fgBorder), TK_CONFIG_COLOR_ONLY}, - {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", - "black", Tk_Offset(Square, fgBorder), TK_CONFIG_MONO_ONLY}, - {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", - "raised", Tk_Offset(Square, relief), 0}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0} +static Tk_OptionSpec configSpecs[] = { + {TK_OPTION_BORDER, "-background", "background", "Background", + "#d9d9d9", Tk_Offset(Square, bgBorderPtr), -1, 0, + (ClientData) "white"}, + {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth"}, + {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-background"}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + "2", Tk_Offset(Square, borderWidthPtr), -1}, + {TK_OPTION_BOOLEAN, "-dbl", "doubleBuffer", "DoubleBuffer", + "1", Tk_Offset(Square, doubleBufferPtr), -1}, + {TK_OPTION_SYNONYM, "-fg", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground"}, + {TK_OPTION_BORDER, "-foreground", "foreground", "Foreground", + "#b03060", Tk_Offset(Square, fgBorderPtr), -1, 0, + (ClientData) "black"}, + {TK_OPTION_PIXELS, "-posx", "posx", "PosX", "0", + Tk_Offset(Square, xPtr), -1}, + {TK_OPTION_PIXELS, "-posy", "posy", "PosY", "0", + Tk_Offset(Square, yPtr), -1}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + "raised", Tk_Offset(Square, reliefPtr), -1}, + {TK_OPTION_PIXELS, "-size", "size", "Size", "20", + Tk_Offset(Square, sizeObjPtr), -1}, + {TK_OPTION_END} }; /* * Forward declarations for procedures defined later in this file: */ -int SquareCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char **argv)); -static void SquareCmdDeletedProc _ANSI_ARGS_(( +int SquareObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj * CONST objv[])); +static void SquareDeletedProc _ANSI_ARGS_(( ClientData clientData)); static int SquareConfigure _ANSI_ARGS_((Tcl_Interp *interp, - Square *squarePtr, int argc, char **argv, - int flags)); + Square *squarePtr)); static void SquareDestroy _ANSI_ARGS_((char *memPtr)); static void SquareDisplay _ANSI_ARGS_((ClientData clientData)); static void KeepInWindow _ANSI_ARGS_((Square *squarePtr)); -static void SquareEventProc _ANSI_ARGS_((ClientData clientData, +static void SquareObjEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static int SquareWidgetCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *, int argc, char **argv)); + Tcl_Interp *, int objc, Tcl_Obj * CONST objv[])); /* *-------------------------------------------------------------- @@ -119,24 +125,41 @@ static int SquareWidgetCmd _ANSI_ARGS_((ClientData clientData, */ int -SquareCmd(clientData, interp, argc, argv) +SquareObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj * CONST objv[]; /* Argument objects. */ { - Tk_Window main = (Tk_Window) clientData; Square *squarePtr; Tk_Window tkwin; + Tk_OptionTable optionTable = (Tk_OptionTable) clientData; + Tcl_CmdInfo info; + char *commandName; + + if (optionTable == NULL) { + /* + * The first time this procedure is invoked, optionTable will + * be NULL. We then create the option table from the template + * and store the table pointer as the command's clinical so + * we'll have easy access to it in the future. + */ + + optionTable = Tk_CreateOptionTable(interp, configSpecs); + commandName = Tcl_GetStringFromObj(objv[0], (int *) NULL); + Tcl_GetCommandInfo(interp, commandName, &info); + info.clientData = (ClientData) optionTable; + Tcl_SetCommandInfo(interp, commandName, &info); + } - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " pathName ?options?\"", (char *) NULL); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } - tkwin = Tk_CreateWindowFromPath(interp, main, argv[1], (char *) NULL); + tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), + Tcl_GetStringFromObj(objv[1], NULL), (char *) NULL); if (tkwin == NULL) { return TCL_ERROR; } @@ -150,29 +173,47 @@ SquareCmd(clientData, interp, argc, argv) squarePtr->tkwin = tkwin; squarePtr->display = Tk_Display(tkwin); squarePtr->interp = interp; - squarePtr->widgetCmd = Tcl_CreateCommand(interp, + squarePtr->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(squarePtr->tkwin), SquareWidgetCmd, - (ClientData) squarePtr, SquareCmdDeletedProc); + (ClientData) squarePtr, SquareDeletedProc); + squarePtr->xPtr = NULL; + squarePtr->yPtr = NULL; squarePtr->x = 0; squarePtr->y = 0; - squarePtr->size = 20; - squarePtr->borderWidth = 0; - squarePtr->bgBorder = NULL; - squarePtr->fgBorder = NULL; - squarePtr->relief = TK_RELIEF_FLAT; + squarePtr->sizeObjPtr = NULL; + squarePtr->borderWidthPtr = NULL; + squarePtr->bgBorderPtr = NULL; + squarePtr->fgBorderPtr = NULL; + squarePtr->reliefPtr = NULL; squarePtr->gc = None; - squarePtr->doubleBuffer = 1; + squarePtr->doubleBufferPtr = NULL; squarePtr->updatePending = 0; + squarePtr->optionTable = optionTable; - Tk_CreateEventHandler(squarePtr->tkwin, ExposureMask|StructureNotifyMask, - SquareEventProc, (ClientData) squarePtr); - if (SquareConfigure(interp, squarePtr, argc-2, argv+2, 0) != TCL_OK) { + if (Tk_InitOptions(interp, (char *) squarePtr, optionTable, tkwin) + != TCL_OK) { Tk_DestroyWindow(squarePtr->tkwin); + ckfree((char *) squarePtr); return TCL_ERROR; } - interp->result = Tk_PathName(squarePtr->tkwin); + Tk_CreateEventHandler(squarePtr->tkwin, ExposureMask|StructureNotifyMask, + SquareObjEventProc, (ClientData) squarePtr); + if (Tk_SetOptions(interp, (char *) squarePtr, optionTable, objc - 2, + objv + 2, tkwin, NULL, (int *) NULL) != TCL_OK) { + goto error; + } + if (SquareConfigure(interp, squarePtr) != TCL_OK) { + goto error; + } + + Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(squarePtr->tkwin), + -1)); return TCL_OK; + +error: + Tk_DestroyWindow(squarePtr->tkwin); + return TCL_ERROR; } /* @@ -194,92 +235,79 @@ SquareCmd(clientData, interp, argc, argv) */ static int -SquareWidgetCmd(clientData, interp, argc, argv) +SquareWidgetCmd(clientData, interp, objc, objv) ClientData clientData; /* Information about square widget. */ Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + int objc; /* Number of arguments. */ + Tcl_Obj * CONST objv[]; /* Argument objects. */ { Square *squarePtr = (Square *) clientData; int result = TCL_OK; - size_t length; - char c; + static char *squareOptions[] = {"cget", "configure", (char *) NULL}; + enum { + SQUARE_CGET, SQUARE_CONFIGURE + }; + Tcl_Obj *resultObjPtr; + int index; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg...?"); + return TCL_ERROR; + } - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " option ?arg arg ...?\"", (char *) NULL); + if (Tcl_GetIndexFromObj(interp, objv[1], squareOptions, "command", + 0, &index) != TCL_OK) { return TCL_ERROR; } + Tcl_Preserve((ClientData) squarePtr); - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " cget option\"", - (char *) NULL); - goto error; - } - result = Tk_ConfigureValue(interp, squarePtr->tkwin, configSpecs, - (char *) squarePtr, argv[2], 0); - } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) - && (length >= 2)) { - if (argc == 2) { - result = Tk_ConfigureInfo(interp, squarePtr->tkwin, configSpecs, - (char *) squarePtr, (char *) NULL, 0); - } else if (argc == 3) { - result = Tk_ConfigureInfo(interp, squarePtr->tkwin, configSpecs, - (char *) squarePtr, argv[2], 0); - } else { - result = SquareConfigure(interp, squarePtr, argc-2, argv+2, - TK_CONFIG_ARGV_ONLY); - } - } else if ((c == 'p') && (strncmp(argv[1], "position", length) == 0)) { - if ((argc != 2) && (argc != 4)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " position ?x y?\"", (char *) NULL); - goto error; - } - if (argc == 4) { - if ((Tk_GetPixels(interp, squarePtr->tkwin, argv[2], - &squarePtr->x) != TCL_OK) || (Tk_GetPixels(interp, - squarePtr->tkwin, argv[3], &squarePtr->y) != TCL_OK)) { + + switch (index) { + case SQUARE_CGET: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); goto error; } - KeepInWindow(squarePtr); - } - sprintf(interp->result, "%d %d", squarePtr->x, squarePtr->y); - } else if ((c == 's') && (strncmp(argv[1], "size", length) == 0)) { - if ((argc != 2) && (argc != 3)) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " size ?amount?\"", (char *) NULL); - goto error; + resultObjPtr = Tk_GetOptionValue(interp, (char *) squarePtr, + squarePtr->optionTable, objv[2], squarePtr->tkwin); + if (resultObjPtr == NULL) { + result = TCL_ERROR; + } else { + Tcl_SetObjResult(interp, resultObjPtr); + } + break; } - if (argc == 3) { - int i; - - if (Tk_GetPixels(interp, squarePtr->tkwin, argv[2], &i) != TCL_OK) { - goto error; + case SQUARE_CONFIGURE: { + resultObjPtr = NULL; + if (objc == 2) { + resultObjPtr = Tk_GetOptionInfo(interp, (char *) squarePtr, + squarePtr->optionTable, (Tcl_Obj *) NULL, + squarePtr->tkwin); + if (resultObjPtr == NULL) { + result = TCL_ERROR; + } + } else if (objc == 3) { + resultObjPtr = Tk_GetOptionInfo(interp, (char *) squarePtr, + squarePtr->optionTable, objv[2], squarePtr->tkwin); + if (resultObjPtr == NULL) { + result = TCL_ERROR; + } + } else { + result = Tk_SetOptions(interp, (char *) squarePtr, + squarePtr->optionTable, objc - 2, objv + 2, + squarePtr->tkwin, NULL, (int *) NULL); + if (result == TCL_OK) { + result = SquareConfigure(interp, squarePtr); + } + if (!squarePtr->updatePending) { + Tcl_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); + squarePtr->updatePending = 1; + } } - if ((i <= 0) || (i > 100)) { - Tcl_AppendResult(interp, "bad size \"", argv[2], - "\"", (char *) NULL); - goto error; + if (resultObjPtr != NULL) { + Tcl_SetObjResult(interp, resultObjPtr); } - squarePtr->size = i; - KeepInWindow(squarePtr); } - sprintf(interp->result, "%d", squarePtr->size); - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": must be cget, configure, position, or size", - (char *) NULL); - goto error; - } - if (!squarePtr->updatePending) { - Tcl_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); - squarePtr->updatePending = 1; } Tcl_Release((ClientData) squarePtr); return result; @@ -300,7 +328,7 @@ SquareWidgetCmd(clientData, interp, argc, argv) * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as colors, border width, @@ -311,27 +339,25 @@ SquareWidgetCmd(clientData, interp, argc, argv) */ static int -SquareConfigure(interp, squarePtr, argc, argv, flags) +SquareConfigure(interp, squarePtr) Tcl_Interp *interp; /* Used for error reporting. */ Square *squarePtr; /* Information about widget. */ - int argc; /* Number of valid entries in argv. */ - char **argv; /* Arguments. */ - int flags; /* Flags to pass to - * Tk_ConfigureWidget. */ { - if (Tk_ConfigureWidget(interp, squarePtr->tkwin, configSpecs, - argc, argv, (char *) squarePtr, flags) != TCL_OK) { - return TCL_ERROR; - } + int borderWidth; + Tk_3DBorder bgBorder; + int doubleBuffer; /* * Set the background for the window and create a graphics context * for use during redisplay. */ + bgBorder = Tk_Get3DBorderFromObj(squarePtr->tkwin, + squarePtr->bgBorderPtr); Tk_SetWindowBackground(squarePtr->tkwin, - Tk_3DBorderColor(squarePtr->bgBorder)->pixel); - if ((squarePtr->gc == None) && (squarePtr->doubleBuffer)) { + Tk_3DBorderColor(bgBorder)->pixel); + Tcl_GetBooleanFromObj(NULL, squarePtr->doubleBufferPtr, &doubleBuffer); + if ((squarePtr->gc == None) && (doubleBuffer)) { XGCValues gcValues; gcValues.function = GXcopy; gcValues.graphics_exposures = False; @@ -345,18 +371,21 @@ SquareConfigure(interp, squarePtr, argc, argv, flags) */ Tk_GeometryRequest(squarePtr->tkwin, 200, 150); - Tk_SetInternalBorder(squarePtr->tkwin, squarePtr->borderWidth); + Tk_GetPixelsFromObj(NULL, squarePtr->tkwin, squarePtr->borderWidthPtr, + &borderWidth); + Tk_SetInternalBorder(squarePtr->tkwin, borderWidth); if (!squarePtr->updatePending) { Tcl_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); squarePtr->updatePending = 1; } + KeepInWindow(squarePtr); return TCL_OK; } /* *-------------------------------------------------------------- * - * SquareEventProc -- + * SquareObjEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on squares. @@ -372,7 +401,7 @@ SquareConfigure(interp, squarePtr, argc, argv, flags) */ static void -SquareEventProc(clientData, eventPtr) +SquareObjEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */ { @@ -391,6 +420,11 @@ SquareEventProc(clientData, eventPtr) } } else if (eventPtr->type == DestroyNotify) { if (squarePtr->tkwin != NULL) { + Tk_FreeConfigOptions((char *) squarePtr, squarePtr->optionTable, + squarePtr->tkwin); + if (squarePtr->gc != None) { + Tk_FreeGC(squarePtr->display, squarePtr->gc); + } squarePtr->tkwin = NULL; Tcl_DeleteCommandFromToken(squarePtr->interp, squarePtr->widgetCmd); @@ -405,7 +439,7 @@ SquareEventProc(clientData, eventPtr) /* *---------------------------------------------------------------------- * - * SquareCmdDeletedProc -- + * SquareDeletedProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, @@ -421,7 +455,7 @@ SquareEventProc(clientData, eventPtr) */ static void -SquareCmdDeletedProc(clientData) +SquareDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */ { Square *squarePtr = (Square *) clientData; @@ -435,7 +469,6 @@ SquareCmdDeletedProc(clientData) */ if (tkwin != NULL) { - squarePtr->tkwin = NULL; Tk_DestroyWindow(tkwin); } } @@ -466,6 +499,9 @@ SquareDisplay(clientData) Tk_Window tkwin = squarePtr->tkwin; Pixmap pm = None; Drawable d; + int borderWidth, size, relief; + Tk_3DBorder bgBorder, fgBorder; + int doubleBuffer; squarePtr->updatePending = 0; if (!Tk_IsMapped(tkwin)) { @@ -476,7 +512,8 @@ SquareDisplay(clientData) * Create a pixmap for double-buffering, if necessary. */ - if (squarePtr->doubleBuffer) { + Tcl_GetBooleanFromObj(NULL, squarePtr->doubleBufferPtr, &doubleBuffer); + if (doubleBuffer) { pm = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), DefaultDepthOfScreen(Tk_Screen(tkwin))); @@ -489,22 +526,29 @@ SquareDisplay(clientData) * Redraw the widget's background and border. */ - Tk_Fill3DRectangle(tkwin, d, squarePtr->bgBorder, 0, 0, Tk_Width(tkwin), - Tk_Height(tkwin), squarePtr->borderWidth, squarePtr->relief); + Tk_GetPixelsFromObj(NULL, squarePtr->tkwin, squarePtr->borderWidthPtr, + &borderWidth); + bgBorder = Tk_Get3DBorderFromObj(squarePtr->tkwin, + squarePtr->bgBorderPtr); + Tk_GetReliefFromObj(NULL, squarePtr->reliefPtr, &relief); + Tk_Fill3DRectangle(tkwin, d, bgBorder, 0, 0, Tk_Width(tkwin), + Tk_Height(tkwin), borderWidth, relief); /* * Display the square. */ - Tk_Fill3DRectangle(tkwin, d, squarePtr->fgBorder, squarePtr->x, - squarePtr->y, squarePtr->size, squarePtr->size, - squarePtr->borderWidth, TK_RELIEF_RAISED); + Tk_GetPixelsFromObj(NULL, squarePtr->tkwin, squarePtr->sizeObjPtr, &size); + fgBorder = Tk_Get3DBorderFromObj(squarePtr->tkwin, + squarePtr->fgBorderPtr); + Tk_Fill3DRectangle(tkwin, d, fgBorder, squarePtr->x, squarePtr->y, size, + size, borderWidth, TK_RELIEF_RAISED); /* * If double-buffered, copy to the screen and release the pixmap. */ - if (squarePtr->doubleBuffer) { + if (doubleBuffer) { XCopyArea(Tk_Display(tkwin), pm, Tk_WindowId(tkwin), squarePtr->gc, 0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin), 0, 0); @@ -535,11 +579,7 @@ SquareDestroy(memPtr) char *memPtr; /* Info about square widget. */ { Square *squarePtr = (Square *) memPtr; - - Tk_FreeOptions(configSpecs, (char *) squarePtr, squarePtr->display, 0); - if (squarePtr->gc != None) { - Tk_FreeGC(squarePtr->display, squarePtr->gc); - } + ckfree((char *) squarePtr); } @@ -565,16 +605,26 @@ static void KeepInWindow(squarePtr) register Square *squarePtr; /* Pointer to widget record. */ { - int i, bd; + int i, bd, relief; + int borderWidth, size; + + Tk_GetPixelsFromObj(NULL, squarePtr->tkwin, squarePtr->borderWidthPtr, + &borderWidth); + Tk_GetPixelsFromObj(NULL, squarePtr->tkwin, squarePtr->xPtr, + &squarePtr->x); + Tk_GetPixelsFromObj(NULL, squarePtr->tkwin, squarePtr->yPtr, + &squarePtr->y); + Tk_GetPixelsFromObj(NULL, squarePtr->tkwin, squarePtr->sizeObjPtr, &size); + Tk_GetReliefFromObj(NULL, squarePtr->reliefPtr, &relief); bd = 0; - if (squarePtr->relief != TK_RELIEF_FLAT) { - bd = squarePtr->borderWidth; + if (relief != TK_RELIEF_FLAT) { + bd = borderWidth; } - i = (Tk_Width(squarePtr->tkwin) - bd) - (squarePtr->x + squarePtr->size); + i = (Tk_Width(squarePtr->tkwin) - bd) - (squarePtr->x + size); if (i < 0) { squarePtr->x += i; } - i = (Tk_Height(squarePtr->tkwin) - bd) - (squarePtr->y + squarePtr->size); + i = (Tk_Height(squarePtr->tkwin) - bd) - (squarePtr->y + size); if (i < 0) { squarePtr->y += i; } @@ -585,3 +635,4 @@ KeepInWindow(squarePtr) squarePtr->y = bd; } } + diff --git a/tk/generic/tkStubImg.c b/tk/generic/tkStubImg.c new file mode 100644 index 00000000000..024e581c578 --- /dev/null +++ b/tk/generic/tkStubImg.c @@ -0,0 +1,75 @@ +/* + * tkStubImg.c -- + * + * Stub object that will be statically linked into extensions that wish + * to access Tk. + * + * Copyright (c) 1999 Jan Nijtmans. + * Copyright (c) 1998-1999 by Scriptics Corporation. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +#include "tcl.h" + + +/* + *---------------------------------------------------------------------- + * + * Tk_InitImageArgs -- + * + * Performs the necessary conversion from Tcl_Obj's to strings + * in the createProc for Tcl_CreateImageType. If running under + * Tk 8.2 or earlier without the Img-patch, this function has + * no effect. + * + * Results: + * argvPtr will point to an argument list which is guaranteed to + * contain strings, no matter what Tk version is running. + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +#ifdef Tk_InitImageArgs +#undef Tk_InitImageArgs +#endif + +void +Tk_InitImageArgs(interp, argc, argvPtr) + Tcl_Interp *interp; + int argc; + char ***argvPtr; +{ + static useNewImage = -1; + static char **argv = NULL; + + if (argv) { + tclStubsPtr->tcl_Free((char *) argv); + argv = NULL; + } + + if (useNewImage < 0) { + Tcl_CmdInfo cmdInfo; + if (!tclStubsPtr->tcl_GetCommandInfo(interp,"image", &cmdInfo)) { + tclStubsPtr->tcl_Panic("cannot find the \"image\" command"); + } + if (cmdInfo.isNativeObjectProc == 1) { + useNewImage = 1; /* Tk uses the new image interface */ + } + } + if (useNewImage && (argc > 0)) { + int i; + argv = (char **) tclStubsPtr->tcl_Alloc(argc * sizeof(char *)); + for (i = 0; i < argc; i++) { + argv[i] = tclStubsPtr->tcl_GetString((Tcl_Obj *)(*argvPtr)[i]); + } + *argvPtr = (char **) argv; + } +} + diff --git a/tk/generic/tkStubInit.c b/tk/generic/tkStubInit.c new file mode 100644 index 00000000000..5dc7b43920a --- /dev/null +++ b/tk/generic/tkStubInit.c @@ -0,0 +1,954 @@ +/* + * tkStubInit.c -- + * + * This file contains the initializers for the Tk stub vectors. + * + * Copyright (c) 1998-1999 by Scriptics Corporation. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +#include "tkInt.h" +#include "tkPort.h" + +#ifdef __WIN32__ +#include "tkWinInt.h" +#endif +#ifdef MAC_TCL +#include "tkMacInt.h" +#endif + +#include "tkDecls.h" +#include "tkPlatDecls.h" +#include "tkIntDecls.h" +#include "tkIntPlatDecls.h" +#include "tkIntXlibDecls.h" + +/* + * Remove macros that will interfere with the definitions below. + */ + +#define Tk_CreateCanvasVisitor ((void (*) _ANSI_ARGS_((Tcl_Interp * interp, \ + VOID * typePtr))) NULL) +#define Tk_GetCanvasVisitor ((VOID * (*) _ANSI_ARGS_((Tcl_Interp * interp, \ + CONST char * name))) NULL) + +/* + * WARNING: The contents of this file is automatically generated by the + * tools/genStubs.tcl script. Any modifications to the function declarations + * below should be made in the generic/tk.decls script. + */ + +/* !BEGIN!: Do not edit below this line. */ + +TkIntStubs tkIntStubs = { + TCL_STUB_MAGIC, + NULL, + TkAllocWindow, /* 0 */ + TkBezierPoints, /* 1 */ + TkBezierScreenPoints, /* 2 */ + TkBindDeadWindow, /* 3 */ + TkBindEventProc, /* 4 */ + TkBindFree, /* 5 */ + TkBindInit, /* 6 */ + TkChangeEventWindow, /* 7 */ + TkClipInit, /* 8 */ + TkComputeAnchor, /* 9 */ + TkCopyAndGlobalEval, /* 10 */ + TkCreateBindingProcedure, /* 11 */ + TkCreateCursorFromData, /* 12 */ + TkCreateFrame, /* 13 */ + TkCreateMainWindow, /* 14 */ + TkCurrentTime, /* 15 */ + TkDeleteAllImages, /* 16 */ + TkDoConfigureNotify, /* 17 */ + TkDrawInsetFocusHighlight, /* 18 */ + TkEventDeadWindow, /* 19 */ + TkFillPolygon, /* 20 */ + TkFindStateNum, /* 21 */ + TkFindStateString, /* 22 */ + TkFocusDeadWindow, /* 23 */ + TkFocusFilterEvent, /* 24 */ + TkFocusKeyEvent, /* 25 */ + TkFontPkgInit, /* 26 */ + TkFontPkgFree, /* 27 */ + TkFreeBindingTags, /* 28 */ + TkpFreeCursor, /* 29 */ + TkGetBitmapData, /* 30 */ + TkGetButtPoints, /* 31 */ + TkGetCursorByName, /* 32 */ + TkGetDefaultScreenName, /* 33 */ + TkGetDisplay, /* 34 */ + TkGetDisplayOf, /* 35 */ + TkGetFocusWin, /* 36 */ + TkGetInterpNames, /* 37 */ + TkGetMiterPoints, /* 38 */ + TkGetPointerCoords, /* 39 */ + TkGetServerInfo, /* 40 */ + TkGrabDeadWindow, /* 41 */ + TkGrabState, /* 42 */ + TkIncludePoint, /* 43 */ + TkInOutEvents, /* 44 */ + TkInstallFrameMenu, /* 45 */ + TkKeysymToString, /* 46 */ + TkLineToArea, /* 47 */ + TkLineToPoint, /* 48 */ + TkMakeBezierCurve, /* 49 */ + TkMakeBezierPostscript, /* 50 */ + TkOptionClassChanged, /* 51 */ + TkOptionDeadWindow, /* 52 */ + TkOvalToArea, /* 53 */ + TkOvalToPoint, /* 54 */ + TkpChangeFocus, /* 55 */ + TkpCloseDisplay, /* 56 */ + TkpClaimFocus, /* 57 */ + TkpDisplayWarning, /* 58 */ + TkpGetAppName, /* 59 */ + TkpGetOtherWindow, /* 60 */ + TkpGetWrapperWindow, /* 61 */ + TkpInit, /* 62 */ + TkpInitializeMenuBindings, /* 63 */ + TkpMakeContainer, /* 64 */ + TkpMakeMenuWindow, /* 65 */ + TkpMakeWindow, /* 66 */ + TkpMenuNotifyToplevelCreate, /* 67 */ + TkpOpenDisplay, /* 68 */ + TkPointerEvent, /* 69 */ + TkPolygonToArea, /* 70 */ + TkPolygonToPoint, /* 71 */ + TkPositionInTree, /* 72 */ + TkpRedirectKeyEvent, /* 73 */ + TkpSetMainMenubar, /* 74 */ + TkpUseWindow, /* 75 */ + TkpWindowWasRecentlyDeleted, /* 76 */ + TkQueueEventForAllChildren, /* 77 */ + TkReadBitmapFile, /* 78 */ + TkScrollWindow, /* 79 */ + TkSelDeadWindow, /* 80 */ + TkSelEventProc, /* 81 */ + TkSelInit, /* 82 */ + TkSelPropProc, /* 83 */ + TkSetClassProcs, /* 84 */ + TkSetWindowMenuBar, /* 85 */ + TkStringToKeysym, /* 86 */ + TkThickPolyLineToArea, /* 87 */ + TkWmAddToColormapWindows, /* 88 */ + TkWmDeadWindow, /* 89 */ + TkWmFocusToplevel, /* 90 */ + TkWmMapWindow, /* 91 */ + TkWmNewWindow, /* 92 */ + TkWmProtocolEventProc, /* 93 */ + TkWmRemoveFromColormapWindows, /* 94 */ + TkWmRestackToplevel, /* 95 */ + TkWmSetClass, /* 96 */ + TkWmUnmapWindow, /* 97 */ + TkDebugBitmap, /* 98 */ + TkDebugBorder, /* 99 */ + TkDebugCursor, /* 100 */ + TkDebugColor, /* 101 */ + TkDebugConfig, /* 102 */ + TkDebugFont, /* 103 */ + TkFindStateNumObj, /* 104 */ + TkGetBitmapPredefTable, /* 105 */ + TkGetDisplayList, /* 106 */ + TkGetMainInfoList, /* 107 */ + TkGetWindowFromObj, /* 108 */ + TkpGetString, /* 109 */ + TkpGetSubFonts, /* 110 */ + TkpGetSystemDefault, /* 111 */ + TkpMenuThreadInit, /* 112 */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 113 */ +#endif /* UNIX */ +#ifdef __WIN32__ + TkClipBox, /* 113 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkClipBox, /* 113 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 114 */ +#endif /* UNIX */ +#ifdef __WIN32__ + TkCreateRegion, /* 114 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkCreateRegion, /* 114 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 115 */ +#endif /* UNIX */ +#ifdef __WIN32__ + TkDestroyRegion, /* 115 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkDestroyRegion, /* 115 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 116 */ +#endif /* UNIX */ +#ifdef __WIN32__ + TkIntersectRegion, /* 116 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkIntersectRegion, /* 116 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 117 */ +#endif /* UNIX */ +#ifdef __WIN32__ + TkRectInRegion, /* 117 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkRectInRegion, /* 117 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 118 */ +#endif /* UNIX */ +#ifdef __WIN32__ + TkSetRegion, /* 118 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkSetRegion, /* 118 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 119 */ +#endif /* UNIX */ +#ifdef __WIN32__ + TkUnionRectWithRegion, /* 119 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkUnionRectWithRegion, /* 119 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 120 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 120 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkGenerateActivateEvents, /* 120 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 121 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 121 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkpCreateNativeBitmap, /* 121 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 122 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 122 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkpDefineNativeBitmaps, /* 122 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 123 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 123 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkpGetMS, /* 123 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 124 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 124 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkpGetNativeAppBitmap, /* 124 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 125 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 125 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkPointerDeadWindow, /* 125 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 126 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 126 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkpSetCapture, /* 126 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 127 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 127 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkpSetCursor, /* 127 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 128 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 128 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkpWmSetState, /* 128 */ +#endif /* MAC_TCL */ + NULL, /* 129 */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 130 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 130 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkGetTransientMaster, /* 130 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 131 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 131 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkGenerateButtonEvent, /* 131 */ +#endif /* MAC_TCL */ + NULL, /* 132 */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 133 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 133 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkGenWMDestroyEvent, /* 133 */ +#endif /* MAC_TCL */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 134 */ +#endif /* UNIX */ +#ifdef __WIN32__ + NULL, /* 134 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkGenWMConfigureEvent, /* 134 */ +#endif /* MAC_TCL */ + TkpDrawHighlightBorder, /* 135 */ + TkSetFocusWin, /* 136 */ + TkpSetKeycodeAndState, /* 137 */ + TkpGetKeySym, /* 138 */ + TkpInitKeymapInfo, /* 139 */ +}; + +TkIntPlatStubs tkIntPlatStubs = { + TCL_STUB_MAGIC, + NULL, +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + TkCreateXEventSource, /* 0 */ + TkFreeWindowId, /* 1 */ + TkInitXId, /* 2 */ + TkpCmapStressed, /* 3 */ + TkpSync, /* 4 */ + TkUnixContainerId, /* 5 */ + TkUnixDoOneXEvent, /* 6 */ + TkUnixSetMenubar, /* 7 */ +#endif /* UNIX */ +#ifdef __WIN32__ + TkAlignImageData, /* 0 */ + NULL, /* 1 */ + TkGenerateActivateEvents, /* 2 */ + TkpGetMS, /* 3 */ + TkPointerDeadWindow, /* 4 */ + TkpPrintWindowId, /* 5 */ + TkpScanWindowId, /* 6 */ + TkpSetCapture, /* 7 */ + TkpSetCursor, /* 8 */ + TkpWmSetState, /* 9 */ + TkSetPixmapColormap, /* 10 */ + TkWinCancelMouseTimer, /* 11 */ + TkWinClipboardRender, /* 12 */ + TkWinEmbeddedEventProc, /* 13 */ + TkWinFillRect, /* 14 */ + TkWinGetBorderPixels, /* 15 */ + TkWinGetDrawableDC, /* 16 */ + TkWinGetModifierState, /* 17 */ + TkWinGetSystemPalette, /* 18 */ + TkWinGetWrapperWindow, /* 19 */ + TkWinHandleMenuEvent, /* 20 */ + TkWinIndexOfColor, /* 21 */ + TkWinReleaseDrawableDC, /* 22 */ + TkWinResendEvent, /* 23 */ + TkWinSelectPalette, /* 24 */ + TkWinSetMenu, /* 25 */ + TkWinSetWindowPos, /* 26 */ + TkWinWmCleanup, /* 27 */ + TkWinXCleanup, /* 28 */ + TkWinXInit, /* 29 */ + TkWinSetForegroundWindow, /* 30 */ + TkWinDialogDebug, /* 31 */ + TkWinGetMenuSystemDefault, /* 32 */ + TkWinGetPlatformId, /* 33 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkGenerateActivateEvents, /* 0 */ + TkpCreateNativeBitmap, /* 1 */ + TkpDefineNativeBitmaps, /* 2 */ + TkpGetMS, /* 3 */ + NULL, /* 4 */ + TkPointerDeadWindow, /* 5 */ + TkpSetCapture, /* 6 */ + TkpSetCursor, /* 7 */ + TkpWmSetState, /* 8 */ + NULL, /* 9 */ + TkAboutDlg, /* 10 */ + NULL, /* 11 */ + NULL, /* 12 */ + TkGetTransientMaster, /* 13 */ + TkGenerateButtonEvent, /* 14 */ + NULL, /* 15 */ + TkGenWMDestroyEvent, /* 16 */ + TkGenWMConfigureEvent, /* 17 */ + TkMacButtonKeyState, /* 18 */ + TkMacClearMenubarActive, /* 19 */ + TkMacConvertEvent, /* 20 */ + TkMacDispatchMenuEvent, /* 21 */ + TkMacInstallCursor, /* 22 */ + TkMacConvertTkEvent, /* 23 */ + TkMacHandleTearoffMenu, /* 24 */ + NULL, /* 25 */ + TkMacInvalClipRgns, /* 26 */ + TkMacDoHLEvent, /* 27 */ + NULL, /* 28 */ + TkMacGenerateTime, /* 29 */ + TkMacGetDrawablePort, /* 30 */ + TkMacGetScrollbarGrowWindow, /* 31 */ + TkMacGetXWindow, /* 32 */ + TkMacGrowToplevel, /* 33 */ + TkMacHandleMenuSelect, /* 34 */ + TkMacHaveAppearance, /* 35 */ + TkMacInitAppleEvents, /* 36 */ + TkMacInitMenus, /* 37 */ + TkMacInvalidateWindow, /* 38 */ + TkMacIsCharacterMissing, /* 39 */ + TkMacMakeRealWindowExist, /* 40 */ + TkMacMakeStippleMap, /* 41 */ + TkMacMenuClick, /* 42 */ + TkMacRegisterOffScreenWindow, /* 43 */ + TkMacResizable, /* 44 */ + NULL, /* 45 */ + TkMacSetHelpMenuItemCount, /* 46 */ + TkMacSetScrollbarGrow, /* 47 */ + TkMacSetUpClippingRgn, /* 48 */ + TkMacSetUpGraphicsPort, /* 49 */ + TkMacUpdateClipRgn, /* 50 */ + TkMacUnregisterMacWindow, /* 51 */ + TkMacUseMenuID, /* 52 */ + TkMacVisableClipRgn, /* 53 */ + TkMacWinBounds, /* 54 */ + TkMacWindowOffset, /* 55 */ + NULL, /* 56 */ + TkSetMacColor, /* 57 */ + TkSetWMName, /* 58 */ + TkSuspendClipboard, /* 59 */ + NULL, /* 60 */ + TkMacZoomToplevel, /* 61 */ + Tk_TopCoordsToWindow, /* 62 */ + TkMacContainerId, /* 63 */ + TkMacGetHostToplevel, /* 64 */ + TkMacPreprocessMenu, /* 65 */ +#endif /* MAC_TCL */ +}; + +TkIntXlibStubs tkIntXlibStubs = { + TCL_STUB_MAGIC, + NULL, +#ifdef __WIN32__ + XSetDashes, /* 0 */ + XGetModifierMapping, /* 1 */ + XCreateImage, /* 2 */ + XGetImage, /* 3 */ + XGetAtomName, /* 4 */ + XKeysymToString, /* 5 */ + XCreateColormap, /* 6 */ + XCreatePixmapCursor, /* 7 */ + XCreateGlyphCursor, /* 8 */ + XGContextFromGC, /* 9 */ + XListHosts, /* 10 */ + XKeycodeToKeysym, /* 11 */ + XStringToKeysym, /* 12 */ + XRootWindow, /* 13 */ + XSetErrorHandler, /* 14 */ + XIconifyWindow, /* 15 */ + XWithdrawWindow, /* 16 */ + XGetWMColormapWindows, /* 17 */ + XAllocColor, /* 18 */ + XBell, /* 19 */ + XChangeProperty, /* 20 */ + XChangeWindowAttributes, /* 21 */ + XClearWindow, /* 22 */ + XConfigureWindow, /* 23 */ + XCopyArea, /* 24 */ + XCopyPlane, /* 25 */ + XCreateBitmapFromData, /* 26 */ + XDefineCursor, /* 27 */ + XDeleteProperty, /* 28 */ + XDestroyWindow, /* 29 */ + XDrawArc, /* 30 */ + XDrawLines, /* 31 */ + XDrawRectangle, /* 32 */ + XFillArc, /* 33 */ + XFillPolygon, /* 34 */ + XFillRectangles, /* 35 */ + XForceScreenSaver, /* 36 */ + XFreeColormap, /* 37 */ + XFreeColors, /* 38 */ + XFreeCursor, /* 39 */ + XFreeModifiermap, /* 40 */ + XGetGeometry, /* 41 */ + XGetInputFocus, /* 42 */ + XGetWindowProperty, /* 43 */ + XGetWindowAttributes, /* 44 */ + XGrabKeyboard, /* 45 */ + XGrabPointer, /* 46 */ + XKeysymToKeycode, /* 47 */ + XLookupColor, /* 48 */ + XMapWindow, /* 49 */ + XMoveResizeWindow, /* 50 */ + XMoveWindow, /* 51 */ + XNextEvent, /* 52 */ + XPutBackEvent, /* 53 */ + XQueryColors, /* 54 */ + XQueryPointer, /* 55 */ + XQueryTree, /* 56 */ + XRaiseWindow, /* 57 */ + XRefreshKeyboardMapping, /* 58 */ + XResizeWindow, /* 59 */ + XSelectInput, /* 60 */ + XSendEvent, /* 61 */ + XSetCommand, /* 62 */ + XSetIconName, /* 63 */ + XSetInputFocus, /* 64 */ + XSetSelectionOwner, /* 65 */ + XSetWindowBackground, /* 66 */ + XSetWindowBackgroundPixmap, /* 67 */ + XSetWindowBorder, /* 68 */ + XSetWindowBorderPixmap, /* 69 */ + XSetWindowBorderWidth, /* 70 */ + XSetWindowColormap, /* 71 */ + XTranslateCoordinates, /* 72 */ + XUngrabKeyboard, /* 73 */ + XUngrabPointer, /* 74 */ + XUnmapWindow, /* 75 */ + XWindowEvent, /* 76 */ + XDestroyIC, /* 77 */ + XFilterEvent, /* 78 */ + XmbLookupString, /* 79 */ + TkPutImage, /* 80 */ + NULL, /* 81 */ + XParseColor, /* 82 */ + XCreateGC, /* 83 */ + XFreeGC, /* 84 */ + XInternAtom, /* 85 */ + XSetBackground, /* 86 */ + XSetForeground, /* 87 */ + XSetClipMask, /* 88 */ + XSetClipOrigin, /* 89 */ + XSetTSOrigin, /* 90 */ + XChangeGC, /* 91 */ + XSetFont, /* 92 */ + XSetArcMode, /* 93 */ + XSetStipple, /* 94 */ + XSetFillRule, /* 95 */ + XSetFillStyle, /* 96 */ + XSetFunction, /* 97 */ + XSetLineAttributes, /* 98 */ + _XInitImageFuncPtrs, /* 99 */ + XCreateIC, /* 100 */ + XGetVisualInfo, /* 101 */ + XSetWMClientMachine, /* 102 */ + XStringListToTextProperty, /* 103 */ + XDrawLine, /* 104 */ + XWarpPointer, /* 105 */ + XFillRectangle, /* 106 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + XSetDashes, /* 0 */ + XGetModifierMapping, /* 1 */ + XCreateImage, /* 2 */ + XGetImage, /* 3 */ + XGetAtomName, /* 4 */ + XKeysymToString, /* 5 */ + XCreateColormap, /* 6 */ + XGContextFromGC, /* 7 */ + XKeycodeToKeysym, /* 8 */ + XStringToKeysym, /* 9 */ + XRootWindow, /* 10 */ + XSetErrorHandler, /* 11 */ + XAllocColor, /* 12 */ + XBell, /* 13 */ + XChangeProperty, /* 14 */ + XChangeWindowAttributes, /* 15 */ + XConfigureWindow, /* 16 */ + XCopyArea, /* 17 */ + XCopyPlane, /* 18 */ + XCreateBitmapFromData, /* 19 */ + XDefineCursor, /* 20 */ + XDestroyWindow, /* 21 */ + XDrawArc, /* 22 */ + XDrawLines, /* 23 */ + XDrawRectangle, /* 24 */ + XFillArc, /* 25 */ + XFillPolygon, /* 26 */ + XFillRectangles, /* 27 */ + XFreeColormap, /* 28 */ + XFreeColors, /* 29 */ + XFreeModifiermap, /* 30 */ + XGetGeometry, /* 31 */ + XGetWindowProperty, /* 32 */ + XGrabKeyboard, /* 33 */ + XGrabPointer, /* 34 */ + XKeysymToKeycode, /* 35 */ + XMapWindow, /* 36 */ + XMoveResizeWindow, /* 37 */ + XMoveWindow, /* 38 */ + XQueryPointer, /* 39 */ + XRaiseWindow, /* 40 */ + XRefreshKeyboardMapping, /* 41 */ + XResizeWindow, /* 42 */ + XSelectInput, /* 43 */ + XSendEvent, /* 44 */ + XSetIconName, /* 45 */ + XSetInputFocus, /* 46 */ + XSetSelectionOwner, /* 47 */ + XSetWindowBackground, /* 48 */ + XSetWindowBackgroundPixmap, /* 49 */ + XSetWindowBorder, /* 50 */ + XSetWindowBorderPixmap, /* 51 */ + XSetWindowBorderWidth, /* 52 */ + XSetWindowColormap, /* 53 */ + XUngrabKeyboard, /* 54 */ + XUngrabPointer, /* 55 */ + XUnmapWindow, /* 56 */ + TkPutImage, /* 57 */ + XParseColor, /* 58 */ + XCreateGC, /* 59 */ + XFreeGC, /* 60 */ + XInternAtom, /* 61 */ + XSetBackground, /* 62 */ + XSetForeground, /* 63 */ + XSetClipMask, /* 64 */ + XSetClipOrigin, /* 65 */ + XSetTSOrigin, /* 66 */ + XChangeGC, /* 67 */ + XSetFont, /* 68 */ + XSetArcMode, /* 69 */ + XSetStipple, /* 70 */ + XSetFillRule, /* 71 */ + XSetFillStyle, /* 72 */ + XSetFunction, /* 73 */ + XSetLineAttributes, /* 74 */ + _XInitImageFuncPtrs, /* 75 */ + XCreateIC, /* 76 */ + XGetVisualInfo, /* 77 */ + XSetWMClientMachine, /* 78 */ + XStringListToTextProperty, /* 79 */ + XDrawSegments, /* 80 */ + XForceScreenSaver, /* 81 */ + XDrawLine, /* 82 */ + XFillRectangle, /* 83 */ + XClearWindow, /* 84 */ + XDrawPoint, /* 85 */ + XDrawPoints, /* 86 */ + XWarpPointer, /* 87 */ + XQueryColor, /* 88 */ + XQueryColors, /* 89 */ +#endif /* MAC_TCL */ +}; + +TkPlatStubs tkPlatStubs = { + TCL_STUB_MAGIC, + NULL, +#ifdef __WIN32__ + Tk_AttachHWND, /* 0 */ + Tk_GetHINSTANCE, /* 1 */ + Tk_GetHWND, /* 2 */ + Tk_HWNDToWindow, /* 3 */ + Tk_PointerEvent, /* 4 */ + Tk_TranslateWinEvent, /* 5 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + Tk_MacSetEmbedHandler, /* 0 */ + Tk_MacTurnOffMenus, /* 1 */ + Tk_MacTkOwnsCursor, /* 2 */ + TkMacInitMenus, /* 3 */ + TkMacInitAppleEvents, /* 4 */ + TkMacConvertEvent, /* 5 */ + TkMacConvertTkEvent, /* 6 */ + TkGenWMConfigureEvent, /* 7 */ + TkMacInvalClipRgns, /* 8 */ + TkMacHaveAppearance, /* 9 */ + TkMacGetDrawablePort, /* 10 */ +#endif /* MAC_TCL */ +}; + +static TkStubHooks tkStubHooks = { + &tkPlatStubs, + &tkIntStubs, + &tkIntPlatStubs, + &tkIntXlibStubs +}; + +TkStubs tkStubs = { + TCL_STUB_MAGIC, + &tkStubHooks, + Tk_MainLoop, /* 0 */ + Tk_3DBorderColor, /* 1 */ + Tk_3DBorderGC, /* 2 */ + Tk_3DHorizontalBevel, /* 3 */ + Tk_3DVerticalBevel, /* 4 */ + Tk_AddOption, /* 5 */ + Tk_BindEvent, /* 6 */ + Tk_CanvasDrawableCoords, /* 7 */ + Tk_CanvasEventuallyRedraw, /* 8 */ + Tk_CanvasGetCoord, /* 9 */ + Tk_CanvasGetTextInfo, /* 10 */ + Tk_CanvasPsBitmap, /* 11 */ + Tk_CanvasPsColor, /* 12 */ + Tk_CanvasPsFont, /* 13 */ + Tk_CanvasPsPath, /* 14 */ + Tk_CanvasPsStipple, /* 15 */ + Tk_CanvasPsY, /* 16 */ + Tk_CanvasSetStippleOrigin, /* 17 */ + Tk_CanvasTagsParseProc, /* 18 */ + Tk_CanvasTagsPrintProc, /* 19 */ + Tk_CanvasTkwin, /* 20 */ + Tk_CanvasWindowCoords, /* 21 */ + Tk_ChangeWindowAttributes, /* 22 */ + Tk_CharBbox, /* 23 */ + Tk_ClearSelection, /* 24 */ + Tk_ClipboardAppend, /* 25 */ + Tk_ClipboardClear, /* 26 */ + Tk_ConfigureInfo, /* 27 */ + Tk_ConfigureValue, /* 28 */ + Tk_ConfigureWidget, /* 29 */ + Tk_ConfigureWindow, /* 30 */ + Tk_ComputeTextLayout, /* 31 */ + Tk_CoordsToWindow, /* 32 */ + Tk_CreateBinding, /* 33 */ + Tk_CreateBindingTable, /* 34 */ + Tk_CreateErrorHandler, /* 35 */ + Tk_CreateEventHandler, /* 36 */ + Tk_CreateGenericHandler, /* 37 */ + Tk_CreateImageType, /* 38 */ + Tk_CreateItemType, /* 39 */ + Tk_CreatePhotoImageFormat, /* 40 */ + Tk_CreateSelHandler, /* 41 */ + Tk_CreateWindow, /* 42 */ + Tk_CreateWindowFromPath, /* 43 */ + Tk_DefineBitmap, /* 44 */ + Tk_DefineCursor, /* 45 */ + Tk_DeleteAllBindings, /* 46 */ + Tk_DeleteBinding, /* 47 */ + Tk_DeleteBindingTable, /* 48 */ + Tk_DeleteErrorHandler, /* 49 */ + Tk_DeleteEventHandler, /* 50 */ + Tk_DeleteGenericHandler, /* 51 */ + Tk_DeleteImage, /* 52 */ + Tk_DeleteSelHandler, /* 53 */ + Tk_DestroyWindow, /* 54 */ + Tk_DisplayName, /* 55 */ + Tk_DistanceToTextLayout, /* 56 */ + Tk_Draw3DPolygon, /* 57 */ + Tk_Draw3DRectangle, /* 58 */ + Tk_DrawChars, /* 59 */ + Tk_DrawFocusHighlight, /* 60 */ + Tk_DrawTextLayout, /* 61 */ + Tk_Fill3DPolygon, /* 62 */ + Tk_Fill3DRectangle, /* 63 */ + Tk_FindPhoto, /* 64 */ + Tk_FontId, /* 65 */ + Tk_Free3DBorder, /* 66 */ + Tk_FreeBitmap, /* 67 */ + Tk_FreeColor, /* 68 */ + Tk_FreeColormap, /* 69 */ + Tk_FreeCursor, /* 70 */ + Tk_FreeFont, /* 71 */ + Tk_FreeGC, /* 72 */ + Tk_FreeImage, /* 73 */ + Tk_FreeOptions, /* 74 */ + Tk_FreePixmap, /* 75 */ + Tk_FreeTextLayout, /* 76 */ + Tk_FreeXId, /* 77 */ + Tk_GCForColor, /* 78 */ + Tk_GeometryRequest, /* 79 */ + Tk_Get3DBorder, /* 80 */ + Tk_GetAllBindings, /* 81 */ + Tk_GetAnchor, /* 82 */ + Tk_GetAtomName, /* 83 */ + Tk_GetBinding, /* 84 */ + Tk_GetBitmap, /* 85 */ + Tk_GetBitmapFromData, /* 86 */ + Tk_GetCapStyle, /* 87 */ + Tk_GetColor, /* 88 */ + Tk_GetColorByValue, /* 89 */ + Tk_GetColormap, /* 90 */ + Tk_GetCursor, /* 91 */ + Tk_GetCursorFromData, /* 92 */ + Tk_GetFont, /* 93 */ + Tk_GetFontFromObj, /* 94 */ + Tk_GetFontMetrics, /* 95 */ + Tk_GetGC, /* 96 */ + Tk_GetImage, /* 97 */ + Tk_GetImageMasterData, /* 98 */ + Tk_GetItemTypes, /* 99 */ + Tk_GetJoinStyle, /* 100 */ + Tk_GetJustify, /* 101 */ + Tk_GetNumMainWindows, /* 102 */ + Tk_GetOption, /* 103 */ + Tk_GetPixels, /* 104 */ + Tk_GetPixmap, /* 105 */ + Tk_GetRelief, /* 106 */ + Tk_GetRootCoords, /* 107 */ + Tk_GetScrollInfo, /* 108 */ + Tk_GetScreenMM, /* 109 */ + Tk_GetSelection, /* 110 */ + Tk_GetUid, /* 111 */ + Tk_GetVisual, /* 112 */ + Tk_GetVRootGeometry, /* 113 */ + Tk_Grab, /* 114 */ + Tk_HandleEvent, /* 115 */ + Tk_IdToWindow, /* 116 */ + Tk_ImageChanged, /* 117 */ + Tk_Init, /* 118 */ + Tk_InternAtom, /* 119 */ + Tk_IntersectTextLayout, /* 120 */ + Tk_MaintainGeometry, /* 121 */ + Tk_MainWindow, /* 122 */ + Tk_MakeWindowExist, /* 123 */ + Tk_ManageGeometry, /* 124 */ + Tk_MapWindow, /* 125 */ + Tk_MeasureChars, /* 126 */ + Tk_MoveResizeWindow, /* 127 */ + Tk_MoveWindow, /* 128 */ + Tk_MoveToplevelWindow, /* 129 */ + Tk_NameOf3DBorder, /* 130 */ + Tk_NameOfAnchor, /* 131 */ + Tk_NameOfBitmap, /* 132 */ + Tk_NameOfCapStyle, /* 133 */ + Tk_NameOfColor, /* 134 */ + Tk_NameOfCursor, /* 135 */ + Tk_NameOfFont, /* 136 */ + Tk_NameOfImage, /* 137 */ + Tk_NameOfJoinStyle, /* 138 */ + Tk_NameOfJustify, /* 139 */ + Tk_NameOfRelief, /* 140 */ + Tk_NameToWindow, /* 141 */ + Tk_OwnSelection, /* 142 */ + Tk_ParseArgv, /* 143 */ + Tk_PhotoPutBlock, /* 144 */ + Tk_PhotoPutZoomedBlock, /* 145 */ + Tk_PhotoGetImage, /* 146 */ + Tk_PhotoBlank, /* 147 */ + Tk_PhotoExpand, /* 148 */ + Tk_PhotoGetSize, /* 149 */ + Tk_PhotoSetSize, /* 150 */ + Tk_PointToChar, /* 151 */ + Tk_PostscriptFontName, /* 152 */ + Tk_PreserveColormap, /* 153 */ + Tk_QueueWindowEvent, /* 154 */ + Tk_RedrawImage, /* 155 */ + Tk_ResizeWindow, /* 156 */ + Tk_RestackWindow, /* 157 */ + Tk_RestrictEvents, /* 158 */ + Tk_SafeInit, /* 159 */ + Tk_SetAppName, /* 160 */ + Tk_SetBackgroundFromBorder, /* 161 */ + Tk_SetClass, /* 162 */ + Tk_SetGrid, /* 163 */ + Tk_SetInternalBorder, /* 164 */ + Tk_SetWindowBackground, /* 165 */ + Tk_SetWindowBackgroundPixmap, /* 166 */ + Tk_SetWindowBorder, /* 167 */ + Tk_SetWindowBorderWidth, /* 168 */ + Tk_SetWindowBorderPixmap, /* 169 */ + Tk_SetWindowColormap, /* 170 */ + Tk_SetWindowVisual, /* 171 */ + Tk_SizeOfBitmap, /* 172 */ + Tk_SizeOfImage, /* 173 */ + Tk_StrictMotif, /* 174 */ + Tk_TextLayoutToPostscript, /* 175 */ + Tk_TextWidth, /* 176 */ + Tk_UndefineCursor, /* 177 */ + Tk_UnderlineChars, /* 178 */ + Tk_UnderlineTextLayout, /* 179 */ + Tk_Ungrab, /* 180 */ + Tk_UnmaintainGeometry, /* 181 */ + Tk_UnmapWindow, /* 182 */ + Tk_UnsetGrid, /* 183 */ + Tk_UpdatePointer, /* 184 */ + Tk_AllocBitmapFromObj, /* 185 */ + Tk_Alloc3DBorderFromObj, /* 186 */ + Tk_AllocColorFromObj, /* 187 */ + Tk_AllocCursorFromObj, /* 188 */ + Tk_AllocFontFromObj, /* 189 */ + Tk_CreateOptionTable, /* 190 */ + Tk_DeleteOptionTable, /* 191 */ + Tk_Free3DBorderFromObj, /* 192 */ + Tk_FreeBitmapFromObj, /* 193 */ + Tk_FreeColorFromObj, /* 194 */ + Tk_FreeConfigOptions, /* 195 */ + Tk_FreeSavedOptions, /* 196 */ + Tk_FreeCursorFromObj, /* 197 */ + Tk_FreeFontFromObj, /* 198 */ + Tk_Get3DBorderFromObj, /* 199 */ + Tk_GetAnchorFromObj, /* 200 */ + Tk_GetBitmapFromObj, /* 201 */ + Tk_GetColorFromObj, /* 202 */ + Tk_GetCursorFromObj, /* 203 */ + Tk_GetOptionInfo, /* 204 */ + Tk_GetOptionValue, /* 205 */ + Tk_GetJustifyFromObj, /* 206 */ + Tk_GetMMFromObj, /* 207 */ + Tk_GetPixelsFromObj, /* 208 */ + Tk_GetReliefFromObj, /* 209 */ + Tk_GetScrollInfoObj, /* 210 */ + Tk_InitOptions, /* 211 */ + Tk_MainEx, /* 212 */ + Tk_RestoreSavedOptions, /* 213 */ + Tk_SetOptions, /* 214 */ + Tk_InitConsoleChannels, /* 215 */ + Tk_CreateConsoleWindow, /* 216 */ + Tk_CreateSmoothMethod, /* 217 */ + NULL, /* 218 */ + NULL, /* 219 */ + Tk_GetDash, /* 220 */ + Tk_CreateOutline, /* 221 */ + Tk_DeleteOutline, /* 222 */ + Tk_ConfigOutlineGC, /* 223 */ + Tk_ChangeOutlineGC, /* 224 */ + Tk_ResetOutlineGC, /* 225 */ + Tk_CanvasPsOutline, /* 226 */ + Tk_SetTSOrigin, /* 227 */ + Tk_CanvasGetCoordFromObj, /* 228 */ + Tk_CanvasSetOffset, /* 229 */ + Tk_DitherPhoto, /* 230 */ + Tk_PostscriptBitmap, /* 231 */ + Tk_PostscriptColor, /* 232 */ + Tk_PostscriptFont, /* 233 */ + Tk_PostscriptImage, /* 234 */ + Tk_PostscriptPath, /* 235 */ + Tk_PostscriptStipple, /* 236 */ + Tk_PostscriptY, /* 237 */ + Tk_PostscriptPhoto, /* 238 */ +}; + +/* !END!: Do not edit above this line. */ diff --git a/tk/generic/tkStubLib.c b/tk/generic/tkStubLib.c new file mode 100644 index 00000000000..7a9e7bd0d53 --- /dev/null +++ b/tk/generic/tkStubLib.c @@ -0,0 +1,110 @@ +/* + * tkStubLib.c -- + * + * Stub object that will be statically linked into extensions that wish + * to access Tk. + * + * Copyright (c) 1998 Paul Duffin. + * Copyright (c) 1998-1999 by Scriptics Corporation. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +/* + * We need to ensure that we use the stub macros so that this file contains + * no references to any of the stub functions. This will make it possible + * to build an extension that references Tk_InitStubs but doesn't end up + * including the rest of the stub functions. + */ + + +#ifndef USE_TCL_STUBS +#define USE_TCL_STUBS +#endif +#undef USE_TCL_STUB_PROCS + +#ifndef USE_TK_STUBS +#define USE_TK_STUBS +#endif +#undef USE_TK_STUB_PROCS + +#include "tkPort.h" +#include "tkInt.h" + +#ifdef __WIN32__ +#include "tkWinInt.h" +#endif +#ifdef MAC_TCL +#include "tkMacInt.h" +#endif + +#include "tkDecls.h" +#include "tkIntDecls.h" +#include "tkPlatDecls.h" +#include "tkIntPlatDecls.h" +#include "tkIntXlibDecls.h" + +/* + * Ensure that Tk_InitStubs is built as an exported symbol. The other stub + * functions should be built as non-exported symbols. + */ + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLEXPORT + +TkStubs *tkStubsPtr; +TkPlatStubs *tkPlatStubsPtr; +TkIntStubs *tkIntStubsPtr; +TkIntPlatStubs *tkIntPlatStubsPtr; +TkIntXlibStubs *tkIntXlibStubsPtr; + + +/* + *---------------------------------------------------------------------- + * + * Tk_InitStubs -- + * + * Checks that the correct version of Tk is loaded and that it + * supports stubs. It then initialises the stub table pointers. + * + * Results: + * The actual version of Tk that satisfies the request, or + * NULL to indicate that an error occurred. + * + * Side effects: + * Sets the stub table pointers. + * + *---------------------------------------------------------------------- + */ + +char * +Tk_InitStubs(interp, version, exact) + Tcl_Interp *interp; + char *version; + int exact; +{ + char *actualVersion; + + actualVersion = Tcl_PkgRequireEx(interp, "Tk", version, exact, + (ClientData *) &tkStubsPtr); + if (!actualVersion) { + return NULL; + } + + if (!tkStubsPtr) { + Tcl_SetResult(interp, + "This implementation of Tk does not support stubs", + TCL_STATIC); + return NULL; + } + + tkPlatStubsPtr = tkStubsPtr->hooks->tkPlatStubs; + tkIntStubsPtr = tkStubsPtr->hooks->tkIntStubs; + tkIntPlatStubsPtr = tkStubsPtr->hooks->tkIntPlatStubs; + tkIntXlibStubsPtr = tkStubsPtr->hooks->tkIntXlibStubs; + + return actualVersion; +} diff --git a/tk/generic/tkTest.c b/tk/generic/tkTest.c index e33d6b62853..7fd0d5125b4 100644 --- a/tk/generic/tkTest.c +++ b/tk/generic/tkTest.c @@ -8,6 +8,7 @@ * * Copyright (c) 1993-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -16,7 +17,8 @@ */ #include "tkInt.h" -#include "tkPort.h" +#include "tkPort.h" +#include "tkText.h" #ifdef __WIN32__ #include "tkWinInt.h" @@ -59,10 +61,17 @@ typedef struct TImageInstance { * The type record for test images: */ +#ifdef USE_OLD_IMAGE +static int ImageCreate _ANSI_ARGS_((Tcl_Interp *interp, + char *name, int argc, char **argv, + Tk_ImageType *typePtr, Tk_ImageMaster master, + ClientData *clientDataPtr)); +#else static int ImageCreate _ANSI_ARGS_((Tcl_Interp *interp, char *name, int argc, Tcl_Obj *CONST objv[], Tk_ImageType *typePtr, Tk_ImageMaster master, ClientData *clientDataPtr)); +#endif static ClientData ImageGet _ANSI_ARGS_((Tk_Window tkwin, ClientData clientData)); static void ImageDisplay _ANSI_ARGS_((ClientData clientData, @@ -76,11 +85,12 @@ static void ImageDelete _ANSI_ARGS_((ClientData clientData)); static Tk_ImageType imageType = { "test", /* name */ - ImageCreate, /* createProc */ + (Tk_ImageCreateProc *) ImageCreate, /* createProc */ ImageGet, /* getProc */ ImageDisplay, /* displayProc */ ImageFree, /* freeProc */ ImageDelete, /* deleteProc */ + (Tk_ImagePostscriptProc *) NULL,/* postscriptPtr */ (Tk_ImageType *) NULL /* nextPtr */ }; @@ -102,8 +112,8 @@ static NewApp *newAppPtr = NULL; * Declaration for the square widget's class command procedure: */ -extern int SquareCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int argc, char *argv[])); +extern int SquareObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])); typedef struct CBinding { Tcl_Interp *interp; @@ -112,6 +122,32 @@ typedef struct CBinding { } CBinding; /* + * Header for trivial configuration command items. + */ + +#define ODD TK_CONFIG_USER_BIT +#define EVEN (TK_CONFIG_USER_BIT << 1) + +enum { + NONE, + ODD_TYPE, + EVEN_TYPE +}; + +typedef struct TrivialCommandHeader { + Tcl_Interp *interp; /* The interp that this command + * lives in. */ + Tk_OptionTable optionTable; /* The option table that go with + * this command. */ + Tk_Window tkwin; /* For widgets, the window associated + * with this widget. */ + Tcl_Command widgetCmd; /* For widgets, the command associated + * with this widget. */ +} TrivialCommandHeader; + + + +/* * Forward declarations for procedures defined later in this file: */ @@ -124,12 +160,23 @@ static int ImageCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, char **argv)); static int TestcbindCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, char **argv)); -#ifdef __WIN32__ -static int TestclipboardCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, char **argv)); -#endif +static int TestbitmapObjCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj * CONST objv[])); +static int TestborderObjCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj * CONST objv[])); +static int TestcolorObjCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj * CONST objv[])); +static int TestcursorObjCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj * CONST objv[])); static int TestdeleteappsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, char **argv)); +static int TestfontObjCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); static int TestmakeexistCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, char **argv)); static int TestmenubarCmd _ANSI_ARGS_((ClientData dummy, @@ -138,22 +185,35 @@ static int TestmenubarCmd _ANSI_ARGS_((ClientData dummy, static int TestmetricsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, char **argv)); #endif +static int TestobjconfigObjCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj * CONST objv[])); +static int TestpropCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int argc, char **argv)); static int TestsendCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, char **argv)); -static int TestpropCmd _ANSI_ARGS_((ClientData dummy, +static int TesttextCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, char **argv)); #if !(defined(__WIN32__) || defined(MAC_TCL)) static int TestwrapperCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, char **argv)); #endif +static void TrivialCmdDeletedProc _ANSI_ARGS_(( + ClientData clientData)); +static int TrivialConfigObjCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj * CONST objv[])); +static void TrivialEventProc _ANSI_ARGS_((ClientData clientData, + XEvent *eventPtr)); /* * External (platform specific) initialization routine: */ -EXTERN int TkplatformtestInit _ANSI_ARGS_(( - Tcl_Interp *interp)); -#ifndef MAC_TCL +extern int TkplatformtestInit _ANSI_ARGS_((Tcl_Interp *interp)); +extern int TclThread_Init _ANSI_ARGS_((Tcl_Interp *interp)); + +#if !(defined(__WIN32__) || defined(MAC_TCL)) #define TkplatformtestInit(x) TCL_OK #endif @@ -167,7 +227,7 @@ EXTERN int TkplatformtestInit _ANSI_ARGS_(( * * Results: * Returns a standard Tcl completion code, and leaves an error - * message in interp->result if an error occurs. + * message in the interp's result if an error occurs. * * Side effects: * Creates several test commands. @@ -189,18 +249,26 @@ Tktest_Init(interp) return TCL_ERROR; } - Tcl_CreateCommand(interp, "square", SquareCmd, + Tcl_CreateObjCommand(interp, "square", SquareObjCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, "testcbind", TestcbindCmd, (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); -#ifdef __WIN32__ - Tcl_CreateCommand(interp, "testclipboard", TestclipboardCmd, + Tcl_CreateObjCommand(interp, "testbitmap", TestbitmapObjCmd, (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); -#endif - Tcl_CreateCommand(interp, "testcbind", TestcbindCmd, + Tcl_CreateObjCommand(interp, "testborder", TestborderObjCmd, + (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "testcolor", TestcolorObjCmd, + (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "testcursor", TestcursorObjCmd, (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testdeleteapps", TestdeleteappsCmd, (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testembed", TkpTestembedCmd, (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "testobjconfig", TestobjconfigObjCmd, + (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "testfont", TestfontObjCmd, + (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testmakeexist", TestmakeexistCmd, (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testmenubar", TestmenubarCmd, @@ -213,12 +281,20 @@ Tktest_Init(interp) (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testsend", TestsendCmd, (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, "testtext", TesttextCmd, + (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); #if !(defined(__WIN32__) || defined(MAC_TCL)) Tcl_CreateCommand(interp, "testwrapper", TestwrapperCmd, (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL); #endif -/* +#ifdef TCL_THREADS + if (TclThread_Init(interp) != TCL_OK) { + return TCL_ERROR; + } +#endif + + /* * Create test image type. */ @@ -237,48 +313,6 @@ Tktest_Init(interp) /* *---------------------------------------------------------------------- * - * TestclipboardCmd -- - * - * This procedure implements the testclipboard command. It provides - * a way to determine the actual contents of the Windows clipboard. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -#ifdef __WIN32__ -static int -TestclipboardCmd(clientData, interp, argc, argv) - ClientData clientData; /* Main window for application. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ -{ - TkWindow *winPtr = (TkWindow *) clientData; - HGLOBAL handle; - char *data; - - if (OpenClipboard(NULL)) { - handle = GetClipboardData(CF_TEXT); - if (handle != NULL) { - data = GlobalLock(handle); - Tcl_AppendResult(interp, data, (char *) NULL); - GlobalUnlock(handle); - } - CloseClipboard(); - } - return TCL_OK; -} -#endif - -/* - *---------------------------------------------------------------------- - * * TestcbindCmd -- * * This procedure implements the "testcbinding" command. It provides @@ -386,6 +420,146 @@ CBindingFreeProc(clientData) /* *---------------------------------------------------------------------- * + * TestbitmapObjCmd -- + * + * This procedure implements the "testbitmap" command, which is used + * to test color resource handling in tkBitmap tmp.c. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +TestbitmapObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Main window for application. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "bitmap"); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, TkDebugBitmap(Tk_MainWindow(interp), + Tcl_GetString(objv[1]))); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TestborderObjCmd -- + * + * This procedure implements the "testborder" command, which is used + * to test color resource handling in tkBorder.c. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +TestborderObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Main window for application. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "border"); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, TkDebugBorder(Tk_MainWindow(interp), + Tcl_GetString(objv[1]))); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TestcolorObjCmd -- + * + * This procedure implements the "testcolor" command, which is used + * to test color resource handling in tkColor.c. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +TestcolorObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Main window for application. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "color"); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, TkDebugColor(Tk_MainWindow(interp), + Tcl_GetString(objv[1]))); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TestcursorObjCmd -- + * + * This procedure implements the "testcursor" command, which is used + * to test color resource handling in tkCursor.c. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +TestcursorObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Main window for application. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "cursor"); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, TkDebugCursor(Tk_MainWindow(interp), + Tcl_GetString(objv[1]))); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * TestdeleteappsCmd -- * * This procedure implements the "testdeleteapps" command. It cleans @@ -424,6 +598,956 @@ TestdeleteappsCmd(clientData, interp, argc, argv) /* *---------------------------------------------------------------------- * + * TestobjconfigObjCmd -- + * + * This procedure implements the "testobjconfig" command, + * which is used to test the procedures in tkConfig.c. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +TestobjconfigObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Main window for application. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + static char *options[] = {"alltypes", "chain1", "chain2", + "configerror", "delete", "info", "internal", "new", + "notenoughparams", "twowindows", (char *) NULL}; + enum { + ALL_TYPES, + CHAIN1, + CHAIN2, + CONFIG_ERROR, + DEL, /* Can't use DELETE: VC++ compiler barfs. */ + INFO, + INTERNAL, + NEW, + NOT_ENOUGH_PARAMS, + TWO_WINDOWS + }; + static Tk_OptionTable tables[11]; /* Holds pointers to option tables + * created by commands below; indexed + * with same values as "options" + * array. */ + Tk_Window mainWin = (Tk_Window) clientData; + Tk_Window tkwin; + int index, result = TCL_OK; + + /* + * Structures used by the "chain1" subcommand and also shared by + * the "chain2" subcommand: + */ + + typedef struct ExtensionWidgetRecord { + TrivialCommandHeader header; + Tcl_Obj *base1ObjPtr; + Tcl_Obj *base2ObjPtr; + Tcl_Obj *extension3ObjPtr; + Tcl_Obj *extension4ObjPtr; + Tcl_Obj *extension5ObjPtr; + } ExtensionWidgetRecord; + static Tk_OptionSpec baseSpecs[] = { + {TK_OPTION_STRING, + "-one", "one", "One", "one", + Tk_Offset(ExtensionWidgetRecord, base1ObjPtr), -1}, + {TK_OPTION_STRING, + "-two", "two", "Two", "two", + Tk_Offset(ExtensionWidgetRecord, base2ObjPtr), -1}, + {TK_OPTION_END} + }; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "command"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[1], options, "command", 0, &index) + != TCL_OK) { + return TCL_ERROR; + } + + switch (index) { + case ALL_TYPES: { + typedef struct TypesRecord { + TrivialCommandHeader header; + Tcl_Obj *booleanPtr; + Tcl_Obj *integerPtr; + Tcl_Obj *doublePtr; + Tcl_Obj *stringPtr; + Tcl_Obj *stringTablePtr; + Tcl_Obj *colorPtr; + Tcl_Obj *fontPtr; + Tcl_Obj *bitmapPtr; + Tcl_Obj *borderPtr; + Tcl_Obj *reliefPtr; + Tcl_Obj *cursorPtr; + Tcl_Obj *activeCursorPtr; + Tcl_Obj *justifyPtr; + Tcl_Obj *anchorPtr; + Tcl_Obj *pixelPtr; + Tcl_Obj *mmPtr; + } TypesRecord; + TypesRecord *recordPtr; + static char *stringTable[] = {"one", "two", "three", "four", + (char *) NULL}; + static Tk_OptionSpec typesSpecs[] = { + {TK_OPTION_BOOLEAN, + "-boolean", "boolean", "Boolean", + "1", Tk_Offset(TypesRecord, booleanPtr), -1, 0, 0, 0x1}, + {TK_OPTION_INT, + "-integer", "integer", "Integer", + "7", Tk_Offset(TypesRecord, integerPtr), -1, 0, 0, 0x2}, + {TK_OPTION_DOUBLE, + "-double", "double", "Double", + "3.14159", Tk_Offset(TypesRecord, doublePtr), -1, 0, 0, + 0x4}, + {TK_OPTION_STRING, + "-string", "string", "String", + "foo", Tk_Offset(TypesRecord, stringPtr), -1, + TK_CONFIG_NULL_OK, 0, 0x8}, + {TK_OPTION_STRING_TABLE, + "-stringtable", "StringTable", "stringTable", + "one", Tk_Offset(TypesRecord, stringTablePtr), -1, + TK_CONFIG_NULL_OK, (ClientData) stringTable, 0x10}, + {TK_OPTION_COLOR, + "-color", "color", "Color", + "red", Tk_Offset(TypesRecord, colorPtr), -1, + TK_CONFIG_NULL_OK, (ClientData) "black", 0x20}, + {TK_OPTION_FONT, + "-font", "font", "Font", + "Helvetica 12", + Tk_Offset(TypesRecord, fontPtr), -1, + TK_CONFIG_NULL_OK, 0, 0x40}, + {TK_OPTION_BITMAP, + "-bitmap", "bitmap", "Bitmap", + "gray50", + Tk_Offset(TypesRecord, bitmapPtr), -1, + TK_CONFIG_NULL_OK, 0, 0x80}, + {TK_OPTION_BORDER, + "-border", "border", "Border", + "blue", Tk_Offset(TypesRecord, borderPtr), -1, + TK_CONFIG_NULL_OK, (ClientData) "white", 0x100}, + {TK_OPTION_RELIEF, + "-relief", "relief", "Relief", + "raised", + Tk_Offset(TypesRecord, reliefPtr), -1, + TK_CONFIG_NULL_OK, 0, 0x200}, + {TK_OPTION_CURSOR, + "-cursor", "cursor", "Cursor", + "xterm", + Tk_Offset(TypesRecord, cursorPtr), -1, + TK_CONFIG_NULL_OK, 0, 0x400}, + {TK_OPTION_JUSTIFY, + "-justify", (char *) NULL, (char *) NULL, + "left", + Tk_Offset(TypesRecord, justifyPtr), -1, + TK_CONFIG_NULL_OK, 0, 0x800}, + {TK_OPTION_ANCHOR, + "-anchor", "anchor", "Anchor", + (char *) NULL, + Tk_Offset(TypesRecord, anchorPtr), -1, + TK_CONFIG_NULL_OK, 0, 0x1000}, + {TK_OPTION_PIXELS, + "-pixel", "pixel", "Pixel", + "1", Tk_Offset(TypesRecord, pixelPtr), -1, + TK_CONFIG_NULL_OK, 0, 0x2000}, + {TK_OPTION_SYNONYM, + "-synonym", (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) "-color", + 0x8000}, + {TK_OPTION_END} + }; + Tk_OptionTable optionTable; + Tk_Window tkwin; + optionTable = Tk_CreateOptionTable(interp, + typesSpecs); + tables[index] = optionTable; + tkwin = Tk_CreateWindowFromPath(interp, (Tk_Window) clientData, + Tcl_GetStringFromObj(objv[2], NULL), (char *) NULL); + if (tkwin == NULL) { + return TCL_ERROR; + } + Tk_SetClass(tkwin, "Test"); + + recordPtr = (TypesRecord *) ckalloc(sizeof(TypesRecord)); + recordPtr->header.interp = interp; + recordPtr->header.optionTable = optionTable; + recordPtr->header.tkwin = tkwin; + recordPtr->booleanPtr = NULL; + recordPtr->integerPtr = NULL; + recordPtr->doublePtr = NULL; + recordPtr->stringPtr = NULL; + recordPtr->colorPtr = NULL; + recordPtr->fontPtr = NULL; + recordPtr->bitmapPtr = NULL; + recordPtr->borderPtr = NULL; + recordPtr->reliefPtr = NULL; + recordPtr->cursorPtr = NULL; + recordPtr->justifyPtr = NULL; + recordPtr->anchorPtr = NULL; + recordPtr->pixelPtr = NULL; + recordPtr->mmPtr = NULL; + recordPtr->stringTablePtr = NULL; + result = Tk_InitOptions(interp, (char *) recordPtr, optionTable, + tkwin); + if (result == TCL_OK) { + recordPtr->header.widgetCmd = Tcl_CreateObjCommand(interp, + Tcl_GetStringFromObj(objv[2], NULL), + TrivialConfigObjCmd, (ClientData) recordPtr, + TrivialCmdDeletedProc); + Tk_CreateEventHandler(tkwin, StructureNotifyMask, + TrivialEventProc, (ClientData) recordPtr); + result = Tk_SetOptions(interp, (char *) recordPtr, + optionTable, objc - 3, objv + 3, tkwin, + (Tk_SavedOptions *) NULL, (int *) NULL); + if (result != TCL_OK) { + Tk_DestroyWindow(tkwin); + } + } else { + Tk_DestroyWindow(tkwin); + ckfree((char *) recordPtr); + } + if (result == TCL_OK) { + Tcl_SetObjResult(interp, objv[2]); + } + break; + } + + case CHAIN1: { + ExtensionWidgetRecord *recordPtr; + Tk_Window tkwin; + Tk_OptionTable optionTable; + + tkwin = Tk_CreateWindowFromPath(interp, (Tk_Window) clientData, + Tcl_GetStringFromObj(objv[2], NULL), (char *) NULL); + if (tkwin == NULL) { + return TCL_ERROR; + } + Tk_SetClass(tkwin, "Test"); + optionTable = Tk_CreateOptionTable(interp, baseSpecs); + tables[index] = optionTable; + + recordPtr = (ExtensionWidgetRecord *) ckalloc( + sizeof(ExtensionWidgetRecord)); + recordPtr->header.interp = interp; + recordPtr->header.optionTable = optionTable; + recordPtr->header.tkwin = tkwin; + recordPtr->base1ObjPtr = recordPtr->base2ObjPtr = NULL; + recordPtr->extension3ObjPtr = recordPtr->extension4ObjPtr = NULL; + result = Tk_InitOptions(interp, (char *) recordPtr, optionTable, + tkwin); + if (result == TCL_OK) { + result = Tk_SetOptions(interp, (char *) recordPtr, optionTable, + objc - 3, objv + 3, tkwin, (Tk_SavedOptions *) NULL, + (int *) NULL); + if (result != TCL_OK) { + Tk_FreeConfigOptions((char *) recordPtr, optionTable, + tkwin); + } + } + if (result == TCL_OK) { + recordPtr->header.widgetCmd = Tcl_CreateObjCommand(interp, + Tcl_GetStringFromObj(objv[2], NULL), + TrivialConfigObjCmd, (ClientData) recordPtr, + TrivialCmdDeletedProc); + Tk_CreateEventHandler(tkwin, StructureNotifyMask, + TrivialEventProc, (ClientData) recordPtr); + Tcl_SetObjResult(interp, objv[2]); + } + break; + } + + case CHAIN2: { + ExtensionWidgetRecord *recordPtr; + static Tk_OptionSpec extensionSpecs[] = { + {TK_OPTION_STRING, + "-three", "three", "Three", "three", + Tk_Offset(ExtensionWidgetRecord, extension3ObjPtr), + -1}, + {TK_OPTION_STRING, + "-four", "four", "Four", "four", + Tk_Offset(ExtensionWidgetRecord, extension4ObjPtr), + -1}, + {TK_OPTION_STRING, + "-two", "two", "Two", "two and a half", + Tk_Offset(ExtensionWidgetRecord, base2ObjPtr), + -1}, + {TK_OPTION_STRING, + "-oneAgain", "oneAgain", "OneAgain", "one again", + Tk_Offset(ExtensionWidgetRecord, extension5ObjPtr), + -1}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, (ClientData) baseSpecs} + }; + Tk_Window tkwin; + Tk_OptionTable optionTable; + + tkwin = Tk_CreateWindowFromPath(interp, (Tk_Window) clientData, + Tcl_GetStringFromObj(objv[2], NULL), (char *) NULL); + if (tkwin == NULL) { + return TCL_ERROR; + } + Tk_SetClass(tkwin, "Test"); + optionTable = Tk_CreateOptionTable(interp, extensionSpecs); + tables[index] = optionTable; + + recordPtr = (ExtensionWidgetRecord *) ckalloc( + sizeof(ExtensionWidgetRecord)); + recordPtr->header.interp = interp; + recordPtr->header.optionTable = optionTable; + recordPtr->header.tkwin = tkwin; + recordPtr->base1ObjPtr = recordPtr->base2ObjPtr = NULL; + recordPtr->extension3ObjPtr = recordPtr->extension4ObjPtr = NULL; + recordPtr->extension5ObjPtr = NULL; + result = Tk_InitOptions(interp, (char *) recordPtr, optionTable, + tkwin); + if (result == TCL_OK) { + result = Tk_SetOptions(interp, (char *) recordPtr, optionTable, + objc - 3, objv + 3, tkwin, (Tk_SavedOptions *) NULL, + (int *) NULL); + if (result != TCL_OK) { + Tk_FreeConfigOptions((char *) recordPtr, optionTable, + tkwin); + } + } + if (result == TCL_OK) { + recordPtr->header.widgetCmd = Tcl_CreateObjCommand(interp, + Tcl_GetStringFromObj(objv[2], NULL), + TrivialConfigObjCmd, (ClientData) recordPtr, + TrivialCmdDeletedProc); + Tk_CreateEventHandler(tkwin, StructureNotifyMask, + TrivialEventProc, (ClientData) recordPtr); + Tcl_SetObjResult(interp, objv[2]); + } + break; + } + + case CONFIG_ERROR: { + typedef struct ErrorWidgetRecord { + Tcl_Obj *intPtr; + } ErrorWidgetRecord; + ErrorWidgetRecord widgetRecord; + static Tk_OptionSpec errorSpecs[] = { + {TK_OPTION_INT, + "-int", "integer", "Integer", + "bogus", Tk_Offset(ErrorWidgetRecord, intPtr)}, + {TK_OPTION_END} + }; + Tk_OptionTable optionTable; + + widgetRecord.intPtr = NULL; + optionTable = Tk_CreateOptionTable(interp, errorSpecs); + tables[index] = optionTable; + return Tk_InitOptions(interp, (char *) &widgetRecord, optionTable, + (Tk_Window) NULL); + } + + case DEL: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tableName"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[2], options, "table", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + if (tables[index] != NULL) { + Tk_DeleteOptionTable(tables[index]); + } + break; + } + + case INFO: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tableName"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[2], options, "table", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, TkDebugConfig(interp, tables[index])); + break; + } + + case INTERNAL: { + /* + * This command is similar to the "alltypes" command except + * that it stores all the configuration options as internal + * forms instead of objects. + */ + + typedef struct InternalRecord { + TrivialCommandHeader header; + int boolean; + int integer; + double doubleValue; + char *string; + int index; + XColor *colorPtr; + Tk_Font tkfont; + Pixmap bitmap; + Tk_3DBorder border; + int relief; + Tk_Cursor cursor; + Tk_Justify justify; + Tk_Anchor anchor; + int pixels; + double mm; + Tk_Window tkwin; + } InternalRecord; + InternalRecord *recordPtr; + static char *internalStringTable[] = { + "one", "two", "three", "four", (char *) NULL + }; + static Tk_OptionSpec internalSpecs[] = { + {TK_OPTION_BOOLEAN, + "-boolean", "boolean", "Boolean", + "1", -1, Tk_Offset(InternalRecord, boolean), 0, 0, 0x1}, + {TK_OPTION_INT, + "-integer", "integer", "Integer", + "148962237", -1, Tk_Offset(InternalRecord, integer), + 0, 0, 0x2}, + {TK_OPTION_DOUBLE, + "-double", "double", "Double", + "3.14159", -1, Tk_Offset(InternalRecord, doubleValue), + 0, 0, 0x4}, + {TK_OPTION_STRING, + "-string", "string", "String", + "foo", -1, Tk_Offset(InternalRecord, string), + TK_CONFIG_NULL_OK, 0, 0x8}, + {TK_OPTION_STRING_TABLE, + "-stringtable", "StringTable", "stringTable", + "one", -1, Tk_Offset(InternalRecord, index), + TK_CONFIG_NULL_OK, (ClientData) internalStringTable, + 0x10}, + {TK_OPTION_COLOR, + "-color", "color", "Color", + "red", -1, Tk_Offset(InternalRecord, colorPtr), + TK_CONFIG_NULL_OK, (ClientData) "black", 0x20}, + {TK_OPTION_FONT, + "-font", "font", "Font", + "Helvetica 12", -1, Tk_Offset(InternalRecord, tkfont), + TK_CONFIG_NULL_OK, 0, 0x40}, + {TK_OPTION_BITMAP, + "-bitmap", "bitmap", "Bitmap", + "gray50", -1, Tk_Offset(InternalRecord, bitmap), + TK_CONFIG_NULL_OK, 0, 0x80}, + {TK_OPTION_BORDER, + "-border", "border", "Border", + "blue", -1, Tk_Offset(InternalRecord, border), + TK_CONFIG_NULL_OK, (ClientData) "white", 0x100}, + {TK_OPTION_RELIEF, + "-relief", "relief", "Relief", + "raised", -1, Tk_Offset(InternalRecord, relief), + TK_CONFIG_NULL_OK, 0, 0x200}, + {TK_OPTION_CURSOR, + "-cursor", "cursor", "Cursor", + "xterm", -1, Tk_Offset(InternalRecord, cursor), + TK_CONFIG_NULL_OK, 0, 0x400}, + {TK_OPTION_JUSTIFY, + "-justify", (char *) NULL, (char *) NULL, + "left", -1, Tk_Offset(InternalRecord, justify), + TK_CONFIG_NULL_OK, 0, 0x800}, + {TK_OPTION_ANCHOR, + "-anchor", "anchor", "Anchor", + (char *) NULL, -1, Tk_Offset(InternalRecord, anchor), + TK_CONFIG_NULL_OK, 0, 0x1000}, + {TK_OPTION_PIXELS, + "-pixel", "pixel", "Pixel", + "1", -1, Tk_Offset(InternalRecord, pixels), + TK_CONFIG_NULL_OK, 0, 0x2000}, + {TK_OPTION_WINDOW, + "-window", "window", "Window", + (char *) NULL, -1, Tk_Offset(InternalRecord, tkwin), + TK_CONFIG_NULL_OK, 0, 0}, + {TK_OPTION_SYNONYM, + "-synonym", (char *) NULL, (char *) NULL, + (char *) NULL, -1, -1, 0, (ClientData) "-color", + 0x8000}, + {TK_OPTION_END} + }; + Tk_OptionTable optionTable; + Tk_Window tkwin; + optionTable = Tk_CreateOptionTable(interp, internalSpecs); + tables[index] = optionTable; + tkwin = Tk_CreateWindowFromPath(interp, (Tk_Window) clientData, + Tcl_GetStringFromObj(objv[2], NULL), (char *) NULL); + if (tkwin == NULL) { + return TCL_ERROR; + } + Tk_SetClass(tkwin, "Test"); + + recordPtr = (InternalRecord *) ckalloc(sizeof(InternalRecord)); + recordPtr->header.interp = interp; + recordPtr->header.optionTable = optionTable; + recordPtr->header.tkwin = tkwin; + recordPtr->boolean = 0; + recordPtr->integer = 0; + recordPtr->doubleValue = 0.0; + recordPtr->string = NULL; + recordPtr->index = 0; + recordPtr->colorPtr = NULL; + recordPtr->tkfont = NULL; + recordPtr->bitmap = None; + recordPtr->border = NULL; + recordPtr->relief = TK_RELIEF_FLAT; + recordPtr->cursor = NULL; + recordPtr->justify = TK_JUSTIFY_LEFT; + recordPtr->anchor = TK_ANCHOR_N; + recordPtr->pixels = 0; + recordPtr->mm = 0.0; + recordPtr->tkwin = NULL; + result = Tk_InitOptions(interp, (char *) recordPtr, optionTable, + tkwin); + if (result == TCL_OK) { + recordPtr->header.widgetCmd = Tcl_CreateObjCommand(interp, + Tcl_GetStringFromObj(objv[2], NULL), + TrivialConfigObjCmd, (ClientData) recordPtr, + TrivialCmdDeletedProc); + Tk_CreateEventHandler(tkwin, StructureNotifyMask, + TrivialEventProc, (ClientData) recordPtr); + result = Tk_SetOptions(interp, (char *) recordPtr, + optionTable, objc - 3, objv + 3, tkwin, + (Tk_SavedOptions *) NULL, (int *) NULL); + if (result != TCL_OK) { + Tk_DestroyWindow(tkwin); + } + } else { + Tk_DestroyWindow(tkwin); + ckfree((char *) recordPtr); + } + if (result == TCL_OK) { + Tcl_SetObjResult(interp, objv[2]); + } + break; + } + + case NEW: { + typedef struct FiveRecord { + TrivialCommandHeader header; + Tcl_Obj *one; + Tcl_Obj *two; + Tcl_Obj *three; + Tcl_Obj *four; + Tcl_Obj *five; + } FiveRecord; + FiveRecord *recordPtr; + static Tk_OptionSpec smallSpecs[] = { + {TK_OPTION_INT, + "-one", "one", "One", + "1", + Tk_Offset(FiveRecord, one), -1}, + {TK_OPTION_INT, + "-two", "two", "Two", + "2", + Tk_Offset(FiveRecord, two), -1}, + {TK_OPTION_INT, + "-three", "three", "Three", + "3", + Tk_Offset(FiveRecord, three), -1}, + {TK_OPTION_INT, + "-four", "four", "Four", + "4", + Tk_Offset(FiveRecord, four), -1}, + {TK_OPTION_STRING, + "-five", NULL, NULL, + NULL, + Tk_Offset(FiveRecord, five), -1}, + {TK_OPTION_END} + }; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 1, objv, "new name ?options?"); + return TCL_ERROR; + } + + recordPtr = (FiveRecord *) ckalloc(sizeof(FiveRecord)); + recordPtr->header.interp = interp; + recordPtr->header.optionTable = Tk_CreateOptionTable(interp, + smallSpecs); + tables[index] = recordPtr->header.optionTable; + recordPtr->header.tkwin = NULL; + recordPtr->one = recordPtr->two = recordPtr->three = NULL; + recordPtr->four = recordPtr->five = NULL; + Tcl_SetObjResult(interp, objv[2]); + result = Tk_InitOptions(interp, (char *) recordPtr, + recordPtr->header.optionTable, (Tk_Window) NULL); + if (result == TCL_OK) { + result = Tk_SetOptions(interp, (char *) recordPtr, + recordPtr->header.optionTable, objc - 3, objv + 3, + (Tk_Window) NULL, (Tk_SavedOptions *) NULL, + (int *) NULL); + if (result == TCL_OK) { + recordPtr->header.widgetCmd = Tcl_CreateObjCommand(interp, + Tcl_GetStringFromObj(objv[2], NULL), + TrivialConfigObjCmd, (ClientData) recordPtr, + TrivialCmdDeletedProc); + } else { + Tk_FreeConfigOptions((char *) recordPtr, + recordPtr->header.optionTable, (Tk_Window) NULL); + } + } + if (result != TCL_OK) { + ckfree((char *) recordPtr); + } + + break; + } + case NOT_ENOUGH_PARAMS: { + typedef struct NotEnoughRecord { + Tcl_Obj *fooObjPtr; + } NotEnoughRecord; + NotEnoughRecord record; + static Tk_OptionSpec errorSpecs[] = { + {TK_OPTION_INT, + "-foo", "foo", "Foo", + "0", Tk_Offset(NotEnoughRecord, fooObjPtr)}, + {TK_OPTION_END} + }; + Tcl_Obj *newObjPtr = Tcl_NewStringObj("-foo", -1); + Tk_OptionTable optionTable; + + record.fooObjPtr = NULL; + + tkwin = Tk_CreateWindowFromPath(interp, mainWin, + ".config", (char *) NULL); + Tk_SetClass(tkwin, "Config"); + optionTable = Tk_CreateOptionTable(interp, errorSpecs); + tables[index] = optionTable; + Tk_InitOptions(interp, (char *) &record, optionTable, tkwin); + if (Tk_SetOptions(interp, (char *) &record, optionTable, + 1, &newObjPtr, tkwin, (Tk_SavedOptions *) NULL, + (int *) NULL) + != TCL_OK) { + result = TCL_ERROR; + } + Tcl_DecrRefCount(newObjPtr); + Tk_FreeConfigOptions( (char *) &record, optionTable, tkwin); + Tk_DestroyWindow(tkwin); + return result; + } + + case TWO_WINDOWS: { + typedef struct SlaveRecord { + TrivialCommandHeader header; + Tcl_Obj *windowPtr; + } SlaveRecord; + SlaveRecord *recordPtr; + static Tk_OptionSpec slaveSpecs[] = { + {TK_OPTION_WINDOW, + "-window", "window", "Window", + ".bar", Tk_Offset(SlaveRecord, windowPtr), -1, + TK_CONFIG_NULL_OK}, + {TK_OPTION_END} + }; + Tk_Window tkwin = Tk_CreateWindowFromPath(interp, + (Tk_Window) clientData, + Tcl_GetStringFromObj(objv[2], NULL), (char *) NULL); + if (tkwin == NULL) { + return TCL_ERROR; + } + Tk_SetClass(tkwin, "Test"); + + recordPtr = (SlaveRecord *) ckalloc(sizeof(SlaveRecord)); + recordPtr->header.interp = interp; + recordPtr->header.optionTable = Tk_CreateOptionTable(interp, + slaveSpecs); + tables[index] = recordPtr->header.optionTable; + recordPtr->header.tkwin = tkwin; + recordPtr->windowPtr = NULL; + + result = Tk_InitOptions(interp, (char *) recordPtr, + recordPtr->header.optionTable, tkwin); + if (result == TCL_OK) { + result = Tk_SetOptions(interp, (char *) recordPtr, + recordPtr->header.optionTable, objc - 3, objv + 3, + tkwin, (Tk_SavedOptions *) NULL, (int *) NULL); + if (result == TCL_OK) { + recordPtr->header.widgetCmd = Tcl_CreateObjCommand(interp, + Tcl_GetStringFromObj(objv[2], NULL), + TrivialConfigObjCmd, (ClientData) recordPtr, + TrivialCmdDeletedProc); + Tk_CreateEventHandler(tkwin, StructureNotifyMask, + TrivialEventProc, (ClientData) recordPtr); + Tcl_SetObjResult(interp, objv[2]); + } else { + Tk_FreeConfigOptions((char *) recordPtr, + recordPtr->header.optionTable, tkwin); + } + } + if (result != TCL_OK) { + Tk_DestroyWindow(tkwin); + ckfree((char *) recordPtr); + } + + } + } + + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TrivialConfigObjCmd -- + * + * This command is used to test the configuration package. It only + * handles the "configure" and "cget" subcommands. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +TrivialConfigObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Main window for application. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + int result = TCL_OK; + static char *options[] = {"cget", "configure", "csave", (char *) NULL}; + enum { + CGET, CONFIGURE, CSAVE + }; + Tcl_Obj *resultObjPtr; + int index, mask; + TrivialCommandHeader *headerPtr = (TrivialCommandHeader *) clientData; + Tk_Window tkwin = headerPtr->tkwin; + Tk_SavedOptions saved; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg...?"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[1], options, "command", + 0, &index) != TCL_OK) { + return TCL_ERROR; + } + + Tcl_Preserve(clientData); + + switch (index) { + case CGET: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); + result = TCL_ERROR; + goto done; + } + resultObjPtr = Tk_GetOptionValue(interp, (char *) clientData, + headerPtr->optionTable, objv[2], tkwin); + if (resultObjPtr != NULL) { + Tcl_SetObjResult(interp, resultObjPtr); + result = TCL_OK; + } else { + result = TCL_ERROR; + } + break; + } + case CONFIGURE: { + if (objc == 2) { + resultObjPtr = Tk_GetOptionInfo(interp, (char *) clientData, + headerPtr->optionTable, (Tcl_Obj *) NULL, tkwin); + if (resultObjPtr == NULL) { + result = TCL_ERROR; + } else { + Tcl_SetObjResult(interp, resultObjPtr); + } + } else if (objc == 3) { + resultObjPtr = Tk_GetOptionInfo(interp, (char *) clientData, + headerPtr->optionTable, objv[2], tkwin); + if (resultObjPtr == NULL) { + result = TCL_ERROR; + } else { + Tcl_SetObjResult(interp, resultObjPtr); + } + } else { + result = Tk_SetOptions(interp, (char *) clientData, + headerPtr->optionTable, objc - 2, objv + 2, + tkwin, (Tk_SavedOptions *) NULL, &mask); + if (result == TCL_OK) { + Tcl_SetIntObj(Tcl_GetObjResult(interp), mask); + } + } + break; + } + case CSAVE: { + result = Tk_SetOptions(interp, (char *) clientData, + headerPtr->optionTable, objc - 2, objv + 2, + tkwin, &saved, &mask); + Tk_FreeSavedOptions(&saved); + if (result == TCL_OK) { + Tcl_SetIntObj(Tcl_GetObjResult(interp), mask); + } + break; + } + } +done: + Tcl_Release(clientData); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TrivialCmdDeletedProc -- + * + * This procedure is invoked when a widget command is deleted. If + * the widget isn't already in the process of being destroyed, + * this command destroys it. + * + * Results: + * None. + * + * Side effects: + * The widget is destroyed. + * + *---------------------------------------------------------------------- + */ + +static void +TrivialCmdDeletedProc(clientData) + ClientData clientData; /* Pointer to widget record for widget. */ +{ + TrivialCommandHeader *headerPtr = (TrivialCommandHeader *) clientData; + Tk_Window tkwin = headerPtr->tkwin; + + if (tkwin != NULL) { + Tk_DestroyWindow(tkwin); + } else if (headerPtr->optionTable != NULL) { + /* + * This is a "new" object, which doesn't have a window, so + * we can't depend on cleaning up in the event procedure. + * Free its resources here. + */ + + Tk_FreeConfigOptions((char *) clientData, + headerPtr->optionTable, (Tk_Window) NULL); + Tcl_EventuallyFree(clientData, TCL_DYNAMIC); + } +} + +/* + *-------------------------------------------------------------- + * + * TrivialEventProc -- + * + * A dummy event proc. + * + * Results: + * None. + * + * Side effects: + * When the window gets deleted, internal structures get + * cleaned up. + * + *-------------------------------------------------------------- + */ + +static void +TrivialEventProc(clientData, eventPtr) + ClientData clientData; /* Information about window. */ + XEvent *eventPtr; /* Information about event. */ +{ + TrivialCommandHeader *headerPtr = (TrivialCommandHeader *) clientData; + + if (eventPtr->type == DestroyNotify) { + if (headerPtr->tkwin != NULL) { + Tk_FreeConfigOptions((char *) clientData, + headerPtr->optionTable, headerPtr->tkwin); + headerPtr->optionTable = NULL; + headerPtr->tkwin = NULL; + Tcl_DeleteCommandFromToken(headerPtr->interp, + headerPtr->widgetCmd); + } + Tcl_EventuallyFree(clientData, TCL_DYNAMIC); + } +} + +/* + *---------------------------------------------------------------------- + * + * TestfontObjCmd -- + * + * This procedure implements the "testfont" command, which is used + * to test TkFont objects. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +TestfontObjCmd(clientData, interp, objc, objv) + ClientData clientData; /* Main window for application. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + static char *options[] = {"counts", "subfonts", (char *) NULL}; + enum option {COUNTS, SUBFONTS}; + int index; + Tk_Window tkwin; + Tk_Font tkfont; + + tkwin = (Tk_Window) clientData; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 1, objv, "option fontName"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[1], options, "command", 0, &index) + != TCL_OK) { + return TCL_ERROR; + } + + switch ((enum option) index) { + case COUNTS: { + Tcl_SetObjResult(interp, TkDebugFont(Tk_MainWindow(interp), + Tcl_GetString(objv[2]))); + break; + } + case SUBFONTS: { + tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]); + if (tkfont == NULL) { + return TCL_ERROR; + } + TkpGetSubFonts(interp, tkfont); + Tk_FreeFont(tkfont); + break; + } + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * ImageCreate -- * * This procedure is called by the Tk image code to create "test" @@ -439,6 +1563,7 @@ TestdeleteappsCmd(clientData, interp, argc, argv) */ /* ARGSUSED */ +#ifdef USE_OLD_IMAGE static int ImageCreate(interp, name, argc, objv, typePtr, master, clientDataPtr) Tcl_Interp *interp; /* Interpreter for application containing @@ -457,21 +1582,55 @@ ImageCreate(interp, name, argc, objv, typePtr, master, clientDataPtr) char *varName; int i; + Tk_InitImageArgs(interp, argc, &argv); varName = "log"; for (i = 0; i < argc; i += 2) { - char *arg = Tcl_GetStringFromObj(objv[i], NULL); - if (strcmp(arg, "-variable") != 0) { - Tcl_AppendResult(interp, "bad option name \"", arg, - "\"", (char *) NULL); + if (strcmp(argv[i], "-variable") != 0) { + Tcl_AppendResult(interp, "bad option name \"", + argv[i], "\"", (char *) NULL); return TCL_ERROR; } if ((i+1) == argc) { - Tcl_AppendResult(interp, "no value given for \"", arg, - "\" option", (char *) NULL); + Tcl_AppendResult(interp, "no value given for \"", + argv[i], "\" option", (char *) NULL); return TCL_ERROR; } varName = Tcl_GetStringFromObj(objv[i+1], NULL); } +#else +static int +ImageCreate(interp, name, objc, objv, typePtr, master, clientDataPtr) + Tcl_Interp *interp; /* Interpreter for application containing + * image. */ + char *name; /* Name to use for image. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument strings for options (doesn't + * include image name or type). */ + Tk_ImageType *typePtr; /* Pointer to our type record (not used). */ + Tk_ImageMaster master; /* Token for image, to be used by us in + * later callbacks. */ + ClientData *clientDataPtr; /* Store manager's token for image here; + * it will be returned in later callbacks. */ +{ + TImageMaster *timPtr; + char *varName; + int i; + + varName = "log"; + for (i = 0; i < objc; i += 2) { + if (strcmp(Tcl_GetString(objv[i]), "-variable") != 0) { + Tcl_AppendResult(interp, "bad option name \"", + Tcl_GetString(objv[i]), "\"", (char *) NULL); + return TCL_ERROR; + } + if ((i+1) == objc) { + Tcl_AppendResult(interp, "no value given for \"", + Tcl_GetString(objv[i]), "\" option", (char *) NULL); + return TCL_ERROR; + } + varName = Tcl_GetString(objv[i+1]); + } +#endif timPtr = (TImageMaster *) ckalloc(sizeof(TImageMaster)); timPtr->master = master; timPtr->interp = interp; @@ -524,7 +1683,8 @@ ImageCmd(clientData, interp, argc, argv) if (strcmp(argv[1], "changed") == 0) { if (argc != 8) { Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " changed x y width height imageWidth imageHeight", + argv[0], + " changed x y width height imageWidth imageHeight", (char *) NULL); return TCL_ERROR; } @@ -618,7 +1778,7 @@ ImageDisplay(clientData, display, drawable, imageX, imageY, width, height, * imageX and imageY. */ { TImageInstance *instPtr = (TImageInstance *) clientData; - char buffer[200]; + char buffer[200 + TCL_INTEGER_SPACE * 6]; sprintf(buffer, "%s display %d %d %d %d %d %d", instPtr->masterPtr->imageName, imageX, imageY, width, height, @@ -735,12 +1895,12 @@ TestmakeexistCmd(clientData, interp, argc, argv) int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { - Tk_Window mainwin = (Tk_Window) clientData; + Tk_Window mainWin = (Tk_Window) clientData; int i; Tk_Window tkwin; for (i = 1; i < argc; i++) { - tkwin = Tk_NameToWindow(interp, argv[i], mainwin); + tkwin = Tk_NameToWindow(interp, argv[i], mainWin); if (tkwin == NULL) { return TCL_ERROR; } @@ -777,7 +1937,7 @@ TestmenubarCmd(clientData, interp, argc, argv) char **argv; /* Argument strings. */ { #ifdef __UNIX__ - Tk_Window mainwin = (Tk_Window) clientData; + Tk_Window mainWin = (Tk_Window) clientData; Tk_Window tkwin, menubar; if (argc < 2) { @@ -792,14 +1952,14 @@ TestmenubarCmd(clientData, interp, argc, argv) "window toplevel menubar\"", (char *) NULL); return TCL_ERROR; } - tkwin = Tk_NameToWindow(interp, argv[2], mainwin); + tkwin = Tk_NameToWindow(interp, argv[2], mainWin); if (tkwin == NULL) { return TCL_ERROR; } if (argv[3][0] == 0) { TkUnixSetMenubar(tkwin, NULL); } else { - menubar = Tk_NameToWindow(interp, argv[3], mainwin); + menubar = Tk_NameToWindow(interp, argv[3], mainWin); if (menubar == NULL) { return TCL_ERROR; } @@ -813,7 +1973,8 @@ TestmenubarCmd(clientData, interp, argc, argv) return TCL_OK; #else - interp->result = "testmenubar is supported only under Unix"; + Tcl_SetResult(interp, "testmenubar is supported only under Unix", + TCL_STATIC); return TCL_ERROR; #endif } @@ -843,7 +2004,7 @@ TestmetricsCmd(clientData, interp, argc, argv) int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { - char buf[200]; + char buf[TCL_INTEGER_SPACE]; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0], @@ -875,7 +2036,7 @@ TestmetricsCmd(clientData, interp, argc, argv) { Tk_Window tkwin = (Tk_Window) clientData; TkWindow *winPtr; - char buf[200]; + char buf[TCL_INTEGER_SPACE]; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0], @@ -928,7 +2089,7 @@ TestpropCmd(clientData, interp, argc, argv) int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { - Tk_Window mainwin = (Tk_Window) clientData; + Tk_Window mainWin = (Tk_Window) clientData; int result, actualFormat; unsigned long bytesAfter, length, value; Atom actualType, propName; @@ -943,9 +2104,9 @@ TestpropCmd(clientData, interp, argc, argv) } w = strtoul(argv[1], &end, 0); - propName = Tk_InternAtom(mainwin, argv[2]); + propName = Tk_InternAtom(mainWin, argv[2]); property = NULL; - result = XGetWindowProperty(Tk_Display(mainwin), + result = XGetWindowProperty(Tk_Display(mainWin), w, propName, 0, 100000, False, AnyPropertyType, &actualType, &actualFormat, &length, &bytesAfter, (unsigned char **) &property); @@ -1006,7 +2167,9 @@ TestsendCmd(clientData, interp, argc, argv) int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { +#if !(defined(__WIN32__) || defined(MAC_TCL)) TkWindow *winPtr = (TkWindow *) clientData; +#endif if (argc < 2) { Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0], @@ -1074,7 +2237,10 @@ TestsendCmd(clientData, interp, argc, argv) } } } else if (strcmp(argv[1], "serial") == 0) { - sprintf(interp->result, "%d", tkSendSerial+1); + char buf[TCL_INTEGER_SPACE]; + + sprintf(buf, "%d", tkSendSerial+1); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be bogus, prop, or serial", (char *) NULL); @@ -1084,6 +2250,85 @@ TestsendCmd(clientData, interp, argc, argv) return TCL_OK; } +/* + *---------------------------------------------------------------------- + * + * TesttextCmd -- + * + * This procedure implements the "testtext" command. It provides + * a set of functions for testing text widgets and the associated + * functions in tkText*.c. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * Depends on option; see below. + * + *---------------------------------------------------------------------- + */ + +static int +TesttextCmd(clientData, interp, argc, argv) + ClientData clientData; /* Main window for application. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ +{ + TkText *textPtr; + size_t len; + int lineIndex, byteIndex, byteOffset; + TkTextIndex index; + char buf[64]; + Tcl_CmdInfo info; + + if (argc < 3) { + return TCL_ERROR; + } + + if (Tcl_GetCommandInfo(interp, argv[1], &info) == 0) { + return TCL_ERROR; + } + textPtr = (TkText *) info.clientData; + len = strlen(argv[2]); + if (strncmp(argv[2], "byteindex", len) == 0) { + if (argc != 5) { + return TCL_ERROR; + } + lineIndex = atoi(argv[3]) - 1; + byteIndex = atoi(argv[4]); + + TkTextMakeByteIndex(textPtr->tree, lineIndex, byteIndex, &index); + } else if (strncmp(argv[2], "forwbytes", len) == 0) { + if (argc != 5) { + return TCL_ERROR; + } + if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) { + return TCL_ERROR; + } + byteOffset = atoi(argv[4]); + TkTextIndexForwBytes(&index, byteOffset, &index); + } else if (strncmp(argv[2], "backbytes", len) == 0) { + if (argc != 5) { + return TCL_ERROR; + } + if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) { + return TCL_ERROR; + } + byteOffset = atoi(argv[4]); + TkTextIndexBackBytes(&index, byteOffset, &index); + } else { + return TCL_ERROR; + } + + TkTextSetMark(textPtr, "insert", &index); + TkTextPrintIndex(&index, buf); + sprintf(buf + strlen(buf), " %d", index.byteIndex); + Tcl_AppendResult(interp, buf, NULL); + + return TCL_OK; +} + #if !(defined(__WIN32__) || defined(MAC_TCL)) /* *---------------------------------------------------------------------- @@ -1128,8 +2373,13 @@ TestwrapperCmd(clientData, interp, argc, argv) wrapperPtr = TkpGetWrapperWindow(winPtr); if (wrapperPtr != NULL) { - TkpPrintWindowId(interp->result, Tk_WindowId(wrapperPtr)); + char buf[TCL_INTEGER_SPACE]; + + TkpPrintWindowId(buf, Tk_WindowId(wrapperPtr)); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_OK; } #endif + + diff --git a/tk/generic/tkText.c b/tk/generic/tkText.c index d9ff1cc9165..560c0260d9c 100644 --- a/tk/generic/tkText.c +++ b/tk/generic/tkText.c @@ -9,6 +9,7 @@ * * Copyright (c) 1992-1994 The Regents of the University of California. * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -28,6 +29,15 @@ #include "tkText.h" /* + * Custom options for handling "-state" + */ + +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) NULL /* only "normal" and "disabled" */ +}; + +/* * Information used to parse text configuration options: */ @@ -112,8 +122,8 @@ static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_PIXELS, "-spacing3", "spacing3", "Spacing", DEF_TEXT_SPACING3, Tk_Offset(TkText, spacing3), TK_CONFIG_DONT_SET_DEFAULT}, - {TK_CONFIG_UID, "-state", "state", "State", - DEF_TEXT_STATE, Tk_Offset(TkText, state), 0}, + {TK_CONFIG_CUSTOM, "-state", "state", "State", + DEF_TEXT_STATE, Tk_Offset(TkText, state), 0, &stateOption}, {TK_CONFIG_STRING, "-tabs", "tabs", "Tabs", DEF_TEXT_TABS, Tk_Offset(TkText, tabOptionString), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", @@ -121,8 +131,8 @@ static Tk_ConfigSpec configSpecs[] = { TK_CONFIG_NULL_OK}, {TK_CONFIG_INT, "-width", "width", "Width", DEF_TEXT_WIDTH, Tk_Offset(TkText, width), 0}, - {TK_CONFIG_UID, "-wrap", "wrap", "Wrap", - DEF_TEXT_WRAP, Tk_Offset(TkText, wrapMode), 0}, + {TK_CONFIG_CUSTOM, "-wrap", "wrap", "Wrap", + DEF_TEXT_WRAP, Tk_Offset(TkText, wrapMode), 0, &textWrapModeOption}, {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", DEF_TEXT_XSCROLL_COMMAND, Tk_Offset(TkText, xScrollCmd), TK_CONFIG_NULL_OK}, @@ -143,21 +153,133 @@ static Tk_ConfigSpec configSpecs[] = { }; /* - * Tk_Uid's used to represent text states: + * Boolean variable indicating whether or not special debugging code + * should be executed. */ -Tk_Uid tkTextCharUid = NULL; -Tk_Uid tkTextDisabledUid = NULL; -Tk_Uid tkTextNoneUid = NULL; -Tk_Uid tkTextNormalUid = NULL; -Tk_Uid tkTextWordUid = NULL; +int tkTextDebug = 0; /* - * Boolean variable indicating whether or not special debugging code - * should be executed. + * Custom options for handling "-wrap": */ -int tkTextDebug = 0; +static int WrapModeParseProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, char *value, + char *widgRec, int offset)); +static char * WrapModePrintProc _ANSI_ARGS_((ClientData clientData, + Tk_Window tkwin, char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); + +Tk_CustomOption textWrapModeOption = { + WrapModeParseProc, + WrapModePrintProc, + (ClientData) NULL +}; + +/* + *-------------------------------------------------------------- + * + * WrapModeParseProc -- + * + * This procedure is invoked during option processing to handle + * "-wrap" options for text widgets. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The wrap mode for a given item gets replaced by the wrap mode + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +static int +WrapModeParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *value; /* Value of option (list of tag + * names). */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + int c; + size_t length; + + register TkWrapMode *wrapPtr = (TkWrapMode *) (widgRec + offset); + + if(value == NULL || *value == 0) { + *wrapPtr = TEXT_WRAPMODE_NULL; + return TCL_OK; + } + + c = value[0]; + length = strlen(value); + + if ((c == 'c') && (strncmp(value, "char", length) == 0)) { + *wrapPtr = TEXT_WRAPMODE_CHAR; + return TCL_OK; + } + if ((c == 'n') && (strncmp(value, "none", length) == 0)) { + *wrapPtr = TEXT_WRAPMODE_NONE; + return TCL_OK; + } + if ((c == 'w') && (strncmp(value, "word", length) == 0)) { + *wrapPtr = TEXT_WRAPMODE_WORD; + return TCL_OK; + } + Tcl_AppendResult(interp, "bad wrap mode \"", value, + "\": must be char, none, or word", + (char *) NULL); + *wrapPtr = TEXT_WRAPMODE_CHAR; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * WrapModePrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-wrap" configuration + * option for canvas items. + * + * Results: + * The return value is a string describing the state for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static char * +WrapModePrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Ignored. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register TkWrapMode *wrapPtr = (TkWrapMode *) (widgRec + offset); + + if (*wrapPtr==TEXT_WRAPMODE_CHAR) { + return "char"; + } else if (*wrapPtr==TEXT_WRAPMODE_NONE) { + return "none"; + } else if (*wrapPtr==TEXT_WRAPMODE_WORD) { + return "word"; + } else { + return ""; + } +} /* * Forward declarations for procedures defined later in this file: @@ -189,7 +311,7 @@ static void DumpLine _ANSI_ARGS_((Tcl_Interp *interp, TkText *textPtr, int what, TkTextLine *linePtr, int start, int end, int lineno, char *command)); static int DumpSegment _ANSI_ARGS_((Tcl_Interp *interp, char *key, - char *value, char * command, int lineno, int offset, + char *value, char * command, TkTextIndex *index, int what)); /* @@ -241,18 +363,6 @@ Tk_TextCmd(clientData, interp, argc, argv) } /* - * Perform once-only initialization: - */ - - if (tkTextNormalUid == NULL) { - tkTextCharUid = Tk_GetUid("char"); - tkTextDisabledUid = Tk_GetUid("disabled"); - tkTextNoneUid = Tk_GetUid("none"); - tkTextNormalUid = Tk_GetUid("normal"); - tkTextWordUid = Tk_GetUid("word"); - } - - /* * Create the window. */ @@ -274,7 +384,7 @@ Tk_TextCmd(clientData, interp, argc, argv) Tcl_InitHashTable(&textPtr->markTable, TCL_STRING_KEYS); Tcl_InitHashTable(&textPtr->windowTable, TCL_STRING_KEYS); Tcl_InitHashTable(&textPtr->imageTable, TCL_STRING_KEYS); - textPtr->state = tkTextNormalUid; + textPtr->state = TK_STATE_NORMAL; textPtr->border = NULL; textPtr->borderWidth = 0; textPtr->padX = 0; @@ -293,14 +403,14 @@ Tk_TextCmd(clientData, interp, argc, argv) textPtr->tabOptionString = NULL; textPtr->tabsize = 8; textPtr->tabArrayPtr = NULL; - textPtr->wrapMode = tkTextCharUid; + textPtr->wrapMode = TEXT_WRAPMODE_CHAR; textPtr->width = 0; textPtr->height = 0; textPtr->setGrid = 0; textPtr->prevWidth = Tk_Width(new); textPtr->prevHeight = Tk_Height(new); TkTextCreateDInfo(textPtr); - TkTextMakeIndex(textPtr->tree, 0, 0, &startIndex); + TkTextMakeByteIndex(textPtr->tree, 0, 0, &startIndex); TkTextSetYView(textPtr, &startIndex, 0); textPtr->selTagPtr = NULL; textPtr->selBorder = NULL; @@ -336,7 +446,8 @@ Tk_TextCmd(clientData, interp, argc, argv) */ textPtr->selTagPtr = TkTextCreateTag(textPtr, "sel"); - textPtr->selTagPtr->reliefString = (char *) ckalloc(7); + textPtr->selTagPtr->reliefString = + (char *) ckalloc(sizeof(DEF_TEXT_SELECT_RELIEF)); strcpy(textPtr->selTagPtr->reliefString, DEF_TEXT_SELECT_RELIEF); textPtr->selTagPtr->relief = TK_RELIEF_RAISED; textPtr->currentMarkPtr = TkTextSetMark(textPtr, "current", &startIndex); @@ -357,7 +468,7 @@ Tk_TextCmd(clientData, interp, argc, argv) Tk_DestroyWindow(textPtr->tkwin); return TCL_ERROR; } - interp->result = Tk_PathName(textPtr->tkwin); + Tcl_SetResult(interp, Tk_PathName(textPtr->tkwin), TCL_STATIC); return TCL_OK; } @@ -474,7 +585,10 @@ TextWidgetCmd(clientData, interp, argc, argv) goto done; } if (TkTextCharBbox(textPtr, &index1, &x, &y, &width, &height) == 0) { - sprintf(interp->result, "%d %d %d %d", x, y, width, height); + char buf[TCL_INTEGER_SPACE * 4]; + + sprintf(buf, "%d %d %d %d", x, y, width, height); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0) && (length >= 2)) { @@ -532,7 +646,7 @@ TextWidgetCmd(clientData, interp, argc, argv) } else { goto compareError; } - interp->result = (value) ? "1" : "0"; + Tcl_SetResult(interp, ((value) ? "1" : "0"), TCL_STATIC); } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0) && (length >= 3)) { if (argc == 2) { @@ -554,7 +668,7 @@ TextWidgetCmd(clientData, interp, argc, argv) goto done; } if (argc == 2) { - interp->result = (tkBTreeDebug) ? "1" : "0"; + Tcl_SetResult(interp, ((tkBTreeDebug) ? "1" : "0"), TCL_STATIC); } else { if (Tcl_GetBoolean(interp, argv[2], &tkBTreeDebug) != TCL_OK) { result = TCL_ERROR; @@ -573,18 +687,7 @@ TextWidgetCmd(clientData, interp, argc, argv) result = TCL_ERROR; goto done; } - if (textPtr->state == tkTextNormalUid) { - /* - * KHAMIS - * Call synchronize command - * BEFORE INSERTING INTO THE EDITOR - ***********************************/ - if (textPtr->SyncCmd && *textPtr->SyncCmd) { - result = ExecSyncCmd (interp, textPtr, argc, argv); - if (result == TCL_ERROR) { - goto done; - } - } + if (textPtr->state == TK_STATE_NORMAL) { result = DeleteChars(textPtr, argv[2], (argc == 4) ? argv[3] : (char *) NULL); } @@ -604,8 +707,10 @@ TextWidgetCmd(clientData, interp, argc, argv) } if (TkTextDLineInfo(textPtr, &index1, &x, &y, &width, &height, &base) == 0) { - sprintf(interp->result, "%d %d %d %d %d", x, y, width, - height, base); + char buf[TCL_INTEGER_SPACE * 5]; + + sprintf(buf, "%d %d %d %d %d", x, y, width, height, base); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { if ((argc != 3) && (argc != 4)) { @@ -638,10 +743,10 @@ TextWidgetCmd(clientData, interp, argc, argv) if (index1.linePtr == index2.linePtr) { int last2; - if (index2.charIndex == index1.charIndex) { + if (index2.byteIndex == index1.byteIndex) { break; } - last2 = index2.charIndex - index1.charIndex + offset; + last2 = index2.byteIndex - index1.byteIndex + offset; if (last2 < last) { last = last2; } @@ -653,10 +758,12 @@ TextWidgetCmd(clientData, interp, argc, argv) (char *) NULL); segPtr->body.chars[last] = savedChar; } - TkTextIndexForwChars(&index1, last-offset, &index1); + TkTextIndexForwBytes(&index1, last-offset, &index1); } } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0) && (length >= 3)) { + char buf[200]; + if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " index index\"", @@ -668,7 +775,8 @@ TextWidgetCmd(clientData, interp, argc, argv) result = TCL_ERROR; goto done; } - TkTextPrintIndex(&index1, interp->result); + TkTextPrintIndex(&index1, buf); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0) && (length >= 3)) { int i, j, numTags; @@ -689,22 +797,11 @@ TextWidgetCmd(clientData, interp, argc, argv) result = TCL_ERROR; goto done; } - if (textPtr->state == tkTextNormalUid) { - /* - * KHAMIS - * Call synchronize command - * BEFORE INSERTING INTO THE EDITOR - ***********************************/ - if (textPtr->SyncCmd && *textPtr->SyncCmd) { - result = ExecSyncCmd (interp, textPtr, argc, argv); - if (result == TCL_ERROR) { - goto done; - } - } + if (textPtr->state == TK_STATE_NORMAL) { for (j = 3; j < argc; j += 2) { InsertChars(textPtr, &index1, argv[j]); if (argc > (j+1)) { - TkTextIndexForwChars(&index1, (int) strlen(argv[j]), + TkTextIndexForwBytes(&index1, (int) strlen(argv[j]), &index2); oldTagArrayPtr = TkBTreeGetTags(&index1, &numTags); if (oldTagArrayPtr != NULL) { @@ -752,8 +849,8 @@ TextWidgetCmd(clientData, interp, argc, argv) } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be bbox, cget, compare, configure, debug, delete, ", - "dlineinfo, get, image, index, insert, mark, scan, search, see, ", - "tag, window, xview, or yview", + "dlineinfo, dump, get, image, index, insert, mark, scan, ", + "search, see, tag, window, xview, or yview", (char *) NULL); result = TCL_ERROR; } @@ -845,7 +942,7 @@ DestroyText(memPtr) * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message. + * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as text string, colors, font, @@ -876,23 +973,6 @@ ConfigureText(interp, textPtr, argc, argv, flags) * the geometry and setting the background from a 3-D border. */ - if ((textPtr->state != tkTextNormalUid) - && (textPtr->state != tkTextDisabledUid)) { - Tcl_AppendResult(interp, "bad state value \"", textPtr->state, - "\": must be normal or disabled", (char *) NULL); - textPtr->state = tkTextNormalUid; - return TCL_ERROR; - } - - if ((textPtr->wrapMode != tkTextCharUid) - && (textPtr->wrapMode != tkTextNoneUid) - && (textPtr->wrapMode != tkTextWordUid)) { - Tcl_AppendResult(interp, "bad wrap mode \"", textPtr->wrapMode, - "\": must be char, none, or word", (char *) NULL); - textPtr->wrapMode = tkTextCharUid; - return TCL_ERROR; - } - Tk_SetBackgroundFromBorder(textPtr->tkwin, textPtr->border); /* @@ -967,7 +1047,8 @@ ConfigureText(interp, textPtr, argc, argv, flags) || (textPtr->selTagPtr->spacing3String != NULL) || (textPtr->selTagPtr->tabString != NULL) || (textPtr->selTagPtr->underlineString != NULL) - || (textPtr->selTagPtr->wrapMode != NULL)) { + || (textPtr->selTagPtr->elideString != NULL) + || (textPtr->selTagPtr->wrapMode != TEXT_WRAPMODE_NULL)) { textPtr->selTagPtr->affectsDisplay = 1; } TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, (TkTextIndex *) NULL, @@ -982,8 +1063,8 @@ ConfigureText(interp, textPtr, argc, argv, flags) TkTextSearch search; TkTextIndex first, last; - TkTextMakeIndex(textPtr->tree, 0, 0, &first); - TkTextMakeIndex(textPtr->tree, + TkTextMakeByteIndex(textPtr->tree, 0, 0, &first); + TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &last); TkBTreeStartSearch(&first, &last, textPtr->selTagPtr, &search); if (TkBTreeCharTagged(&first, textPtr->selTagPtr) @@ -1214,7 +1295,7 @@ InsertChars(textPtr, indexPtr, string) lineIndex = TkBTreeLineIndex(indexPtr->linePtr); if (lineIndex == TkBTreeNumLines(textPtr->tree)) { lineIndex--; - TkTextMakeIndex(textPtr->tree, lineIndex, 1000000, indexPtr); + TkTextMakeByteIndex(textPtr->tree, lineIndex, 1000000, indexPtr); } /* @@ -1227,16 +1308,16 @@ InsertChars(textPtr, indexPtr, string) resetView = offset = 0; if (indexPtr->linePtr == textPtr->topIndex.linePtr) { resetView = 1; - offset = textPtr->topIndex.charIndex; - if (offset > indexPtr->charIndex) { + offset = textPtr->topIndex.byteIndex; + if (offset > indexPtr->byteIndex) { offset += strlen(string); } } TkTextChanged(textPtr, indexPtr, indexPtr); TkBTreeInsertChars(indexPtr, string); if (resetView) { - TkTextMakeIndex(textPtr->tree, lineIndex, 0, &newTop); - TkTextIndexForwChars(&newTop, offset, &newTop); + TkTextMakeByteIndex(textPtr->tree, lineIndex, 0, &newTop); + TkTextIndexForwBytes(&newTop, offset, &newTop); TkTextSetYView(textPtr, &newTop, 0); } @@ -1275,7 +1356,7 @@ DeleteChars(textPtr, index1String, index2String) * delete the one character given by * index1String. */ { - int line1, line2, line, charIndex, resetView; + int line1, line2, line, byteIndex, resetView; TkTextIndex index1, index2; /* @@ -1326,7 +1407,7 @@ DeleteChars(textPtr, index1String, index2String) oldIndex2 = index2; TkTextIndexBackChars(&oldIndex2, 1, &index2); line2--; - if ((index1.charIndex == 0) && (line1 != 0)) { + if ((index1.byteIndex == 0) && (line1 != 0)) { TkTextIndexBackChars(&index1, 1, &index1); line1--; } @@ -1349,7 +1430,9 @@ DeleteChars(textPtr, index1String, index2String) */ TkTextChanged(textPtr, &index1, &index2); - resetView = line = charIndex = 0; + resetView = 0; + line = 0; + byteIndex = 0; if (TkTextIndexCmp(&index2, &textPtr->topIndex) >= 0) { if (TkTextIndexCmp(&index1, &textPtr->topIndex) <= 0) { /* @@ -1359,7 +1442,7 @@ DeleteChars(textPtr, index1String, index2String) resetView = 1; line = line1; - charIndex = index1.charIndex; + byteIndex = index1.byteIndex; } else if (index1.linePtr == textPtr->topIndex.linePtr) { /* * Deletion range starts on top line but after topIndex. @@ -1368,7 +1451,7 @@ DeleteChars(textPtr, index1String, index2String) resetView = 1; line = line1; - charIndex = textPtr->topIndex.charIndex; + byteIndex = textPtr->topIndex.byteIndex; } } else if (index2.linePtr == textPtr->topIndex.linePtr) { /* @@ -1379,16 +1462,16 @@ DeleteChars(textPtr, index1String, index2String) resetView = 1; line = line2; - charIndex = textPtr->topIndex.charIndex; + byteIndex = textPtr->topIndex.byteIndex; if (index1.linePtr != index2.linePtr) { - charIndex -= index2.charIndex; + byteIndex -= index2.byteIndex; } else { - charIndex -= (index2.charIndex - index1.charIndex); + byteIndex -= (index2.byteIndex - index1.byteIndex); } } TkBTreeDeleteChars(&index1, &index2); if (resetView) { - TkTextMakeIndex(textPtr->tree, line, charIndex, &index1); + TkTextMakeByteIndex(textPtr->tree, line, byteIndex, &index1); TkTextSetYView(textPtr, &index1, 0); } @@ -1452,12 +1535,12 @@ TextFetchSelection(clientData, offset, buffer, maxBytes) */ if (offset == 0) { - TkTextMakeIndex(textPtr->tree, 0, 0, &textPtr->selIndex); + TkTextMakeByteIndex(textPtr->tree, 0, 0, &textPtr->selIndex); textPtr->abortSelections = 0; } else if (textPtr->abortSelections) { return 0; } - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &eof); + TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &eof); TkBTreeStartSearch(&textPtr->selIndex, &eof, textPtr->selTagPtr, &search); if (!TkBTreeCharTagged(&textPtr->selIndex, textPtr->selTagPtr)) { if (!TkBTreeNextTag(&search)) { @@ -1504,8 +1587,8 @@ TextFetchSelection(clientData, offset, buffer, maxBytes) if (textPtr->selIndex.linePtr == search.curIndex.linePtr) { int leftInRange; - leftInRange = search.curIndex.charIndex - - textPtr->selIndex.charIndex; + leftInRange = search.curIndex.byteIndex + - textPtr->selIndex.byteIndex; if (leftInRange < chunkSize) { chunkSize = leftInRange; if (chunkSize <= 0) { @@ -1513,14 +1596,15 @@ TextFetchSelection(clientData, offset, buffer, maxBytes) } } } - if (segPtr->typePtr == &tkTextCharType) { + if ((segPtr->typePtr == &tkTextCharType) + && !TkTextIsElided(textPtr, &textPtr->selIndex)) { memcpy((VOID *) buffer, (VOID *) (segPtr->body.chars + offsetInSeg), (size_t) chunkSize); buffer += chunkSize; maxBytes -= chunkSize; count += chunkSize; } - TkTextIndexForwChars(&textPtr->selIndex, chunkSize, + TkTextIndexForwBytes(&textPtr->selIndex, chunkSize, &textPtr->selIndex); } @@ -1577,8 +1661,8 @@ TkTextLostSelection(clientData) * just remove the "sel" tag from everything in the widget. */ - TkTextMakeIndex(textPtr->tree, 0, 0, &start); - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &end); + TkTextMakeByteIndex(textPtr->tree, 0, 0, &start); + TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &end); TkTextRedrawTag(textPtr, &start, &end, textPtr->selTagPtr, 1); TkBTreeTag(&start, &end, textPtr->selTagPtr, 0); #endif @@ -1611,7 +1695,8 @@ TextBlinkProc(clientData) TkTextIndex index; int x, y, w, h; - if (!(textPtr->flags & GOT_FOCUS) || (textPtr->insertOffTime == 0)) { + if ((textPtr->state == TK_STATE_DISABLED) || + !(textPtr->flags & GOT_FOCUS) || (textPtr->insertOffTime == 0)) { return; } if (textPtr->flags & INSERT_ON) { @@ -1654,10 +1739,10 @@ TextSearchCmd(textPtr, interp, argc, argv) int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { - int backwards, exact, c, i, argsLeft, noCase, leftToScan; + int backwards, exact, searchElide, c, i, argsLeft, noCase, leftToScan; size_t length; - int numLines, startingLine, startingChar, lineNum, firstChar, lastChar; - int code, matchLength, matchChar, passes, stopLine, searchWholeText; + int numLines, startingLine, startingByte, lineNum, firstByte, lastByte; + int code, matchLength, matchByte, passes, stopLine, searchWholeText; int patLength; char *arg, *pattern, *varName, *p, *startOfLine; char buffer[20]; @@ -1665,6 +1750,8 @@ TextSearchCmd(textPtr, interp, argc, argv) Tcl_DString line, patDString; TkTextSegment *segPtr; TkTextLine *linePtr; + TkTextIndex curIndex; + Tcl_Obj *patObj = NULL; Tcl_RegExp regexp = NULL; /* Initialization needed only to * prevent compiler warning. */ @@ -1673,6 +1760,8 @@ TextSearchCmd(textPtr, interp, argc, argv) */ exact = 1; + searchElide = 0; + curIndex.tree = textPtr->tree; backwards = 0; noCase = 0; varName = NULL; @@ -1685,8 +1774,8 @@ TextSearchCmd(textPtr, interp, argc, argv) if (length < 2) { badSwitch: Tcl_AppendResult(interp, "bad switch \"", arg, - "\": must be -forward, -backward, -exact, -regexp, ", - "-nocase, -count, or --", (char *) NULL); + "\": must be --, -backward, -count, -elide, -exact, ", + "-forward, -nocase, or -regexp", (char *) NULL); return TCL_ERROR; } c = arg[1]; @@ -1694,13 +1783,24 @@ TextSearchCmd(textPtr, interp, argc, argv) backwards = 1; } else if ((c == 'c') && (strncmp(argv[i], "-count", length) == 0)) { if (i >= (argc-1)) { - interp->result = "no value given for \"-count\" option"; + Tcl_SetResult(interp, "no value given for \"-count\" option", + TCL_STATIC); return TCL_ERROR; } i++; varName = argv[i]; - } else if ((c == 'e') && (strncmp(argv[i], "-exact", length) == 0)) { + } else if ((c == 'e') && (length > 2) + && (strncmp(argv[i], "-exact", length) == 0)) { exact = 1; + } else if ((c == 'e') && (length > 2) + && (strncmp(argv[i], "-elide", length) == 0)) { + searchElide = 1; + } else if ((c == 'h') && (strncmp(argv[i], "-hidden", length) == 0)) { + /* + * -hidden is kept around for backwards compatibility with + * the dash patch, but -elide is the official option + */ + searchElide = 1; } else if ((c == 'f') && (strncmp(argv[i], "-forwards", length) == 0)) { backwards = 0; } else if ((c == 'n') && (strncmp(argv[i], "-nocase", length) == 0)) { @@ -1717,7 +1817,7 @@ TextSearchCmd(textPtr, interp, argc, argv) argsLeft = argc - (i+2); if ((argsLeft != 0) && (argsLeft != 1)) { Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " search ?switches? pattern index ?stopIndex?", + argv[0], " search ?switches? pattern index ?stopIndex?\"", (char *) NULL); return TCL_ERROR; } @@ -1727,36 +1827,35 @@ TextSearchCmd(textPtr, interp, argc, argv) * Convert the pattern to lower-case if we're supposed to ignore case. */ - if (noCase) { + if (noCase && exact) { Tcl_DStringInit(&patDString); Tcl_DStringAppend(&patDString, pattern, -1); pattern = Tcl_DStringValue(&patDString); - for (p = pattern; *p != 0; p++) { - if (isupper(UCHAR(*p))) { - *p = tolower(UCHAR(*p)); - } - } + Tcl_UtfToLower(pattern); } + Tcl_DStringInit(&line); if (TkTextGetIndex(interp, textPtr, argv[i+1], &index) != TCL_OK) { - return TCL_ERROR; + code = TCL_ERROR; + goto done; } numLines = TkBTreeNumLines(textPtr->tree); startingLine = TkBTreeLineIndex(index.linePtr); - startingChar = index.charIndex; + startingByte = index.byteIndex; if (startingLine >= numLines) { if (backwards) { startingLine = TkBTreeNumLines(textPtr->tree) - 1; - startingChar = TkBTreeCharsInLine(TkBTreeFindLine(textPtr->tree, + startingByte = TkBTreeBytesInLine(TkBTreeFindLine(textPtr->tree, startingLine)); } else { startingLine = 0; - startingChar = 0; + startingByte = 0; } } if (argsLeft == 1) { if (TkTextGetIndex(interp, textPtr, argv[i+2], &stopIndex) != TCL_OK) { - return TCL_ERROR; + code = TCL_ERROR; + goto done; } stopLine = TkBTreeLineIndex(stopIndex.linePtr); if (!backwards && (stopLine == numLines)) { @@ -1778,14 +1877,17 @@ TextSearchCmd(textPtr, interp, argc, argv) if (exact) { patLength = strlen(pattern); } else { - regexp = Tcl_RegExpCompile(interp, pattern); + patObj = Tcl_NewStringObj(pattern, -1); + Tcl_IncrRefCount(patObj); + regexp = Tcl_GetRegExpFromObj(interp, patObj, + (noCase ? TCL_REG_NOCASE : 0) | TCL_REG_ADVANCED); if (regexp == NULL) { - return TCL_ERROR; + code = TCL_ERROR; + goto done; } } lineNum = startingLine; code = TCL_OK; - Tcl_DStringInit(&line); for (passes = 0; passes < 2; ) { if (lineNum >= numLines) { /* @@ -1802,9 +1904,11 @@ TextSearchCmd(textPtr, interp, argc, argv) */ linePtr = TkBTreeFindLine(textPtr->tree, lineNum); + curIndex.linePtr = linePtr; curIndex.byteIndex = 0; for (segPtr = linePtr->segPtr; segPtr != NULL; - segPtr = segPtr->nextPtr) { - if (segPtr->typePtr != &tkTextCharType) { + curIndex.byteIndex += segPtr->size, segPtr = segPtr->nextPtr) { + if ((segPtr->typePtr != &tkTextCharType) + || (!searchElide && TkTextIsElided(textPtr, &curIndex))) { continue; } Tcl_DStringAppend(&line, segPtr->body.chars, segPtr->size); @@ -1819,22 +1923,20 @@ TextSearchCmd(textPtr, interp, argc, argv) */ if (noCase) { - for (p = Tcl_DStringValue(&line); *p != 0; p++) { - if (isupper(UCHAR(*p))) { - *p = tolower(UCHAR(*p)); - } - } + Tcl_DStringSetLength(&line, + Tcl_UtfToLower(Tcl_DStringValue(&line))); } /* * Check for matches within the current line. If so, and if we're * searching backwards, repeat the search to find the last match - * in the line. + * in the line. (Note: The lastByte should include the NULL char + * so we can handle searching for end of line easier.) */ - matchChar = -1; - firstChar = 0; - lastChar = INT_MAX; + matchByte = -1; + firstByte = 0; + lastByte = Tcl_DStringLength(&line) + 1; if (lineNum == startingLine) { int indexInDString; @@ -1848,8 +1950,8 @@ TextSearchCmd(textPtr, interp, argc, argv) * character. */ - indexInDString = startingChar; - for (segPtr = linePtr->segPtr, leftToScan = startingChar; + indexInDString = startingByte; + for (segPtr = linePtr->segPtr, leftToScan = startingByte; leftToScan > 0; segPtr = segPtr->nextPtr) { if (segPtr->typePtr != &tkTextCharType) { indexInDString -= segPtr->size; @@ -1863,8 +1965,9 @@ TextSearchCmd(textPtr, interp, argc, argv) * Only use the last part of the line. */ - firstChar = indexInDString; - if (firstChar >= Tcl_DStringLength(&line)) { + firstByte = indexInDString; + if ((firstByte >= Tcl_DStringLength(&line)) + && !((Tcl_DStringLength(&line) == 0) && !exact)) { goto nextLine; } } else { @@ -1872,13 +1975,16 @@ TextSearchCmd(textPtr, interp, argc, argv) * Use only the first part of the line. */ - lastChar = indexInDString; + lastByte = indexInDString; } } do { int thisLength; + Tcl_UniChar ch; + if (exact) { - p = strstr(startOfLine + firstChar, pattern); + p = strstr(startOfLine + firstByte, /* INTL: Native. */ + pattern); if (p == NULL) { break; } @@ -1889,7 +1995,7 @@ TextSearchCmd(textPtr, interp, argc, argv) int match; match = Tcl_RegExpExec(interp, regexp, - startOfLine + firstChar, startOfLine); + startOfLine + firstByte, startOfLine); if (match < 0) { code = TCL_ERROR; goto done; @@ -1901,12 +2007,12 @@ TextSearchCmd(textPtr, interp, argc, argv) i = start - startOfLine; thisLength = end - start; } - if (i >= lastChar) { + if (i >= lastByte) { break; } - matchChar = i; + matchByte = i; matchLength = thisLength; - firstChar = matchChar+1; + firstByte = i + Tcl_UtfToUniChar(startOfLine + matchByte, &ch); } while (backwards); /* @@ -1915,32 +2021,49 @@ TextSearchCmd(textPtr, interp, argc, argv) * specified. */ - if (matchChar >= 0) { + if (matchByte >= 0) { + int numChars; + + /* + * Convert the byte length to a character count. + */ + + numChars = Tcl_NumUtfChars(startOfLine + matchByte, + matchLength); + /* * The index information returned by the regular expression * parser only considers textual information: it doesn't - * account for embedded windows or any other non-textual info. + * account for embedded windows, elided text (when we are not + * searching elided text) or any other non-textual info. * Scan through the line's segments again to adjust both * matchChar and matchCount. + * + * We will walk through the segments of this line until we have + * either reached the end of the match or we have reached the end + * of the line. */ - for (segPtr = linePtr->segPtr, leftToScan = matchChar; - leftToScan >= 0; segPtr = segPtr->nextPtr) { - if (segPtr->typePtr != &tkTextCharType) { - matchChar += segPtr->size; - continue; + curIndex.linePtr = linePtr; curIndex.byteIndex = 0; + for (segPtr = linePtr->segPtr, leftToScan = matchByte; + leftToScan >= 0 && segPtr; segPtr = segPtr->nextPtr) { + if (segPtr->typePtr != &tkTextCharType || \ + (!searchElide && TkTextIsElided(textPtr, &curIndex))) { + matchByte += segPtr->size; + } else { + leftToScan -= segPtr->size; } - leftToScan -= segPtr->size; + curIndex.byteIndex += segPtr->size; } for (leftToScan += matchLength; leftToScan > 0; segPtr = segPtr->nextPtr) { if (segPtr->typePtr != &tkTextCharType) { - matchLength += segPtr->size; + numChars += segPtr->size; continue; } leftToScan -= segPtr->size; } - TkTextMakeIndex(textPtr->tree, lineNum, matchChar, &index); + TkTextMakeByteIndex(textPtr->tree, lineNum, matchByte, &index); if (!searchWholeText) { if (!backwards && (TkTextIndexCmp(&index, &stopIndex) >= 0)) { goto done; @@ -1950,14 +2073,15 @@ TextSearchCmd(textPtr, interp, argc, argv) } } if (varName != NULL) { - sprintf(buffer, "%d", matchLength); + sprintf(buffer, "%d", numChars); if (Tcl_SetVar(interp, varName, buffer, TCL_LEAVE_ERR_MSG) == NULL) { code = TCL_ERROR; goto done; } } - TkTextPrintIndex(&index, interp->result); + TkTextPrintIndex(&index, buffer); + Tcl_SetResult(interp, buffer, TCL_VOLATILE); goto done; } @@ -1989,9 +2113,12 @@ TextSearchCmd(textPtr, interp, argc, argv) } done: Tcl_DStringFree(&line); - if (noCase) { + if (noCase && exact) { Tcl_DStringFree(&patDString); } + if (patObj != NULL) { + Tcl_DecrRefCount(patObj); + } return code; } @@ -2006,7 +2133,7 @@ TextSearchCmd(textPtr, interp, argc, argv) * The return value is a pointer to a malloc'ed structure holding * parsed information about the tab stops. If an error occurred * then the return value is NULL and an error message is left in - * interp->result. + * the interp's result. * * Side effects: * Memory is allocated for the structure that is returned. It is @@ -2028,6 +2155,7 @@ TkTextGetTabs(interp, tkwin, string) char **argv; TkTextTabArray *tabArrayPtr; TkTextTab *tabPtr; + Tcl_UniChar ch; if (Tcl_SplitList(interp, string, &argc, &argv) != TCL_OK) { return NULL; @@ -2070,11 +2198,12 @@ TkTextGetTabs(interp, tkwin, string) if ((i+1) == argc) { continue; } - c = UCHAR(argv[i+1][0]); - if (!isalpha(c)) { + Tcl_UtfToUniChar(argv[i+1], &ch); + if (!Tcl_UniCharIsAlpha(ch)) { continue; } i += 1; + c = argv[i][0]; if ((c == 'l') && (strncmp(argv[i], "left", strlen(argv[i])) == 0)) { tabPtr->alignment = LEFT; @@ -2186,7 +2315,7 @@ TextDumpCmd(textPtr, interp, argc, argv) if (TkTextGetIndex(interp, textPtr, argv[arg], &index1) != TCL_OK) { return TCL_ERROR; } - lineno = TkBTreeLineIndex(index1.linePtr) + 1; + lineno = TkBTreeLineIndex(index1.linePtr); arg++; atEnd = 0; if (argc == arg) { @@ -2204,10 +2333,10 @@ TextDumpCmd(textPtr, interp, argc, argv) } if (index1.linePtr == index2.linePtr) { DumpLine(interp, textPtr, what, index1.linePtr, - index1.charIndex, index2.charIndex, lineno, command); + index1.byteIndex, index2.byteIndex, lineno, command); } else { DumpLine(interp, textPtr, what, index1.linePtr, - index1.charIndex, 32000000, lineno, command); + index1.byteIndex, 32000000, lineno, command); linePtr = index1.linePtr; while ((linePtr = TkBTreeNextLine(linePtr)) != (TkTextLine *)NULL) { lineno++; @@ -2218,14 +2347,14 @@ TextDumpCmd(textPtr, interp, argc, argv) lineno, command); } DumpLine(interp, textPtr, what, index2.linePtr, 0, - index2.charIndex, lineno, command); + index2.byteIndex, lineno, command); } /* * Special case to get the leftovers hiding at the end mark. */ if (atEnd) { DumpLine(interp, textPtr, what & ~TK_DUMP_TEXT, index2.linePtr, - 0, 1, lineno, command); + 0, 1, lineno, command); } return TCL_OK; @@ -2243,17 +2372,18 @@ TextDumpCmd(textPtr, interp, argc, argv) * None, but see DumpSegment. */ static void -DumpLine(interp, textPtr, what, linePtr, start, end, lineno, command) +DumpLine(interp, textPtr, what, linePtr, startByte, endByte, lineno, command) Tcl_Interp *interp; TkText *textPtr; int what; /* bit flags to select segment types */ TkTextLine *linePtr; /* The current line */ - int start, end; /* Character range to dump */ + int startByte, endByte; /* Byte range to dump */ int lineno; /* Line number for indices dump */ char *command; /* Script to apply to the segment */ { int offset; TkTextSegment *segPtr; + TkTextIndex index; /* * Must loop through line looking at its segments. * character @@ -2262,47 +2392,54 @@ DumpLine(interp, textPtr, what, linePtr, start, end, lineno, command) * image * window */ + for (offset = 0, segPtr = linePtr->segPtr ; - (offset < end) && (segPtr != (TkTextSegment *)NULL) ; + (offset < endByte) && (segPtr != (TkTextSegment *)NULL) ; offset += segPtr->size, segPtr = segPtr->nextPtr) { if ((what & TK_DUMP_TEXT) && (segPtr->typePtr == &tkTextCharType) && - (offset + segPtr->size > start)) { + (offset + segPtr->size > startByte)) { char savedChar; /* Last char used in the seg */ int last = segPtr->size; /* Index of savedChar */ int first = 0; /* Index of first char in seg */ - if (offset + segPtr->size > end) { - last = end - offset; + if (offset + segPtr->size > endByte) { + last = endByte - offset; } - if (start > offset) { - first = start - offset; + if (startByte > offset) { + first = startByte - offset; } savedChar = segPtr->body.chars[last]; segPtr->body.chars[last] = '\0'; + + TkTextMakeByteIndex(textPtr->tree, lineno, offset + first, &index); DumpSegment(interp, "text", segPtr->body.chars + first, - command, lineno, offset + first, what); + command, &index, what); segPtr->body.chars[last] = savedChar; - } else if ((offset >= start)) { + } else if ((offset >= startByte)) { if ((what & TK_DUMP_MARK) && (segPtr->typePtr->name[0] == 'm')) { TkTextMark *markPtr = (TkTextMark *)&segPtr->body; char *name = Tcl_GetHashKey(&textPtr->markTable, markPtr->hPtr); - DumpSegment(interp, "mark", name, - command, lineno, offset, what); + + TkTextMakeByteIndex(textPtr->tree, lineno, offset, &index); + DumpSegment(interp, "mark", name, command, &index, what); } else if ((what & TK_DUMP_TAG) && (segPtr->typePtr == &tkTextToggleOnType)) { + TkTextMakeByteIndex(textPtr->tree, lineno, offset, &index); DumpSegment(interp, "tagon", segPtr->body.toggle.tagPtr->name, - command, lineno, offset, what); + command, &index, what); } else if ((what & TK_DUMP_TAG) && (segPtr->typePtr == &tkTextToggleOffType)) { + TkTextMakeByteIndex(textPtr->tree, lineno, offset, &index); DumpSegment(interp, "tagoff", segPtr->body.toggle.tagPtr->name, - command, lineno, offset, what); + command, &index, what); } else if ((what & TK_DUMP_IMG) && (segPtr->typePtr->name[0] == 'i')) { TkTextEmbImage *eiPtr = (TkTextEmbImage *)&segPtr->body; char *name = (eiPtr->name == NULL) ? "" : eiPtr->name; + TkTextMakeByteIndex(textPtr->tree, lineno, offset, &index); DumpSegment(interp, "image", name, - command, lineno, offset, what); + command, &index, what); } else if ((what & TK_DUMP_WIN) && (segPtr->typePtr->name[0] == 'w')) { TkTextEmbWindow *ewPtr = (TkTextEmbWindow *)&segPtr->body; @@ -2312,8 +2449,9 @@ DumpLine(interp, textPtr, what, linePtr, start, end, lineno, command) } else { pathname = Tk_PathName(ewPtr->tkwin); } + TkTextMakeByteIndex(textPtr->tree, lineno, offset, &index); DumpSegment(interp, "window", pathname, - command, lineno, offset, what); + command, &index, what); } } } @@ -2331,17 +2469,16 @@ DumpLine(interp, textPtr, what, linePtr, start, end, lineno, command) * Either evals the callback or appends elements to the result string. */ static int -DumpSegment(interp, key, value, command, lineno, offset, what) +DumpSegment(interp, key, value, command, index, what) Tcl_Interp *interp; char *key; /* Segment type key */ char *value; /* Segment value */ char *command; /* Script callback */ - int lineno; /* Line number for indices dump */ - int offset; /* Character position */ + TkTextIndex *index; /* index with line/byte position info */ int what; /* Look for TK_DUMP_INDEX bit */ { - char buffer[30]; - sprintf(buffer, "%d.%d", lineno, offset); + char buffer[TCL_INTEGER_SPACE*2]; + TkTextPrintIndex(index, buffer); if (command == (char *) NULL) { Tcl_AppendElement(interp, key); Tcl_AppendElement(interp, value); @@ -2362,3 +2499,5 @@ DumpSegment(interp, key, value, command, lineno, offset, what) } } + + diff --git a/tk/generic/tkText.h b/tk/generic/tkText.h index e8c0ab2440e..9152e2c7264 100644 --- a/tk/generic/tkText.h +++ b/tk/generic/tkText.h @@ -20,6 +20,11 @@ #include "tk.h" #endif +#ifdef BUILD_tk +# undef TCL_STORAGE_CLASS +# define TCL_STORAGE_CLASS DLLEXPORT +#endif + /* * Opaque types for structures whose guts are only needed by a single * file: @@ -176,7 +181,7 @@ typedef struct TkTextIndex { TkTextBTree tree; /* Tree containing desired position. */ TkTextLine *linePtr; /* Pointer to line containing position * of interest. */ - int charIndex; /* Index within line of desired + int byteIndex; /* Index within line of desired * character (0 means first one). */ } TkTextIndex; @@ -241,7 +246,7 @@ struct TkTextDispChunk { * a given x-location. */ Tk_ChunkBboxProc *bboxProc; /* Procedure to find bounding box * of character in chunk. */ - int numChars; /* Number of characters that will be + int numBytes; /* Number of bytes that will be * displayed in the chunk. */ int minAscent; /* Minimum space above the baseline * needed by this chunk. */ @@ -256,7 +261,7 @@ struct TkTextDispChunk { * of line. */ int breakIndex; /* Index within chunk of last * acceptable position for a line - * (break just before this character). + * (break just before this byte index). * <= 0 means don't break during or * immediately after this chunk. */ ClientData clientData; /* Additional information for use @@ -269,6 +274,12 @@ struct TkTextDispChunk { * referred to in other structures. */ +typedef enum { TEXT_WRAPMODE_NULL, TEXT_WRAPMODE_NONE, + TEXT_WRAPMODE_CHAR, TEXT_WRAPMODE_WORD +} TkWrapMode; + +EXTERN Tk_CustomOption textWrapModeOption; + typedef struct TkTextTag { char *name; /* Name of this tag. This field is actually * a pointer to the key from the entry in @@ -366,10 +377,15 @@ typedef struct TkTextTag { int underline; /* Non-zero means draw underline underneath * text. Only valid if underlineString is * non-NULL. */ - Tk_Uid wrapMode; /* How to handle wrap-around for this tag. - * Must be tkTextCharUid, tkTextNoneUid, - * tkTextWordUid, or NULL to use wrapMode - * for whole widget. */ + TkWrapMode wrapMode; /* How to handle wrap-around for this tag. + * Must be TEXT_WRAPMODE_CHAR, + * TEXT_WRAPMODE_NONE, TEXT_WRAPMODE_WORD, + * or TEXT_WRAPMODE_NULL to use wrapmode for + * whole widget. */ + char *elideString; /* -elide option string (malloc-ed). + * NULL means option not specified. */ + int elide; /* Non-zero means that data under this tag + * should not be displayed. */ int affectsDisplay; /* Non-zero means that this tag affects the * way information is displayed on the screen * (so need to redisplay if tag changes). */ @@ -470,8 +486,8 @@ typedef struct TkText { * image segment doesn't yet have an * associated image, there is no entry for * it here. */ - Tk_Uid state; /* Normal or disabled. Text is read-only - * when disabled. */ + int state; /* Either STATE_NORMAL or STATE_DISABLED. A + * text widget is read-only when disabled. */ /* * Default information for displaying (may be overridden by tags @@ -518,9 +534,9 @@ typedef struct TkText { * Additional information used for displaying: */ - Tk_Uid wrapMode; /* How to handle wrap-around. Must be - * tkTextCharUid, tkTextNoneUid, or - * tkTextWordUid. */ + TkWrapMode wrapMode; /* How to handle wrap-around. Must be + * TEXT_WRAPMODE_CHAR, TEXT_WRAPMODE_NONE, or + * TEXT_WRAPMODE_WORD. */ int width, height; /* Desired dimensions for window, measured * in characters. */ int setGrid; /* Non-zero means pass gridding information @@ -661,7 +677,7 @@ typedef void Tk_SegLineChangeProc _ANSI_ARGS_(( typedef int Tk_SegLayoutProc _ANSI_ARGS_((struct TkText *textPtr, struct TkTextIndex *indexPtr, TkTextSegment *segPtr, int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, + int noCharsYet, TkWrapMode wrapMode, struct TkTextDispChunk *chunkPtr)); typedef void Tk_SegCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, TkTextLine *linePtr)); @@ -717,141 +733,156 @@ typedef struct Tk_SegType { * Declarations for variables shared among the text-related files: */ -extern int tkBTreeDebug; -extern int tkTextDebug; -extern Tk_SegType tkTextCharType; -extern Tk_Uid tkTextCharUid; -extern Tk_Uid tkTextDisabledUid; -extern Tk_SegType tkTextLeftMarkType; -extern Tk_Uid tkTextNoneUid; -extern Tk_Uid tkTextNormalUid; -extern Tk_SegType tkTextRightMarkType; -extern Tk_SegType tkTextToggleOnType; -extern Tk_SegType tkTextToggleOffType; -extern Tk_Uid tkTextWordUid; +EXTERN int tkBTreeDebug; +EXTERN int tkTextDebug; +EXTERN Tk_SegType tkTextCharType; +EXTERN Tk_SegType tkTextLeftMarkType; +EXTERN Tk_SegType tkTextRightMarkType; +EXTERN Tk_SegType tkTextToggleOnType; +EXTERN Tk_SegType tkTextToggleOffType; /* * Declarations for procedures that are used by the text-related files * but shouldn't be used anywhere else in Tk (or by Tk clients): */ -extern int TkBTreeCharTagged _ANSI_ARGS_((TkTextIndex *indexPtr, +EXTERN int TkBTreeCharTagged _ANSI_ARGS_((TkTextIndex *indexPtr, TkTextTag *tagPtr)); -extern void TkBTreeCheck _ANSI_ARGS_((TkTextBTree tree)); -extern int TkBTreeCharsInLine _ANSI_ARGS_((TkTextLine *linePtr)); -extern TkTextBTree TkBTreeCreate _ANSI_ARGS_((TkText *textPtr)); -extern void TkBTreeDestroy _ANSI_ARGS_((TkTextBTree tree)); -extern void TkBTreeDeleteChars _ANSI_ARGS_((TkTextIndex *index1Ptr, +EXTERN void TkBTreeCheck _ANSI_ARGS_((TkTextBTree tree)); +EXTERN int TkBTreeCharsInLine _ANSI_ARGS_((TkTextLine *linePtr)); +EXTERN int TkBTreeBytesInLine _ANSI_ARGS_((TkTextLine *linePtr)); +EXTERN TkTextBTree TkBTreeCreate _ANSI_ARGS_((TkText *textPtr)); +EXTERN void TkBTreeDestroy _ANSI_ARGS_((TkTextBTree tree)); +EXTERN void TkBTreeDeleteChars _ANSI_ARGS_((TkTextIndex *index1Ptr, TkTextIndex *index2Ptr)); -extern TkTextLine * TkBTreeFindLine _ANSI_ARGS_((TkTextBTree tree, +EXTERN TkTextLine * TkBTreeFindLine _ANSI_ARGS_((TkTextBTree tree, int line)); -extern TkTextTag ** TkBTreeGetTags _ANSI_ARGS_((TkTextIndex *indexPtr, +EXTERN TkTextTag ** TkBTreeGetTags _ANSI_ARGS_((TkTextIndex *indexPtr, int *numTagsPtr)); -extern void TkBTreeInsertChars _ANSI_ARGS_((TkTextIndex *indexPtr, +EXTERN void TkBTreeInsertChars _ANSI_ARGS_((TkTextIndex *indexPtr, char *string)); -extern int TkBTreeLineIndex _ANSI_ARGS_((TkTextLine *linePtr)); -extern void TkBTreeLinkSegment _ANSI_ARGS_((TkTextSegment *segPtr, +EXTERN int TkBTreeLineIndex _ANSI_ARGS_((TkTextLine *linePtr)); +EXTERN void TkBTreeLinkSegment _ANSI_ARGS_((TkTextSegment *segPtr, TkTextIndex *indexPtr)); -extern TkTextLine * TkBTreeNextLine _ANSI_ARGS_((TkTextLine *linePtr)); -extern int TkBTreeNextTag _ANSI_ARGS_((TkTextSearch *searchPtr)); -extern int TkBTreeNumLines _ANSI_ARGS_((TkTextBTree tree)); -extern TkTextLine * TkBTreePreviousLine _ANSI_ARGS_((TkTextLine *linePtr)); -extern int TkBTreePrevTag _ANSI_ARGS_((TkTextSearch *searchPtr)); -extern void TkBTreeStartSearch _ANSI_ARGS_((TkTextIndex *index1Ptr, +EXTERN TkTextLine * TkBTreeNextLine _ANSI_ARGS_((TkTextLine *linePtr)); +EXTERN int TkBTreeNextTag _ANSI_ARGS_((TkTextSearch *searchPtr)); +EXTERN int TkBTreeNumLines _ANSI_ARGS_((TkTextBTree tree)); +EXTERN TkTextLine * TkBTreePreviousLine _ANSI_ARGS_((TkTextLine *linePtr)); +EXTERN int TkBTreePrevTag _ANSI_ARGS_((TkTextSearch *searchPtr)); +EXTERN void TkBTreeStartSearch _ANSI_ARGS_((TkTextIndex *index1Ptr, TkTextIndex *index2Ptr, TkTextTag *tagPtr, TkTextSearch *searchPtr)); -extern void TkBTreeStartSearchBack _ANSI_ARGS_((TkTextIndex *index1Ptr, +EXTERN void TkBTreeStartSearchBack _ANSI_ARGS_((TkTextIndex *index1Ptr, TkTextIndex *index2Ptr, TkTextTag *tagPtr, TkTextSearch *searchPtr)); -extern void TkBTreeTag _ANSI_ARGS_((TkTextIndex *index1Ptr, +EXTERN void TkBTreeTag _ANSI_ARGS_((TkTextIndex *index1Ptr, TkTextIndex *index2Ptr, TkTextTag *tagPtr, int add)); -extern void TkBTreeUnlinkSegment _ANSI_ARGS_((TkTextBTree tree, +EXTERN void TkBTreeUnlinkSegment _ANSI_ARGS_((TkTextBTree tree, TkTextSegment *segPtr, TkTextLine *linePtr)); -extern void TkTextBindProc _ANSI_ARGS_((ClientData clientData, +EXTERN void TkTextBindProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); -extern void TkTextChanged _ANSI_ARGS_((TkText *textPtr, +EXTERN void TkTextChanged _ANSI_ARGS_((TkText *textPtr, TkTextIndex *index1Ptr, TkTextIndex *index2Ptr)); -extern int TkTextCharBbox _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextCharBbox _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, int *xPtr, int *yPtr, int *widthPtr, int *heightPtr)); -extern int TkTextCharLayoutProc _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextCharLayoutProc _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, TkTextSegment *segPtr, int offset, int maxX, int maxChars, int noBreakYet, - Tk_Uid wrapMode, TkTextDispChunk *chunkPtr)); -extern void TkTextCreateDInfo _ANSI_ARGS_((TkText *textPtr)); -extern int TkTextDLineInfo _ANSI_ARGS_((TkText *textPtr, + TkWrapMode wrapMode, TkTextDispChunk *chunkPtr)); +EXTERN void TkTextCreateDInfo _ANSI_ARGS_((TkText *textPtr)); +EXTERN int TkTextDLineInfo _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, int *xPtr, int *yPtr, int *widthPtr, int *heightPtr, int *basePtr)); -extern TkTextTag * TkTextCreateTag _ANSI_ARGS_((TkText *textPtr, +EXTERN TkTextTag * TkTextCreateTag _ANSI_ARGS_((TkText *textPtr, char *tagName)); -extern void TkTextFreeDInfo _ANSI_ARGS_((TkText *textPtr)); -extern void TkTextFreeTag _ANSI_ARGS_((TkText *textPtr, +EXTERN void TkTextFreeDInfo _ANSI_ARGS_((TkText *textPtr)); +EXTERN void TkTextFreeTag _ANSI_ARGS_((TkText *textPtr, TkTextTag *tagPtr)); -extern int TkTextGetIndex _ANSI_ARGS_((Tcl_Interp *interp, +EXTERN int TkTextGetIndex _ANSI_ARGS_((Tcl_Interp *interp, TkText *textPtr, char *string, TkTextIndex *indexPtr)); -extern TkTextTabArray * TkTextGetTabs _ANSI_ARGS_((Tcl_Interp *interp, +EXTERN TkTextTabArray * TkTextGetTabs _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, char *string)); -extern void TkTextIndexBackChars _ANSI_ARGS_((TkTextIndex *srcPtr, - int count, TkTextIndex *dstPtr)); -extern int TkTextIndexCmp _ANSI_ARGS_((TkTextIndex *index1Ptr, - TkTextIndex *index2Ptr)); -extern void TkTextIndexForwChars _ANSI_ARGS_((TkTextIndex *srcPtr, - int count, TkTextIndex *dstPtr)); -extern TkTextSegment * TkTextIndexToSeg _ANSI_ARGS_((TkTextIndex *indexPtr, - int *offsetPtr)); -extern void TkTextInsertDisplayProc _ANSI_ARGS_(( +EXTERN void TkTextIndexBackBytes _ANSI_ARGS_(( + CONST TkTextIndex *srcPtr, int count, + TkTextIndex *dstPtr)); +EXTERN void TkTextIndexBackChars _ANSI_ARGS_(( + CONST TkTextIndex *srcPtr, int count, + TkTextIndex *dstPtr)); +EXTERN int TkTextIndexCmp _ANSI_ARGS_(( + CONST TkTextIndex *index1Ptr, + CONST TkTextIndex *index2Ptr)); +EXTERN void TkTextIndexForwBytes _ANSI_ARGS_(( + CONST TkTextIndex *srcPtr, int count, + TkTextIndex *dstPtr)); +EXTERN void TkTextIndexForwChars _ANSI_ARGS_(( + CONST TkTextIndex *srcPtr, int count, + TkTextIndex *dstPtr)); +EXTERN TkTextSegment * TkTextIndexToSeg _ANSI_ARGS_(( + CONST TkTextIndex *indexPtr, int *offsetPtr)); +EXTERN void TkTextInsertDisplayProc _ANSI_ARGS_(( TkTextDispChunk *chunkPtr, int x, int y, int height, int baseline, Display *display, Drawable dst, int screenY)); -extern void TkTextLostSelection _ANSI_ARGS_(( +EXTERN void TkTextLostSelection _ANSI_ARGS_(( ClientData clientData)); -extern TkTextIndex * TkTextMakeIndex _ANSI_ARGS_((TkTextBTree tree, +EXTERN TkTextIndex * TkTextMakeCharIndex _ANSI_ARGS_((TkTextBTree tree, int lineIndex, int charIndex, TkTextIndex *indexPtr)); -extern int TkTextMarkCmd _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextIsElided _ANSI_ARGS_((TkText *textPtr, + TkTextIndex *indexPtr)); +EXTERN TkTextIndex * TkTextMakeByteIndex _ANSI_ARGS_((TkTextBTree tree, + int lineIndex, int byteIndex, + TkTextIndex *indexPtr)); +EXTERN int TkTextMarkCmd _ANSI_ARGS_((TkText *textPtr, Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextMarkNameToIndex _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextMarkNameToIndex _ANSI_ARGS_((TkText *textPtr, char *name, TkTextIndex *indexPtr)); -extern void TkTextMarkSegToIndex _ANSI_ARGS_((TkText *textPtr, +EXTERN void TkTextMarkSegToIndex _ANSI_ARGS_((TkText *textPtr, TkTextSegment *markPtr, TkTextIndex *indexPtr)); -extern void TkTextEventuallyRepick _ANSI_ARGS_((TkText *textPtr)); -extern void TkTextPickCurrent _ANSI_ARGS_((TkText *textPtr, +EXTERN void TkTextEventuallyRepick _ANSI_ARGS_((TkText *textPtr)); +EXTERN void TkTextPickCurrent _ANSI_ARGS_((TkText *textPtr, XEvent *eventPtr)); -extern void TkTextPixelIndex _ANSI_ARGS_((TkText *textPtr, +EXTERN void TkTextPixelIndex _ANSI_ARGS_((TkText *textPtr, int x, int y, TkTextIndex *indexPtr)); -extern void TkTextPrintIndex _ANSI_ARGS_((TkTextIndex *indexPtr, - char *string)); -extern void TkTextRedrawRegion _ANSI_ARGS_((TkText *textPtr, +EXTERN void TkTextPrintIndex _ANSI_ARGS_(( + CONST TkTextIndex *indexPtr, char *string)); +EXTERN void TkTextRedrawRegion _ANSI_ARGS_((TkText *textPtr, int x, int y, int width, int height)); -extern void TkTextRedrawTag _ANSI_ARGS_((TkText *textPtr, +EXTERN void TkTextRedrawTag _ANSI_ARGS_((TkText *textPtr, TkTextIndex *index1Ptr, TkTextIndex *index2Ptr, TkTextTag *tagPtr, int withTag)); -extern void TkTextRelayoutWindow _ANSI_ARGS_((TkText *textPtr)); -extern int TkTextScanCmd _ANSI_ARGS_((TkText *textPtr, +EXTERN void TkTextRelayoutWindow _ANSI_ARGS_((TkText *textPtr)); +EXTERN int TkTextScanCmd _ANSI_ARGS_((TkText *textPtr, Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextSeeCmd _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextSeeCmd _ANSI_ARGS_((TkText *textPtr, Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextSegToOffset _ANSI_ARGS_((TkTextSegment *segPtr, - TkTextLine *linePtr)); -extern TkTextSegment * TkTextSetMark _ANSI_ARGS_((TkText *textPtr, char *name, +EXTERN int TkTextSegToOffset _ANSI_ARGS_(( + CONST TkTextSegment *segPtr, + CONST TkTextLine *linePtr)); +EXTERN TkTextSegment * TkTextSetMark _ANSI_ARGS_((TkText *textPtr, char *name, TkTextIndex *indexPtr)); -extern void TkTextSetYView _ANSI_ARGS_((TkText *textPtr, +EXTERN void TkTextSetYView _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, int pickPlace)); -extern int TkTextTagCmd _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextTagCmd _ANSI_ARGS_((TkText *textPtr, Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextImageCmd _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextImageCmd _ANSI_ARGS_((TkText *textPtr, Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextImageIndex _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextImageIndex _ANSI_ARGS_((TkText *textPtr, char *name, TkTextIndex *indexPtr)); -extern int TkTextWindowCmd _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextWindowCmd _ANSI_ARGS_((TkText *textPtr, Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextWindowIndex _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextWindowIndex _ANSI_ARGS_((TkText *textPtr, char *name, TkTextIndex *indexPtr)); -extern int TkTextXviewCmd _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextXviewCmd _ANSI_ARGS_((TkText *textPtr, Tcl_Interp *interp, int argc, char **argv)); -extern int TkTextYviewCmd _ANSI_ARGS_((TkText *textPtr, +EXTERN int TkTextYviewCmd _ANSI_ARGS_((TkText *textPtr, Tcl_Interp *interp, int argc, char **argv)); +# undef TCL_STORAGE_CLASS +# define TCL_STORAGE_CLASS DLLIMPORT + #endif /* _TKTEXT */ + diff --git a/tk/generic/tkTextBTree.c b/tk/generic/tkTextBTree.c index 128edd29550..42fa1b2cba4 100644 --- a/tk/generic/tkTextBTree.c +++ b/tk/generic/tkTextBTree.c @@ -535,7 +535,7 @@ SplitSeg(indexPtr) TkTextSegment *prevPtr, *segPtr; int count; - for (count = indexPtr->charIndex, prevPtr = NULL, + for (count = indexPtr->byteIndex, prevPtr = NULL, segPtr = indexPtr->linePtr->segPtr; segPtr != NULL; count -= segPtr->size, prevPtr = segPtr, segPtr = segPtr->nextPtr) { if (segPtr->size > count) { @@ -1530,7 +1530,7 @@ FindTagStart(tree, tagPtr, indexPtr) */ indexPtr->tree = tree; indexPtr->linePtr = linePtr; - indexPtr->charIndex = offset; + indexPtr->byteIndex = offset; return segPtr; } } @@ -1619,7 +1619,7 @@ FindTagEnd(tree, tagPtr, indexPtr) } indexPtr->tree = tree; indexPtr->linePtr = lastLinePtr; - indexPtr->charIndex = lastoffset2; + indexPtr->byteIndex = lastoffset2; return last2SegPtr; } @@ -1694,7 +1694,7 @@ TkBTreeStartSearch(index1Ptr, index2Ptr, tagPtr, searchPtr) searchPtr->curIndex = *index1Ptr; searchPtr->segPtr = NULL; searchPtr->nextPtr = TkTextIndexToSeg(index1Ptr, &offset); - searchPtr->curIndex.charIndex -= offset; + searchPtr->curIndex.byteIndex -= offset; } searchPtr->lastPtr = TkTextIndexToSeg(index2Ptr, (int *) NULL); searchPtr->tagPtr = tagPtr; @@ -1709,9 +1709,9 @@ TkBTreeStartSearch(index1Ptr, index2Ptr, tagPtr, searchPtr) * the range, unless the range is artificially moved up to index0. */ if (((index1Ptr == &index0) && - (index1Ptr->charIndex > index2Ptr->charIndex)) || + (index1Ptr->byteIndex > index2Ptr->byteIndex)) || ((index1Ptr != &index0) && - (index1Ptr->charIndex >= index2Ptr->charIndex))) { + (index1Ptr->byteIndex >= index2Ptr->byteIndex))) { searchPtr->linesLeft = 0; } } @@ -1793,7 +1793,7 @@ TkBTreeStartSearchBack(index1Ptr, index2Ptr, tagPtr, searchPtr) } searchPtr->segPtr = NULL; searchPtr->nextPtr = TkTextIndexToSeg(&searchPtr->curIndex, &offset); - searchPtr->curIndex.charIndex -= offset; + searchPtr->curIndex.byteIndex -= offset; /* * Adjust the end of the search so it does find toggles that are right @@ -1801,7 +1801,7 @@ TkBTreeStartSearchBack(index1Ptr, index2Ptr, tagPtr, searchPtr) */ if ((TkBTreeLineIndex(index2Ptr->linePtr) == 0) && - (index2Ptr->charIndex == 0)) { + (index2Ptr->byteIndex == 0)) { backOne = *index2Ptr; searchPtr->lastPtr = NULL; /* Signals special case for 1.0 */ } else { @@ -1819,7 +1819,7 @@ TkBTreeStartSearchBack(index1Ptr, index2Ptr, tagPtr, searchPtr) * first. */ - if (index1Ptr->charIndex <= backOne.charIndex) { + if (index1Ptr->byteIndex <= backOne.byteIndex) { searchPtr->linesLeft = 0; } } @@ -1889,7 +1889,7 @@ TkBTreeNextTag(searchPtr) searchPtr->tagPtr = segPtr->body.toggle.tagPtr; return 1; } - searchPtr->curIndex.charIndex += segPtr->size; + searchPtr->curIndex.byteIndex += segPtr->size; } /* @@ -1906,7 +1906,7 @@ TkBTreeNextTag(searchPtr) } if (searchPtr->curIndex.linePtr != NULL) { segPtr = searchPtr->curIndex.linePtr->segPtr; - searchPtr->curIndex.charIndex = 0; + searchPtr->curIndex.byteIndex = 0; continue; } if (nodePtr == searchPtr->tagPtr->tagRootPtr) { @@ -1972,7 +1972,7 @@ TkBTreeNextTag(searchPtr) */ searchPtr->curIndex.linePtr = nodePtr->children.linePtr; - searchPtr->curIndex.charIndex = 0; + searchPtr->curIndex.byteIndex = 0; segPtr = searchPtr->curIndex.linePtr->segPtr; if (searchPtr->linesLeft <= 0) { goto searchOver; @@ -2022,7 +2022,7 @@ TkBTreePrevTag(searchPtr) register TkTextLine *linePtr, *prevLinePtr; register Node *nodePtr, *node2Ptr, *prevNodePtr; register Summary *summaryPtr; - int charIndex; + int byteIndex; int pastLast; /* Saw last marker during scan */ int linesSkipped; @@ -2041,7 +2041,7 @@ TkBTreePrevTag(searchPtr) /* * Check for the last toggle before the current segment on this line. */ - charIndex = 0; + byteIndex = 0; if (searchPtr->lastPtr == NULL) { /* * Search back to the very beginning, so pastLast is irrelevent. @@ -2058,13 +2058,13 @@ TkBTreePrevTag(searchPtr) && (searchPtr->allTags || (segPtr->body.toggle.tagPtr == searchPtr->tagPtr))) { prevPtr = segPtr; - searchPtr->curIndex.charIndex = charIndex; + searchPtr->curIndex.byteIndex = byteIndex; } if (segPtr == searchPtr->lastPtr) { prevPtr = NULL; /* Segments earlier than last don't count */ pastLast = 1; } - charIndex += segPtr->size; + byteIndex += segPtr->size; } if (prevPtr != NULL) { if (searchPtr->linesLeft == 1 && !pastLast) { @@ -2191,7 +2191,7 @@ TkBTreePrevTag(searchPtr) /* empty loop body */ ; } searchPtr->curIndex.linePtr = prevLinePtr; - searchPtr->curIndex.charIndex = 0; + searchPtr->curIndex.byteIndex = 0; if (searchPtr->linesLeft <= 0) { goto searchOver; } @@ -2241,7 +2241,7 @@ TkBTreeCharTagged(indexPtr, tagPtr) toggleSegPtr = NULL; for (index = 0, segPtr = indexPtr->linePtr->segPtr; - (index + segPtr->size) <= indexPtr->charIndex; + (index + segPtr->size) <= indexPtr->byteIndex; index += segPtr->size, segPtr = segPtr->nextPtr) { if (((segPtr->typePtr == &tkTextToggleOnType) || (segPtr->typePtr == &tkTextToggleOffType)) @@ -2360,7 +2360,7 @@ TkBTreeGetTags(indexPtr, numTagsPtr) */ for (index = 0, segPtr = indexPtr->linePtr->segPtr; - (index + segPtr->size) <= indexPtr->charIndex; + (index + segPtr->size) <= indexPtr->byteIndex; index += segPtr->size, segPtr = segPtr->nextPtr) { if ((segPtr->typePtr == &tkTextToggleOnType) || (segPtr->typePtr == &tkTextToggleOffType)) { @@ -2431,6 +2431,148 @@ TkBTreeGetTags(indexPtr, numTagsPtr) /* *---------------------------------------------------------------------- * + * TkTextIsElided -- + * + * Special case to just return information about elided attribute. + * Specialized from TkBTreeGetTags(indexPtr, numTagsPtr) + * and GetStyle(textPtr, indexPtr). + * Just need to keep track of invisibility settings for each priority, + * pick highest one active at end + * + * Results: + * Returns whether this text should be elided or not. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +TkTextIsElided(textPtr, indexPtr) + TkText *textPtr; /* Overall information about text widget. */ + TkTextIndex *indexPtr; /* The character in the text for which + * display information is wanted. */ +{ +#define LOTSA_TAGS 1000 + int elide = 0; /* if nobody says otherwise, it's visible */ + + int deftagCnts[LOTSA_TAGS]; + int *tagCnts = deftagCnts; + TkTextTag *deftagPtrs[LOTSA_TAGS]; + TkTextTag **tagPtrs = deftagPtrs; + int numTags = textPtr->numTags; + register Node *nodePtr; + register TkTextLine *siblingLinePtr; + register TkTextSegment *segPtr; + register TkTextTag *tagPtr; + register int i, index; + + /* almost always avoid malloc, so stay out of system calls */ + if (LOTSA_TAGS < numTags) { + tagCnts = (int *)ckalloc((unsigned)sizeof(int) * numTags); + tagPtrs = (TkTextTag **)ckalloc((unsigned)sizeof(TkTextTag *) * numTags); + } + + for (i=0; i<numTags; i++) { + tagCnts[i] = 0; + } + + /* + * Record tag toggles within the line of indexPtr but preceding + * indexPtr. + */ + + for (index = 0, segPtr = indexPtr->linePtr->segPtr; + (index + segPtr->size) <= indexPtr->byteIndex; + index += segPtr->size, segPtr = segPtr->nextPtr) { + if ((segPtr->typePtr == &tkTextToggleOnType) + || (segPtr->typePtr == &tkTextToggleOffType)) { + tagPtr = segPtr->body.toggle.tagPtr; + if (tagPtr->elideString != NULL) { + tagPtrs[tagPtr->priority] = tagPtr; + tagCnts[tagPtr->priority]++; + } + } + } + + /* + * Record toggles for tags in lines that are predecessors of + * indexPtr->linePtr but under the same level-0 node. + */ + + for (siblingLinePtr = indexPtr->linePtr->parentPtr->children.linePtr; + siblingLinePtr != indexPtr->linePtr; + siblingLinePtr = siblingLinePtr->nextPtr) { + for (segPtr = siblingLinePtr->segPtr; segPtr != NULL; + segPtr = segPtr->nextPtr) { + if ((segPtr->typePtr == &tkTextToggleOnType) + || (segPtr->typePtr == &tkTextToggleOffType)) { + tagPtr = segPtr->body.toggle.tagPtr; + if (tagPtr->elideString != NULL) { + tagPtrs[tagPtr->priority] = tagPtr; + tagCnts[tagPtr->priority]++; + } + } + } + } + + /* + * For each node in the ancestry of this line, record tag toggles + * for all siblings that precede that node. + */ + + for (nodePtr = indexPtr->linePtr->parentPtr; nodePtr->parentPtr != NULL; + nodePtr = nodePtr->parentPtr) { + register Node *siblingPtr; + register Summary *summaryPtr; + + for (siblingPtr = nodePtr->parentPtr->children.nodePtr; + siblingPtr != nodePtr; siblingPtr = siblingPtr->nextPtr) { + for (summaryPtr = siblingPtr->summaryPtr; summaryPtr != NULL; + summaryPtr = summaryPtr->nextPtr) { + if (summaryPtr->toggleCount & 1) { + tagPtr = summaryPtr->tagPtr; + if (tagPtr->elideString != NULL) { + tagPtrs[tagPtr->priority] = tagPtr; + tagCnts[tagPtr->priority] += summaryPtr->toggleCount; + } + } + } + } + } + + /* + * Now traverse from highest priority to lowest, + * take elided value from first odd count (= on) + */ + + for (i = numTags-1; i >=0; i--) { + if (tagCnts[i] & 1) { +#ifndef ALWAYS_SHOW_SELECTION + /* who would make the selection elided? */ + if ((tagPtr == textPtr->selTagPtr) + && !(textPtr->flags & GOT_FOCUS)) { + continue; + } +#endif + elide = tagPtrs[i]->elide; + break; + } + } + + if (LOTSA_TAGS < numTags) { + ckfree((char *) tagCnts); + ckfree((char *) tagPtrs); + } + + return elide; +} + +/* + *---------------------------------------------------------------------- + * * IncCount -- * * This is a utility procedure used by TkBTreeGetTags. It @@ -3588,7 +3730,27 @@ TkBTreeCharsInLine(linePtr) count = 0; for (segPtr = linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { + if (segPtr->typePtr == &tkTextCharType) { + count += Tcl_NumUtfChars(segPtr->body.chars, segPtr->size); + } else { + count += segPtr->size; + } + } + return count; +} + +int +TkBTreeBytesInLine(linePtr) + TkTextLine *linePtr; /* Line whose characters should be + * counted. */ +{ + TkTextSegment *segPtr; + int count; + + count = 0; + for (segPtr = linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { count += segPtr->size; } return count; } + diff --git a/tk/generic/tkTextDisp.c b/tk/generic/tkTextDisp.c index 9d0afc19727..36906b8caba 100644 --- a/tk/generic/tkTextDisp.c +++ b/tk/generic/tkTextDisp.c @@ -18,6 +18,10 @@ #include "tkInt.h" #include "tkText.h" +#ifdef __WIN32__ +#include "tkWinInt.h" +#endif + /* * The following structure describes how to display a range of characters. * The information is generated by scanning all of the tags associated @@ -55,9 +59,10 @@ typedef struct StyleValues { * be NULL). */ int underline; /* Non-zero means draw underline underneath * text. */ - Tk_Uid wrapMode; /* How to handle wrap-around for this tag. - * One of tkTextCharUid, tkTextNoneUid, - * or tkTextWordUid. */ + int elide; /* Non-zero means draw text */ + TkWrapMode wrapMode; /* How to handle wrap-around for this tag. + * One of TEXT_WRAPMODE_CHAR, + * TEXT_WRAPMODE_NONE or TEXT_WRAPMODE_WORD.*/ } StyleValues; /* @@ -98,7 +103,7 @@ typedef struct TextStyle { typedef struct DLine { TkTextIndex index; /* Identifies first character in text * that is displayed on this line. */ - int count; /* Number of characters accounted for by this + int byteCount; /* Number of bytes accounted for by this * display line, including a trailing space * or newline that isn't actually displayed. */ int y; /* Y-position at which line is supposed to @@ -156,12 +161,14 @@ typedef struct DLine { * BOTTOM_LINE - Non-zero means that this was the bottom line * in the window the last time that the window * was laid out. + * IS_DISABLED - This Dline cannot be edited. */ #define HAS_3D_BORDER 1 #define NEW_LAYOUT 2 #define TOP_LINE 4 #define BOTTOM_LINE 8 +#define IS_DISABLED 16 /* * Overall display information for a text widget: @@ -199,7 +206,7 @@ typedef struct TextDInfo { * Information used for scrolling: */ - int newCharOffset; /* Desired x scroll position, measured as the + int newByteOffset; /* Desired x scroll position, measured as the * number of average-size characters off-screen * to the left for a line with no left * margin. */ @@ -222,8 +229,9 @@ typedef struct TextDInfo { * The following information is used to implement scanning: */ - int scanMarkChar; /* Character that was at the left edge of - * the window when the scan started. */ + int scanMarkIndex; /* Byte index of character that was at the + * left edge of the window when the scan + * started. */ int scanMarkX; /* X-position of mouse at time scan started. */ int scanTotalScroll; /* Total scrolling (in screen lines) that has * occurred since scanMarkY was set. */ @@ -254,9 +262,9 @@ typedef struct TextDInfo { */ typedef struct CharInfo { - int numChars; /* Number of characters to display. */ - char chars[4]; /* Characters to display. Actual size - * will be numChars, not 4. THIS MUST BE + int numBytes; /* Number of bytes to display. */ + char chars[4]; /* UTF characters to display. Actual size + * will be numBytes, not 4. THIS MUST BE * THE LAST FIELD IN THE STRUCTURE. */ } CharInfo; @@ -311,6 +319,21 @@ static int CharMeasureProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr, int x)); static void CharUndisplayProc _ANSI_ARGS_((TkText *textPtr, TkTextDispChunk *chunkPtr)); + +/* + Definitions of elided procs. + Compiler can't inline these since we use pointers to these functions. + ElideDisplayProc, ElideUndisplayProc special-cased for speed, + as potentially many elided DLine chunks if large, tag toggle-filled + elided region. +*/ +static void ElideBboxProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr, + int index, int y, int lineHeight, int baseline, + int *xPtr, int *yPtr, int *widthPtr, + int *heightPtr)); +static int ElideMeasureProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr, + int x)); + static void DisplayDLine _ANSI_ARGS_((TkText *textPtr, DLine *dlPtr, DLine *prevPtr, Pixmap pixmap)); static void DisplayLineBackground _ANSI_ARGS_((TkText *textPtr, @@ -331,7 +354,7 @@ static void GetYView _ANSI_ARGS_((Tcl_Interp *interp, static DLine * LayoutDLine _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr)); static int MeasureChars _ANSI_ARGS_((Tk_Font tkfont, - CONST char *source, int maxChars, int startX, + CONST char *source, int maxBytes, int startX, int maxX, int tabOrigin, int *nextXPtr)); static void MeasureUp _ANSI_ARGS_((TkText *textPtr, TkTextIndex *srcPtr, int distance, @@ -381,14 +404,14 @@ TkTextCreateDInfo(textPtr) dInfoPtr->scrollGC = Tk_GetGC(textPtr->tkwin, GCGraphicsExposures, &gcValues); dInfoPtr->topOfEof = 0; - dInfoPtr->newCharOffset = 0; + dInfoPtr->newByteOffset = 0; dInfoPtr->curPixelOffset = 0; dInfoPtr->maxLength = 0; dInfoPtr->xScrollFirst = -1; dInfoPtr->xScrollLast = -1; dInfoPtr->yScrollFirst = -1; dInfoPtr->yScrollLast = -1; - dInfoPtr->scanMarkChar = 0; + dInfoPtr->scanMarkIndex = 0; dInfoPtr->scanMarkX = 0; dInfoPtr->scanTotalScroll = 0; dInfoPtr->scanMarkY = 0; @@ -479,7 +502,7 @@ GetStyle(textPtr, indexPtr) int borderPrio, borderWidthPrio, reliefPrio, bgStipplePrio; int fgPrio, fontPrio, fgStipplePrio; - int underlinePrio, justifyPrio, offsetPrio; + int underlinePrio, elidePrio, justifyPrio, offsetPrio; int lMargin1Prio, lMargin2Prio, rMarginPrio; int spacing1Prio, spacing2Prio, spacing3Prio; int overstrikePrio, tabPrio, wrapPrio; @@ -494,7 +517,7 @@ GetStyle(textPtr, indexPtr) tagPtrs = TkBTreeGetTags(indexPtr, &numTags); borderPrio = borderWidthPrio = reliefPrio = bgStipplePrio = -1; fgPrio = fontPrio = fgStipplePrio = -1; - underlinePrio = justifyPrio = offsetPrio = -1; + underlinePrio = elidePrio = justifyPrio = offsetPrio = -1; lMargin1Prio = lMargin2Prio = rMarginPrio = -1; spacing1Prio = spacing2Prio = spacing3Prio = -1; overstrikePrio = tabPrio = wrapPrio = -1; @@ -508,6 +531,7 @@ GetStyle(textPtr, indexPtr) styleValues.spacing3 = textPtr->spacing3; styleValues.tabArrayPtr = textPtr->tabArrayPtr; styleValues.wrapMode = textPtr->wrapMode; + styleValues.elide = 0; for (i = 0 ; i < numTags; i++) { tagPtr = tagPtrs[i]; @@ -612,7 +636,12 @@ GetStyle(textPtr, indexPtr) styleValues.underline = tagPtr->underline; underlinePrio = tagPtr->priority; } - if ((tagPtr->wrapMode != NULL) + if ((tagPtr->elideString != NULL) + && (tagPtr->priority > elidePrio)) { + styleValues.elide = tagPtr->elide; + elidePrio = tagPtr->priority; + } + if ((tagPtr->wrapMode != TEXT_WRAPMODE_NULL) && (tagPtr->priority > wrapPrio)) { styleValues.wrapMode = tagPtr->wrapMode; wrapPrio = tagPtr->priority; @@ -648,22 +677,20 @@ GetStyle(textPtr, indexPtr) gcValues.fill_style = FillStippled; mask |= GCStipple|GCFillStyle; } - stylePtr->bgGC = Tk_GetGCColor(textPtr->tkwin, mask, &gcValues, - Tk_3DBorderColor(styleValues.border), - NULL); + stylePtr->bgGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues); } else { stylePtr->bgGC = None; } - mask = GCForeground|GCFont; - gcValues.foreground = styleValues.fgColor->pixel; + mask = GCFont; gcValues.font = Tk_FontId(styleValues.tkfont); + mask |= GCForeground; + gcValues.foreground = styleValues.fgColor->pixel; if (styleValues.fgStipple != None) { gcValues.stipple = styleValues.fgStipple; gcValues.fill_style = FillStippled; mask |= GCStipple|GCFillStyle; } - stylePtr->fgGC = Tk_GetGCColor(textPtr->tkwin, mask, &gcValues, - styleValues.fgColor, NULL); + stylePtr->fgGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues); stylePtr->sValuePtr = (StyleValues *) Tcl_GetHashKey(&textPtr->dInfoPtr->styleTable, hPtr); stylePtr->hPtr = hPtr; @@ -701,7 +728,9 @@ FreeStyle(textPtr, stylePtr) if (stylePtr->bgGC != None) { Tk_FreeGC(textPtr->display, stylePtr->bgGC); } - Tk_FreeGC(textPtr->display, stylePtr->fgGC); + if (stylePtr->fgGC != None) { + Tk_FreeGC(textPtr->display, stylePtr->fgGC); + } Tcl_DeleteHashEntry(stylePtr->hPtr); ckfree((char *) stylePtr); } @@ -742,16 +771,18 @@ LayoutDLine(textPtr, indexPtr) * point, if any. */ TkTextIndex breakIndex; /* Index of first character in * breakChunkPtr. */ - int breakCharOffset; /* Character within breakChunkPtr just - * to right of best break point. */ + int breakByteOffset; /* Byte offset of character within + * breakChunkPtr just to right of best + * break point. */ int noCharsYet; /* Non-zero means that no characters * have been placed on the line yet. */ int justify; /* How to justify line: taken from - * style for first character in line. */ + * style for the first character in + * line. */ int jIndent; /* Additional indentation (beyond * margins) due to justification. */ int rMargin; /* Right margin width for line. */ - Tk_Uid wrapMode; /* Wrap mode to use for this line. */ + TkWrapMode wrapMode; /* Wrap mode to use for this line. */ int x = 0, maxX = 0; /* Initializations needed only to * stop compiler warnings. */ int wholeLine; /* Non-zero means this display line @@ -761,17 +792,18 @@ LayoutDLine(textPtr, indexPtr) * contains a tab. */ TkTextDispChunk *tabChunkPtr; /* Pointer to the chunk containing * the previous tab stop. */ - int maxChars; /* Maximum number of characters to + int maxBytes; /* Maximum number of bytes to * include in this chunk. */ - TkTextTabArray *tabArrayPtr; /* Tab stops for line; taken from - * style for first character on line. */ + TkTextTabArray *tabArrayPtr; /* Tab stops for line; taken from + * style for the first character on + * line. */ int tabSize; /* Number of pixels consumed by current * tab stop. */ TkTextDispChunk *lastCharChunkPtr; /* Pointer to last chunk in display - * lines with numChars > 0. Used to + * lines with numBytes > 0. Used to * drop 0-sized chunks from the end * of the line. */ - int offset, ascent, descent, code; + int byteOffset, ascent, descent, code, elide, elidesize; StyleValues *sValuePtr; /* @@ -780,7 +812,7 @@ LayoutDLine(textPtr, indexPtr) dlPtr = (DLine *) ckalloc(sizeof(DLine)); dlPtr->index = *indexPtr; - dlPtr->count = 0; + dlPtr->byteCount = 0; dlPtr->y = 0; dlPtr->oldY = -1; dlPtr->height = 0; @@ -790,6 +822,37 @@ LayoutDLine(textPtr, indexPtr) dlPtr->flags = NEW_LAYOUT; /* + * Special case entirely elide line as there may be 1000s or more + */ + elide = TkTextIsElided(textPtr, indexPtr); /* save a malloc */ + if (elide && indexPtr->byteIndex==0) { + maxBytes = 0; + for (segPtr = indexPtr->linePtr->segPtr; + elide && (segPtr != NULL); + segPtr = segPtr->nextPtr) { + if ((elidesize = segPtr->size) > 0) { + maxBytes += elidesize; + /* + * If have we have a tag toggle, there is a chance + * that invisibility state changed, so bail out + */ + } else if ((segPtr->typePtr == &tkTextToggleOffType) + || (segPtr->typePtr == &tkTextToggleOnType)) { + if (segPtr->body.toggle.tagPtr->elideString != NULL) { + elide = (segPtr->typePtr == &tkTextToggleOffType) + ^ segPtr->body.toggle.tagPtr->elide; + } + } + } + + if (elide) { + dlPtr->byteCount = maxBytes; + dlPtr->spaceAbove = dlPtr->spaceBelow = dlPtr->length = 0; + return dlPtr; + } + } + + /* * Each iteration of the loop below creates one TkTextDispChunk for * the new display line. The line will always have at least one * chunk (for the newline character at the end, if there's nothing @@ -800,14 +863,15 @@ LayoutDLine(textPtr, indexPtr) lastChunkPtr = NULL; chunkPtr = NULL; noCharsYet = 1; + elide = 0; breakChunkPtr = NULL; - breakCharOffset = 0; + breakByteOffset = 0; justify = TK_JUSTIFY_LEFT; tabIndex = -1; tabChunkPtr = NULL; tabArrayPtr = NULL; rMargin = 0; - wrapMode = tkTextCharUid; + wrapMode = TEXT_WRAPMODE_CHAR; tabSize = 0; lastCharChunkPtr = NULL; @@ -817,16 +881,48 @@ LayoutDLine(textPtr, indexPtr) * with zero size (such as the insertion cursor's mark). */ - for (offset = curIndex.charIndex, segPtr = curIndex.linePtr->segPtr; - (offset > 0) && (offset >= segPtr->size); - offset -= segPtr->size, segPtr = segPtr->nextPtr) { + for (byteOffset = curIndex.byteIndex, segPtr = curIndex.linePtr->segPtr; + (byteOffset > 0) && (byteOffset >= segPtr->size); + byteOffset -= segPtr->size, segPtr = segPtr->nextPtr) { /* Empty loop body. */ } while (segPtr != NULL) { + /* + * Every line still gets at least one chunk due to expectations + * in the rest of the code, but we are able to skip elided portions + * of the line quickly. + * If current chunk is elided and last chunk was too, coalese + */ + if (elide && (lastChunkPtr != NULL) + && (lastChunkPtr->displayProc == NULL /*ElideDisplayProc*/)) { + if ((elidesize = segPtr->size - byteOffset) > 0) { + curIndex.byteIndex += elidesize; + lastChunkPtr->numBytes += elidesize; + breakByteOffset = lastChunkPtr->breakIndex = lastChunkPtr->numBytes; + /* + * If have we have a tag toggle, there is a chance + * that invisibility state changed, so bail out + */ + } else if ((segPtr->typePtr == &tkTextToggleOffType) + || (segPtr->typePtr == &tkTextToggleOnType)) { + if (segPtr->body.toggle.tagPtr->elideString != NULL) { + elide = (segPtr->typePtr == &tkTextToggleOffType) + ^ segPtr->body.toggle.tagPtr->elide; + } + } + + byteOffset = 0; + segPtr = segPtr->nextPtr; + if (segPtr == NULL && chunkPtr != NULL) { + ckfree((char *) chunkPtr); + } + continue; + } + if (segPtr->typePtr->layoutProc == NULL) { segPtr = segPtr->nextPtr; - offset = 0; + byteOffset = 0; continue; } if (chunkPtr == NULL) { @@ -834,6 +930,7 @@ LayoutDLine(textPtr, indexPtr) chunkPtr->nextPtr = NULL; } chunkPtr->stylePtr = GetStyle(textPtr, &curIndex); + elide = chunkPtr->stylePtr->sValuePtr->elide; /* * Save style information such as justification and indentation, @@ -846,11 +943,11 @@ LayoutDLine(textPtr, indexPtr) justify = chunkPtr->stylePtr->sValuePtr->justify; rMargin = chunkPtr->stylePtr->sValuePtr->rMargin; wrapMode = chunkPtr->stylePtr->sValuePtr->wrapMode; - x = ((curIndex.charIndex == 0) + x = ((curIndex.byteIndex == 0) ? chunkPtr->stylePtr->sValuePtr->lMargin1 : chunkPtr->stylePtr->sValuePtr->lMargin2); - if (wrapMode == tkTextNoneUid) { - maxX = INT_MAX; + if (wrapMode == TEXT_WRAPMODE_NONE) { + maxX = -1; } else { maxX = textPtr->dInfoPtr->maxX - textPtr->dInfoPtr->x - rMargin; @@ -866,24 +963,37 @@ LayoutDLine(textPtr, indexPtr) */ gotTab = 0; - maxChars = segPtr->size - offset; - if (justify == TK_JUSTIFY_LEFT) { + maxBytes = segPtr->size - byteOffset; + if (!elide && justify == TK_JUSTIFY_LEFT) { if (segPtr->typePtr == &tkTextCharType) { char *p; - for (p = segPtr->body.chars + offset; *p != 0; p++) { + for (p = segPtr->body.chars + byteOffset; *p != 0; p++) { if (*p == '\t') { - maxChars = (p + 1 - segPtr->body.chars) - offset; + maxBytes = (p + 1 - segPtr->body.chars) - byteOffset; gotTab = 1; break; } } } } - chunkPtr->x = x; + if (elide && maxBytes) { + /* don't free style here, as other code expects to be able to do that */ + /*breakByteOffset =*/ chunkPtr->breakIndex = chunkPtr->numBytes = maxBytes; + chunkPtr->width = 0; + chunkPtr->minAscent = chunkPtr->minDescent = chunkPtr->minHeight = 0; + + /* would just like to point to canonical empty chunk */ + chunkPtr->displayProc = (Tk_ChunkDisplayProc *) NULL; + chunkPtr->undisplayProc = (Tk_ChunkUndisplayProc *) NULL; + chunkPtr->measureProc = ElideMeasureProc; + chunkPtr->bboxProc = ElideBboxProc; + + code = 1; + } else code = (*segPtr->typePtr->layoutProc)(textPtr, &curIndex, segPtr, - offset, maxX-tabSize, maxChars, noCharsYet, wrapMode, + byteOffset, maxX-tabSize, maxBytes, noCharsYet, wrapMode, chunkPtr); if (code <= 0) { FreeStyle(textPtr, chunkPtr->stylePtr); @@ -894,7 +1004,7 @@ LayoutDLine(textPtr, indexPtr) */ segPtr = segPtr->nextPtr; - offset = 0; + byteOffset = 0; continue; } @@ -908,7 +1018,7 @@ LayoutDLine(textPtr, indexPtr) } break; } - if (chunkPtr->numChars > 0) { + if (chunkPtr->numBytes > 0) { noCharsYet = 0; lastCharChunkPtr = chunkPtr; } @@ -920,11 +1030,11 @@ LayoutDLine(textPtr, indexPtr) lastChunkPtr = chunkPtr; x += chunkPtr->width; if (chunkPtr->breakIndex > 0) { - breakCharOffset = chunkPtr->breakIndex; + breakByteOffset = chunkPtr->breakIndex; breakIndex = curIndex; breakChunkPtr = chunkPtr; } - if (chunkPtr->numChars != maxChars) { + if (chunkPtr->numBytes != maxBytes) { break; } @@ -943,16 +1053,17 @@ LayoutDLine(textPtr, indexPtr) tabIndex++; tabChunkPtr = chunkPtr; tabSize = SizeOfTab(textPtr, tabArrayPtr, tabIndex, x, maxX); - if (tabSize >= (maxX - x)) { + if ((maxX >= 0) && (tabSize >= maxX - x)) { break; } } - curIndex.charIndex += chunkPtr->numChars; - offset += chunkPtr->numChars; - if (offset >= segPtr->size) { - offset = 0; + curIndex.byteIndex += chunkPtr->numBytes; + byteOffset += chunkPtr->numBytes; + if (byteOffset >= segPtr->size) { + byteOffset = 0; segPtr = segPtr->nextPtr; } + chunkPtr = NULL; } if (noCharsYet) { @@ -976,10 +1087,10 @@ LayoutDLine(textPtr, indexPtr) */ breakChunkPtr = lastCharChunkPtr; - breakCharOffset = breakChunkPtr->numChars; + breakByteOffset = breakChunkPtr->numBytes; } if ((breakChunkPtr != NULL) && ((lastChunkPtr != breakChunkPtr) - || (breakCharOffset != lastChunkPtr->numChars))) { + || (breakByteOffset != lastChunkPtr->numBytes))) { while (1) { chunkPtr = breakChunkPtr->nextPtr; if (chunkPtr == NULL) { @@ -990,17 +1101,18 @@ LayoutDLine(textPtr, indexPtr) (*chunkPtr->undisplayProc)(textPtr, chunkPtr); ckfree((char *) chunkPtr); } - if (breakCharOffset != breakChunkPtr->numChars) { + if (breakByteOffset != breakChunkPtr->numBytes) { (*breakChunkPtr->undisplayProc)(textPtr, breakChunkPtr); - segPtr = TkTextIndexToSeg(&breakIndex, &offset); + segPtr = TkTextIndexToSeg(&breakIndex, &byteOffset); (*segPtr->typePtr->layoutProc)(textPtr, &breakIndex, - segPtr, offset, maxX, breakCharOffset, 0, + segPtr, byteOffset, maxX, breakByteOffset, 0, wrapMode, breakChunkPtr); } lastChunkPtr = breakChunkPtr; wholeLine = 0; } + /* * Make tab adjustments for the last tab stop, if there is one. */ @@ -1011,7 +1123,7 @@ LayoutDLine(textPtr, indexPtr) /* * Make one more pass over the line to recompute various things - * like its height, length, and total number of characters. Also + * like its height, length, and total number of bytes. Also * modify the x-locations of chunks to reflect justification. * If we're not wrapping, I'm not sure what is the best way to * handle left and center justification: should the total length, @@ -1022,7 +1134,7 @@ LayoutDLine(textPtr, indexPtr) * what is implemented below. */ - if (wrapMode == tkTextNoneUid) { + if (wrapMode == TEXT_WRAPMODE_NONE) { maxX = textPtr->dInfoPtr->maxX - textPtr->dInfoPtr->x - rMargin; } dlPtr->length = lastChunkPtr->x + lastChunkPtr->width; @@ -1037,7 +1149,7 @@ LayoutDLine(textPtr, indexPtr) for (chunkPtr = dlPtr->chunkPtr; chunkPtr != NULL; chunkPtr = chunkPtr->nextPtr) { chunkPtr->x += jIndent; - dlPtr->count += chunkPtr->numChars; + dlPtr->byteCount += chunkPtr->numBytes; if (chunkPtr->minAscent > ascent) { ascent = chunkPtr->minAscent; } @@ -1060,7 +1172,7 @@ LayoutDLine(textPtr, indexPtr) dlPtr->baseline = ascent + (dlPtr->height - ascent - descent)/2; } sValuePtr = dlPtr->chunkPtr->stylePtr->sValuePtr; - if (dlPtr->index.charIndex == 0) { + if (dlPtr->index.byteIndex == 0) { dlPtr->spaceAbove = sValuePtr->spacing1; } else { dlPtr->spaceAbove = sValuePtr->spacing2 - sValuePtr->spacing2/2; @@ -1213,7 +1325,7 @@ UpdateDisplayInfo(textPtr) * index within the line. */ - if (index.charIndex == dlPtr->index.charIndex) { + if (index.byteIndex == dlPtr->index.byteIndex) { /* * Case (a) -- can use existing display line as-is. */ @@ -1224,7 +1336,7 @@ UpdateDisplayInfo(textPtr) } goto lineOK; } - if (index.charIndex < dlPtr->index.charIndex) { + if (index.byteIndex < dlPtr->index.byteIndex) { goto makeNewDLine; } @@ -1251,7 +1363,7 @@ UpdateDisplayInfo(textPtr) lineOK: dlPtr->y = y; y += dlPtr->height; - TkTextIndexForwChars(&index, dlPtr->count, &index); + TkTextIndexForwBytes(&index, dlPtr->byteCount, &index); prevPtr = dlPtr; dlPtr = dlPtr->nextPtr; @@ -1302,7 +1414,7 @@ UpdateDisplayInfo(textPtr) */ if (y < maxY) { - int lineNum, spaceLeft, charsToCount; + int lineNum, spaceLeft, bytesToCount; DLine *lowestPtr; /* @@ -1315,22 +1427,24 @@ UpdateDisplayInfo(textPtr) spaceLeft = maxY - y; lineNum = TkBTreeLineIndex(dInfoPtr->dLinePtr->index.linePtr); - charsToCount = dInfoPtr->dLinePtr->index.charIndex; - if (charsToCount == 0) { - charsToCount = INT_MAX; + bytesToCount = dInfoPtr->dLinePtr->index.byteIndex; + if (bytesToCount == 0) { + bytesToCount = INT_MAX; lineNum--; } for ( ; (lineNum >= 0) && (spaceLeft > 0); lineNum--) { index.linePtr = TkBTreeFindLine(textPtr->tree, lineNum); - index.charIndex = 0; + index.byteIndex = 0; lowestPtr = NULL; + do { dlPtr = LayoutDLine(textPtr, &index); dlPtr->nextPtr = lowestPtr; lowestPtr = dlPtr; - TkTextIndexForwChars(&index, dlPtr->count, &index); - charsToCount -= dlPtr->count; - } while ((charsToCount > 0) + if (dlPtr->length == 0 && dlPtr->height == 0) { bytesToCount--; break; } /* elide */ + TkTextIndexForwBytes(&index, dlPtr->byteCount, &index); + bytesToCount -= dlPtr->byteCount; + } while ((bytesToCount > 0) && (index.linePtr == lowestPtr->index.linePtr)); /* @@ -1357,7 +1471,7 @@ UpdateDisplayInfo(textPtr) } } FreeDLines(textPtr, lowestPtr, (DLine *) NULL, 0); - charsToCount = INT_MAX; + bytesToCount = INT_MAX; } /* @@ -1444,13 +1558,13 @@ UpdateDisplayInfo(textPtr) } maxOffset = (dInfoPtr->maxLength - (dInfoPtr->maxX - dInfoPtr->x) + textPtr->charWidth - 1)/textPtr->charWidth; - if (dInfoPtr->newCharOffset > maxOffset) { - dInfoPtr->newCharOffset = maxOffset; + if (dInfoPtr->newByteOffset > maxOffset) { + dInfoPtr->newByteOffset = maxOffset; } - if (dInfoPtr->newCharOffset < 0) { - dInfoPtr->newCharOffset = 0; + if (dInfoPtr->newByteOffset < 0) { + dInfoPtr->newByteOffset = 0; } - pixelOffset = dInfoPtr->newCharOffset * textPtr->charWidth; + pixelOffset = dInfoPtr->newByteOffset * textPtr->charWidth; if (pixelOffset != dInfoPtr->curPixelOffset) { dInfoPtr->curPixelOffset = pixelOffset; for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; @@ -1557,6 +1671,8 @@ DisplayDLine(textPtr, dlPtr, prevPtr, pixmap) Display *display; int height, x; + if (dlPtr->chunkPtr == NULL) return; + /* * First, clear the area of the line to the background color for the * text widget. @@ -1580,11 +1696,7 @@ DisplayDLine(textPtr, dlPtr, prevPtr, pixmap) * to its left. */ -#ifndef __WIN32__ - /* CYGNUS LOCAL: On Windows, display the cursor even for disabled - text widgets. */ - if (textPtr->state == tkNormalUid) { -#endif /* __WIN32__ */ + if (textPtr->state == TK_STATE_NORMAL) { for (chunkPtr = dlPtr->chunkPtr; (chunkPtr != NULL); chunkPtr = chunkPtr->nextPtr) { x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curPixelOffset; @@ -1595,9 +1707,7 @@ DisplayDLine(textPtr, dlPtr, prevPtr, pixmap) dlPtr->y + dlPtr->spaceAbove); } } -#ifndef __WIN32__ } -#endif /* __WIN32__ */ /* * Make yet another pass through all of the chunks to redraw all of @@ -1629,12 +1739,16 @@ DisplayDLine(textPtr, dlPtr, prevPtr, pixmap) * something is off to the right). */ + if (chunkPtr->displayProc != NULL) (*chunkPtr->displayProc)(chunkPtr, -chunkPtr->width, dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, display, pixmap, dlPtr->y + dlPtr->spaceAbove); } else { + /* don't call if elide. This tax ok since not very many visible DLine's in + an area, but potentially many elide ones */ + if (chunkPtr->displayProc != NULL) (*chunkPtr->displayProc)(chunkPtr, x, dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, display, pixmap, @@ -1723,6 +1837,7 @@ DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap) StyleValues *sValuePtr; Display *display; + /* * Pass 1: scan through dlPtr from left to right. For each range of * chunks with the same style, draw the main background for the style @@ -1796,7 +1911,7 @@ DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap) rightX = maxX; } chunkPtr2 = NULL; - if (prevPtr != NULL) { + if (prevPtr != NULL && prevPtr->chunkPtr != NULL) { /* * Find the chunk in the previous line that covers leftX. */ @@ -1917,7 +2032,7 @@ DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap) rightX = maxX; } chunkPtr2 = NULL; - if (dlPtr->nextPtr != NULL) { + if (dlPtr->nextPtr != NULL && dlPtr->nextPtr->chunkPtr != NULL) { /* * Find the chunk in the previous line that covers leftX. */ @@ -2243,17 +2358,19 @@ DisplayText(clientData) Tk_Height(textPtr->tkwin) - 2*textPtr->highlightWidth, textPtr->borderWidth, textPtr->relief); if (textPtr->highlightWidth != 0) { - GC gc; + GC fgGC, bgGC; + bgGC = Tk_GCForColor(textPtr->highlightBgColorPtr, + Tk_WindowId(textPtr->tkwin)); if (textPtr->flags & GOT_FOCUS) { - gc = Tk_GCForColor(textPtr->highlightColorPtr, + fgGC = Tk_GCForColor(textPtr->highlightColorPtr, Tk_WindowId(textPtr->tkwin)); + TkpDrawHighlightBorder(textPtr->tkwin, fgGC, bgGC, + textPtr->highlightWidth, Tk_WindowId(textPtr->tkwin)); } else { - gc = Tk_GCForColor(textPtr->highlightBgColorPtr, - Tk_WindowId(textPtr->tkwin)); + TkpDrawHighlightBorder(textPtr->tkwin, bgGC, bgGC, + textPtr->highlightWidth, Tk_WindowId(textPtr->tkwin)); } - Tk_DrawFocusHighlight(textPtr->tkwin, gc, textPtr->highlightWidth, - Tk_WindowId(textPtr->tkwin)); } borders = textPtr->borderWidth + textPtr->highlightWidth; if (textPtr->padY > 0) { @@ -2308,6 +2425,7 @@ DisplayText(clientData) for (prevPtr = NULL, dlPtr = textPtr->dInfoPtr->dLinePtr; (dlPtr != NULL) && (dlPtr->y < dInfoPtr->maxY); prevPtr = dlPtr, dlPtr = dlPtr->nextPtr) { + if (dlPtr->chunkPtr == NULL) continue; if (dlPtr->oldY != dlPtr->y) { if (tkTextDebug) { char string[TK_POS_CHARS]; @@ -2324,6 +2442,7 @@ DisplayText(clientData) dlPtr->oldY = dlPtr->y; dlPtr->flags &= ~NEW_LAYOUT; } + /*prevPtr = dlPtr;*/ } Tk_FreePixmap(Tk_Display(textPtr->tkwin), pixmap); } @@ -2600,7 +2719,7 @@ TkTextChanged(textPtr, index1Ptr, index2Ptr) */ rounded = *index1Ptr; - rounded.charIndex = 0; + rounded.byteIndex = 0; firstPtr = FindDLine(dInfoPtr->dLinePtr, &rounded); if (firstPtr == NULL) { return; @@ -2676,7 +2795,7 @@ TkTextRedrawTag(textPtr, index1Ptr, index2Ptr, tagPtr, withTag) */ if (index2Ptr == NULL) { - index2Ptr = TkTextMakeIndex(textPtr->tree, + index2Ptr = TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &endOfText); } @@ -2730,13 +2849,13 @@ TkTextRedrawTag(textPtr, index1Ptr, index2Ptr, tagPtr, withTag) * previous character. */ - if (curIndexPtr->charIndex == 0) { + if (curIndexPtr->byteIndex == 0) { dlPtr = FindDLine(dlPtr, curIndexPtr); } else { TkTextIndex tmp; tmp = *curIndexPtr; - tmp.charIndex -= 1; + tmp.byteIndex -= 1; dlPtr = FindDLine(dlPtr, &tmp); } if (dlPtr == NULL) { @@ -2755,7 +2874,7 @@ TkTextRedrawTag(textPtr, index1Ptr, index2Ptr, tagPtr, withTag) } endPtr = FindDLine(dlPtr, endIndexPtr); if ((endPtr != NULL) && (endPtr->index.linePtr == endIndexPtr->linePtr) - && (endPtr->index.charIndex < endIndexPtr->charIndex)) { + && (endPtr->index.byteIndex < endIndexPtr->byteIndex)) { endPtr = endPtr->nextPtr; } @@ -2867,7 +2986,7 @@ TkTextRelayoutWindow(textPtr) * or options could change the way lines wrap. */ - if (textPtr->topIndex.charIndex != 0) { + if (textPtr->topIndex.byteIndex != 0) { MeasureUp(textPtr, &textPtr->topIndex, 0, &textPtr->topIndex); } @@ -2934,7 +3053,7 @@ TkTextSetYView(textPtr, indexPtr, pickPlace) * without redisplaying it all. */ - if (indexPtr->charIndex == 0) { + if (indexPtr->byteIndex == 0) { textPtr->topIndex = *indexPtr; } else { MeasureUp(textPtr, indexPtr, 0, &textPtr->topIndex); @@ -2962,7 +3081,7 @@ TkTextSetYView(textPtr, indexPtr, pickPlace) dlPtr = NULL; } else if ((dlPtr->index.linePtr == indexPtr->linePtr) - && (dlPtr->index.charIndex <= indexPtr->charIndex)) { + && (dlPtr->index.byteIndex <= indexPtr->byteIndex)) { return; } } @@ -3060,37 +3179,37 @@ MeasureUp(textPtr, srcPtr, distance, dstPtr) TkTextIndex *dstPtr; /* Index to fill in with result. */ { int lineNum; /* Number of current line. */ - int charsToCount; /* Maximum number of characters to measure - * in current line. */ + int bytesToCount; /* Maximum number of bytes to measure in + * current line. */ TkTextIndex bestIndex; /* Best candidate seen so far for result. */ TkTextIndex index; DLine *dlPtr, *lowestPtr; int noBestYet; /* 1 means bestIndex hasn't been set. */ noBestYet = 1; - charsToCount = srcPtr->charIndex + 1; + bytesToCount = srcPtr->byteIndex + 1; index.tree = srcPtr->tree; for (lineNum = TkBTreeLineIndex(srcPtr->linePtr); lineNum >= 0; lineNum--) { /* * Layout an entire text line (potentially > 1 display line). * For the first line, which contains srcPtr, only layout the - * part up through srcPtr (charsToCount is non-infinite to + * part up through srcPtr (bytesToCount is non-infinite to * accomplish this). Make a list of all the display lines * in backwards order (the lowest DLine on the screen is first * in the list). */ index.linePtr = TkBTreeFindLine(srcPtr->tree, lineNum); - index.charIndex = 0; + index.byteIndex = 0; lowestPtr = NULL; do { dlPtr = LayoutDLine(textPtr, &index); dlPtr->nextPtr = lowestPtr; lowestPtr = dlPtr; - TkTextIndexForwChars(&index, dlPtr->count, &index); - charsToCount -= dlPtr->count; - } while ((charsToCount > 0) && (index.linePtr == dlPtr->index.linePtr)); + TkTextIndexForwBytes(&index, dlPtr->byteCount, &index); + bytesToCount -= dlPtr->byteCount; + } while ((bytesToCount > 0) && (index.linePtr == dlPtr->index.linePtr)); /* * Scan through the display lines to see if we've covered enough @@ -3117,7 +3236,7 @@ MeasureUp(textPtr, srcPtr, distance, dstPtr) if (distance < 0) { return; } - charsToCount = INT_MAX; /* Consider all chars. in next line. */ + bytesToCount = INT_MAX; /* Consider all chars. in next line. */ } /* @@ -3125,7 +3244,7 @@ MeasureUp(textPtr, srcPtr, distance, dstPtr) * in the text. */ - TkTextMakeIndex(textPtr->tree, 0, 0, dstPtr); + TkTextMakeByteIndex(textPtr->tree, 0, 0, dstPtr); } /* @@ -3157,7 +3276,7 @@ TkTextSeeCmd(textPtr, interp, argc, argv) { TextDInfo *dInfoPtr = textPtr->dInfoPtr; TkTextIndex index; - int x, y, width, height, lineWidth, charCount, oneThird, delta; + int x, y, width, height, lineWidth, byteCount, oneThird, delta; DLine *dlPtr; TkTextDispChunk *chunkPtr; @@ -3166,7 +3285,6 @@ TkTextSeeCmd(textPtr, interp, argc, argv) argv[0], " see index\"", (char *) NULL); return TCL_ERROR; } - if (TkTextGetIndex(interp, textPtr, argv[2], &index) != TCL_OK) { return TCL_ERROR; } @@ -3203,27 +3321,12 @@ TkTextSeeCmd(textPtr, interp, argc, argv) */ dlPtr = FindDLine(dInfoPtr->dLinePtr, &index); - - /* - * CYGNUS LOCAL: I can sometimes get FindDLine to return a null - * pointer. I have not been able to find a simple test case, - * it happens in Gdbtk when you change the font for the debug window. - * Since you should not have to catch the see command, I have made - * the error silent... - */ - - if (dlPtr == NULL) { - Tcl_AppendResult(interp, "got a null dlinePtr from FindDLine in the see command.", - (char *) NULL); - return TCL_OK; - } - - charCount = index.charIndex - dlPtr->index.charIndex; - for (chunkPtr = dlPtr->chunkPtr; ; chunkPtr = chunkPtr->nextPtr) { - if (charCount < chunkPtr->numChars) { + byteCount = index.byteIndex - dlPtr->index.byteIndex; + for (chunkPtr = dlPtr->chunkPtr; chunkPtr!=NULL ; chunkPtr = chunkPtr->nextPtr) { + if (byteCount < chunkPtr->numBytes) { break; } - charCount -= chunkPtr->numChars; + byteCount -= chunkPtr->numBytes; } /* @@ -3231,7 +3334,8 @@ TkTextSeeCmd(textPtr, interp, argc, argv) * the character within the chunk. */ - (*chunkPtr->bboxProc)(chunkPtr, charCount, dlPtr->y + dlPtr->spaceAbove, + if (chunkPtr!=NULL) { /* chunkPtr==NULL iff trying to see in elided region */ + (*chunkPtr->bboxProc)(chunkPtr, byteCount, dlPtr->y + dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width, &height); @@ -3239,24 +3343,24 @@ TkTextSeeCmd(textPtr, interp, argc, argv) oneThird = lineWidth/3; if (delta < 0) { if (delta < -oneThird) { - dInfoPtr->newCharOffset = (x - lineWidth/2)/textPtr->charWidth; + dInfoPtr->newByteOffset = (x - lineWidth/2)/textPtr->charWidth; } else { - dInfoPtr->newCharOffset -= ((-delta) + textPtr->charWidth - 1) + dInfoPtr->newByteOffset -= ((-delta) + textPtr->charWidth - 1) / textPtr->charWidth; } } else { delta -= (lineWidth - width); if (delta > 0) { if (delta > oneThird) { - dInfoPtr->newCharOffset = (x - lineWidth/2)/textPtr->charWidth; + dInfoPtr->newByteOffset = (x - lineWidth/2)/textPtr->charWidth; } else { - dInfoPtr->newCharOffset += (delta + textPtr->charWidth - 1) + dInfoPtr->newByteOffset += (delta + textPtr->charWidth - 1) / textPtr->charWidth; } } else { return TCL_OK; } - } + }} dInfoPtr->flags |= DINFO_OUT_OF_DATE; if (!(dInfoPtr->flags & REDRAW_PENDING)) { dInfoPtr->flags |= REDRAW_PENDING; @@ -3305,7 +3409,7 @@ TkTextXviewCmd(textPtr, interp, argc, argv) return TCL_OK; } - newOffset = dInfoPtr->newCharOffset; + newOffset = dInfoPtr->newByteOffset; type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count); switch (type) { case TK_SCROLL_ERROR: @@ -3326,14 +3430,14 @@ TkTextXviewCmd(textPtr, interp, argc, argv) if (charsPerPage < 1) { charsPerPage = 1; } - newOffset += charsPerPage*count; + newOffset += charsPerPage * count; break; case TK_SCROLL_UNITS: newOffset += count; break; } - dInfoPtr->newCharOffset = newOffset; + dInfoPtr->newByteOffset = newOffset; dInfoPtr->flags |= DINFO_OUT_OF_DATE; if (!(dInfoPtr->flags & REDRAW_PENDING)) { dInfoPtr->flags |= REDRAW_PENDING; @@ -3369,7 +3473,7 @@ ScrollByLines(textPtr, offset) * means that information earlier in the * text becomes visible. */ { - int i, charsToCount, lineNum; + int i, bytesToCount, lineNum; TkTextIndex new, index; TkTextLine *lastLinePtr; TextDInfo *dInfoPtr = textPtr->dInfoPtr; @@ -3382,21 +3486,21 @@ ScrollByLines(textPtr, offset) * it counts lines instead of pixels. */ - charsToCount = textPtr->topIndex.charIndex + 1; + bytesToCount = textPtr->topIndex.byteIndex + 1; index.tree = textPtr->tree; offset--; /* Skip line containing topIndex. */ for (lineNum = TkBTreeLineIndex(textPtr->topIndex.linePtr); lineNum >= 0; lineNum--) { index.linePtr = TkBTreeFindLine(textPtr->tree, lineNum); - index.charIndex = 0; + index.byteIndex = 0; lowestPtr = NULL; do { dlPtr = LayoutDLine(textPtr, &index); dlPtr->nextPtr = lowestPtr; lowestPtr = dlPtr; - TkTextIndexForwChars(&index, dlPtr->count, &index); - charsToCount -= dlPtr->count; - } while ((charsToCount > 0) + TkTextIndexForwBytes(&index, dlPtr->byteCount, &index); + bytesToCount -= dlPtr->byteCount; + } while ((bytesToCount > 0) && (index.linePtr == dlPtr->index.linePtr)); for (dlPtr = lowestPtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) { @@ -3406,7 +3510,7 @@ ScrollByLines(textPtr, offset) break; } } - + /* * Discard the display lines, then either return or prepare * for the next display line to lay out. @@ -3416,7 +3520,7 @@ ScrollByLines(textPtr, offset) if (offset >= 0) { goto scheduleUpdate; } - charsToCount = INT_MAX; + bytesToCount = INT_MAX; } /* @@ -3424,7 +3528,7 @@ ScrollByLines(textPtr, offset) * in the text. */ - TkTextMakeIndex(textPtr->tree, 0, 0, &textPtr->topIndex); + TkTextMakeByteIndex(textPtr->tree, 0, 0, &textPtr->topIndex); } else { /* * Scrolling down, to show later information in the text. @@ -3435,8 +3539,9 @@ ScrollByLines(textPtr, offset) TkBTreeNumLines(textPtr->tree)); for (i = 0; i < offset; i++) { dlPtr = LayoutDLine(textPtr, &textPtr->topIndex); + if (dlPtr->length == 0 && dlPtr->height == 0) offset++; dlPtr->nextPtr = NULL; - TkTextIndexForwChars(&textPtr->topIndex, dlPtr->count, &new); + TkTextIndexForwBytes(&textPtr->topIndex, dlPtr->byteCount, &new); FreeDLines(textPtr, dlPtr, (DLine *) NULL, 0); if (new.linePtr == lastLinePtr) { break; @@ -3480,7 +3585,7 @@ TkTextYviewCmd(textPtr, interp, argc, argv) * argv[1] is "yview". */ { TextDInfo *dInfoPtr = textPtr->dInfoPtr; - int pickPlace, lineNum, type, charsInLine; + int pickPlace, lineNum, type, bytesInLine; Tk_FontMetrics fm; int pixels, count; size_t switchLength; @@ -3518,7 +3623,7 @@ TkTextYviewCmd(textPtr, interp, argc, argv) } if ((argc == 3) || pickPlace) { if (Tcl_GetInt(interp, argv[2+pickPlace], &lineNum) == TCL_OK) { - TkTextMakeIndex(textPtr->tree, lineNum, 0, &index); + TkTextMakeByteIndex(textPtr->tree, lineNum, 0, &index); TkTextSetYView(textPtr, &index, 0); return TCL_OK; } @@ -3553,11 +3658,11 @@ TkTextYviewCmd(textPtr, interp, argc, argv) } fraction *= TkBTreeNumLines(textPtr->tree); lineNum = (int) fraction; - TkTextMakeIndex(textPtr->tree, lineNum, 0, &index); - charsInLine = TkBTreeCharsInLine(index.linePtr); - index.charIndex = (int)((charsInLine * (fraction-lineNum)) + 0.5); - if (index.charIndex >= charsInLine) { - TkTextMakeIndex(textPtr->tree, lineNum+1, 0, &index); + TkTextMakeByteIndex(textPtr->tree, lineNum, 0, &index); + bytesInLine = TkBTreeBytesInLine(index.linePtr); + index.byteIndex = (int)((bytesInLine * (fraction-lineNum)) + 0.5); + if (index.byteIndex >= bytesInLine) { + TkTextMakeByteIndex(textPtr->tree, lineNum + 1, 0, &index); } TkTextSetYView(textPtr, &index, 0); break; @@ -3595,7 +3700,7 @@ TkTextYviewCmd(textPtr, interp, argc, argv) do { dlPtr = LayoutDLine(textPtr, &textPtr->topIndex); dlPtr->nextPtr = NULL; - TkTextIndexForwChars(&textPtr->topIndex, dlPtr->count, + TkTextIndexForwBytes(&textPtr->topIndex, dlPtr->byteCount, &new); pixels -= dlPtr->height; FreeDLines(textPtr, dlPtr, (DLine *) NULL, 0); @@ -3647,13 +3752,14 @@ TkTextScanCmd(textPtr, interp, argc, argv) { TextDInfo *dInfoPtr = textPtr->dInfoPtr; TkTextIndex index; - int c, x, y, totalScroll, newChar, maxChar; + int c, x, y, totalScroll, newByte, maxByte, gain=10; Tk_FontMetrics fm; size_t length; - if (argc != 5) { + if ((argc != 5) && (argc != 6)) { Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " scan mark|dragto x y\"", (char *) NULL); + argv[0], " scan mark x y\" or \"", + argv[0], " scan dragto x y ?gain?\"", (char *) NULL); return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) { @@ -3662,6 +3768,8 @@ TkTextScanCmd(textPtr, interp, argc, argv) if (Tcl_GetInt(interp, argv[4], &y) != TCL_OK) { return TCL_ERROR; } + if ((argc == 6) && (Tcl_GetInt(interp, argv[5], &gain) != TCL_OK)) + return TCL_ERROR; c = argv[2][0]; length = strlen(argv[2]); if ((c == 'd') && (strncmp(argv[2], "dragto", length) == 0)) { @@ -3677,33 +3785,35 @@ TkTextScanCmd(textPtr, interp, argc, argv) * moving again). */ - newChar = dInfoPtr->scanMarkChar + (10*(dInfoPtr->scanMarkX - x)) + newByte = dInfoPtr->scanMarkIndex + (gain*(dInfoPtr->scanMarkX - x)) / (textPtr->charWidth); - maxChar = 1 + (dInfoPtr->maxLength - (dInfoPtr->maxX - dInfoPtr->x) + maxByte = 1 + (dInfoPtr->maxLength - (dInfoPtr->maxX - dInfoPtr->x) + textPtr->charWidth - 1)/textPtr->charWidth; - if (newChar < 0) { - dInfoPtr->scanMarkChar = newChar = 0; + if (newByte < 0) { + newByte = 0; + dInfoPtr->scanMarkIndex = 0; dInfoPtr->scanMarkX = x; - } else if (newChar > maxChar) { - dInfoPtr->scanMarkChar = newChar = maxChar; + } else if (newByte > maxByte) { + newByte = maxByte; + dInfoPtr->scanMarkIndex = maxByte; dInfoPtr->scanMarkX = x; } - dInfoPtr->newCharOffset = newChar; + dInfoPtr->newByteOffset = newByte; Tk_GetFontMetrics(textPtr->tkfont, &fm); - totalScroll = (10*(dInfoPtr->scanMarkY - y)) / fm.linespace; + totalScroll = (gain*(dInfoPtr->scanMarkY - y)) / fm.linespace; if (totalScroll != dInfoPtr->scanTotalScroll) { index = textPtr->topIndex; ScrollByLines(textPtr, totalScroll-dInfoPtr->scanTotalScroll); dInfoPtr->scanTotalScroll = totalScroll; if ((index.linePtr == textPtr->topIndex.linePtr) && - (index.charIndex == textPtr->topIndex.charIndex)) { + (index.byteIndex == textPtr->topIndex.byteIndex)) { dInfoPtr->scanTotalScroll = 0; dInfoPtr->scanMarkY = y; } } } else if ((c == 'm') && (strncmp(argv[2], "mark", length) == 0)) { - dInfoPtr->scanMarkChar = dInfoPtr->newCharOffset; + dInfoPtr->scanMarkIndex = dInfoPtr->newByteOffset; dInfoPtr->scanMarkX = x; dInfoPtr->scanTotalScroll = 0; dInfoPtr->scanMarkY = y; @@ -3730,11 +3840,11 @@ TkTextScanCmd(textPtr, interp, argc, argv) * Tcl script to report them to the text's associated scrollbar. * * Results: - * If report is zero, then interp->result is filled in with + * If report is zero, then the interp's result is filled in with * two real numbers separated by a space, giving the position of * the left and right edges of the window as fractions from 0 to * 1, where 0 means the left edge of the text and 1 means the right - * edge. If report is non-zero, then interp->result isn't modified + * edge. If report is non-zero, then the interp's result isn't modified * directly, but instead a script is evaluated in interp to report * the new horizontal scroll position to the scrollbar (if the scroll * position hasn't changed then no script is invoked). @@ -3749,13 +3859,13 @@ static void GetXView(interp, textPtr, report) Tcl_Interp *interp; /* If "report" is FALSE, string * describing visible range gets - * stored in interp->result. */ + * stored in the interp's result. */ TkText *textPtr; /* Information about text widget. */ int report; /* Non-zero means report info to * scrollbar if it has changed. */ { TextDInfo *dInfoPtr = textPtr->dInfoPtr; - char buffer[200]; + char buffer[TCL_DOUBLE_SPACE * 2]; double first, last; int code; @@ -3772,7 +3882,8 @@ GetXView(interp, textPtr, report) last = 1.0; } if (!report) { - sprintf(interp->result, "%g %g", first, last); + sprintf(buffer, "%g %g", first, last); + Tcl_SetResult(interp, buffer, TCL_VOLATILE); return; } if ((first == dInfoPtr->xScrollFirst) && (last == dInfoPtr->xScrollLast)) { @@ -3800,11 +3911,11 @@ GetXView(interp, textPtr, report) * Tcl script to report them to the text's associated scrollbar. * * Results: - * If report is zero, then interp->result is filled in with + * If report is zero, then the interp's result is filled in with * two real numbers separated by a space, giving the position of * the top and bottom of the window as fractions from 0 to 1, where * 0 means the beginning of the text and 1 means the end. If - * report is non-zero, then interp->result isn't modified directly, + * report is non-zero, then the interp's result isn't modified directly, * but a script is evaluated in interp to report the new scroll * position to the scrollbar (if the scroll position hasn't changed * then no script is invoked). @@ -3819,22 +3930,22 @@ static void GetYView(interp, textPtr, report) Tcl_Interp *interp; /* If "report" is FALSE, string * describing visible range gets - * stored in interp->result. */ + * stored in the interp's result. */ TkText *textPtr; /* Information about text widget. */ int report; /* Non-zero means report info to * scrollbar if it has changed. */ { TextDInfo *dInfoPtr = textPtr->dInfoPtr; - char buffer[200]; + char buffer[TCL_DOUBLE_SPACE * 2]; double first, last; DLine *dlPtr; int totalLines, code, count; dlPtr = dInfoPtr->dLinePtr; totalLines = TkBTreeNumLines(textPtr->tree); - first = ((double) TkBTreeLineIndex(dlPtr->index.linePtr)) - + ((double) dlPtr->index.charIndex) - / (TkBTreeCharsInLine(dlPtr->index.linePtr)); + first = (double) TkBTreeLineIndex(dlPtr->index.linePtr) + + (double) dlPtr->index.byteIndex + / TkBTreeBytesInLine(dlPtr->index.linePtr); first /= totalLines; while (1) { if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) { @@ -3846,17 +3957,18 @@ GetYView(interp, textPtr, report) break; } if (dlPtr->nextPtr == NULL) { - count = dlPtr->count; + count = dlPtr->byteCount; break; } dlPtr = dlPtr->nextPtr; } last = ((double) TkBTreeLineIndex(dlPtr->index.linePtr)) - + ((double) (dlPtr->index.charIndex + count)) - / (TkBTreeCharsInLine(dlPtr->index.linePtr)); + + ((double) (dlPtr->index.byteIndex + count)) + / (TkBTreeBytesInLine(dlPtr->index.linePtr)); last /= totalLines; if (!report) { - sprintf(interp->result, "%g %g", first, last); + sprintf(buffer, "%g %g", first, last); + Tcl_SetResult(interp, buffer, TCL_VOLATILE); return; } if ((first == dInfoPtr->yScrollFirst) && (last == dInfoPtr->yScrollLast)) { @@ -3865,8 +3977,7 @@ GetYView(interp, textPtr, report) dInfoPtr->yScrollFirst = first; dInfoPtr->yScrollLast = last; sprintf(buffer, " %g %g", first, last); - code = Tcl_VarEval(interp, textPtr->yScrollCmd, - buffer, (char *) NULL); + code = Tcl_VarEval(interp, textPtr->yScrollCmd, buffer, (char *) NULL); if (code != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (vertical scrolling command executed by text)"); @@ -3938,7 +4049,7 @@ FindDLine(dlPtr, indexPtr) * Now get to the right position within the text line. */ - while (indexPtr->charIndex >= (dlPtr->index.charIndex + dlPtr->count)) { + while (indexPtr->byteIndex >= (dlPtr->index.byteIndex + dlPtr->byteCount)) { dlPtr = dlPtr->nextPtr; if ((dlPtr == NULL) || (dlPtr->index.linePtr != indexPtr->linePtr)) { break; @@ -3974,7 +4085,7 @@ TkTextPixelIndex(textPtr, x, y, indexPtr) * index of the character nearest to (x,y). */ { TextDInfo *dInfoPtr = textPtr->dInfoPtr; - register DLine *dlPtr; + register DLine *dlPtr, *validdlPtr; register TkTextDispChunk *chunkPtr; /* @@ -4007,8 +4118,9 @@ TkTextPixelIndex(textPtr, x, y, indexPtr) * Find the display line containing the desired y-coordinate. */ - for (dlPtr = dInfoPtr->dLinePtr; y >= (dlPtr->y + dlPtr->height); + for (dlPtr = validdlPtr = dInfoPtr->dLinePtr; y >= (dlPtr->y + dlPtr->height); dlPtr = dlPtr->nextPtr) { + if (dlPtr->chunkPtr !=NULL) validdlPtr = dlPtr; if (dlPtr->nextPtr == NULL) { /* * Y-coordinate is off the bottom of the displayed text. @@ -4019,6 +4131,8 @@ TkTextPixelIndex(textPtr, x, y, indexPtr) break; } } + if (dlPtr->chunkPtr == NULL) dlPtr = validdlPtr; + /* * Scan through the line's chunks to find the one that contains @@ -4030,21 +4144,22 @@ TkTextPixelIndex(textPtr, x, y, indexPtr) *indexPtr = dlPtr->index; x = x - dInfoPtr->x + dInfoPtr->curPixelOffset; for (chunkPtr = dlPtr->chunkPtr; x >= (chunkPtr->x + chunkPtr->width); - indexPtr->charIndex += chunkPtr->numChars, + indexPtr->byteIndex += chunkPtr->numBytes, chunkPtr = chunkPtr->nextPtr) { if (chunkPtr->nextPtr == NULL) { - indexPtr->charIndex += chunkPtr->numChars - 1; + indexPtr->byteIndex += chunkPtr->numBytes; + TkTextIndexBackChars(indexPtr, 1, indexPtr); return; } } /* - * If the chunk has more than one character in it, ask it which + * If the chunk has more than one byte in it, ask it which * character is at the desired location. */ - if (chunkPtr->numChars > 1) { - indexPtr->charIndex += (*chunkPtr->measureProc)(chunkPtr, x); + if (chunkPtr->numBytes > 1) { + indexPtr->byteIndex += (*chunkPtr->measureProc)(chunkPtr, x); } } @@ -4081,7 +4196,7 @@ TkTextCharBbox(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr) TextDInfo *dInfoPtr = textPtr->dInfoPtr; DLine *dlPtr; register TkTextDispChunk *chunkPtr; - int index; + int byteIndex; /* * Make sure that all of the screen layout information is up to date. @@ -4105,15 +4220,15 @@ TkTextCharBbox(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr) * index. */ - index = indexPtr->charIndex - dlPtr->index.charIndex; + byteIndex = indexPtr->byteIndex - dlPtr->index.byteIndex; for (chunkPtr = dlPtr->chunkPtr; ; chunkPtr = chunkPtr->nextPtr) { if (chunkPtr == NULL) { return -1; } - if (index < chunkPtr->numChars) { + if (byteIndex < chunkPtr->numBytes) { break; } - index -= chunkPtr->numChars; + byteIndex -= chunkPtr->numBytes; } /* @@ -4124,12 +4239,12 @@ TkTextCharBbox(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr) * horizontal scrolling. */ - (*chunkPtr->bboxProc)(chunkPtr, index, dlPtr->y + dlPtr->spaceAbove, + (*chunkPtr->bboxProc)(chunkPtr, byteIndex, dlPtr->y + dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, xPtr, yPtr, widthPtr, heightPtr); *xPtr = *xPtr + dInfoPtr->x - dInfoPtr->curPixelOffset; - if ((index == (chunkPtr->numChars-1)) && (chunkPtr->nextPtr == NULL)) { + if ((byteIndex == (chunkPtr->numBytes - 1)) && (chunkPtr->nextPtr == NULL)) { /* * Last character in display line. Give it all the space up to * the line. @@ -4191,6 +4306,7 @@ TkTextDLineInfo(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr, basePtr) { TextDInfo *dInfoPtr = textPtr->dInfoPtr; DLine *dlPtr; + int dlx; /* * Make sure that all of the screen layout information is up to date. @@ -4209,8 +4325,9 @@ TkTextDLineInfo(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr, basePtr) return -1; } - *xPtr = dInfoPtr->x - dInfoPtr->curPixelOffset + dlPtr->chunkPtr->x; - *widthPtr = dlPtr->length - dlPtr->chunkPtr->x; + dlx = (dlPtr->chunkPtr != NULL? dlPtr->chunkPtr->x: 0); + *xPtr = dInfoPtr->x - dInfoPtr->curPixelOffset + dlx; + *widthPtr = dlPtr->length - dlx; *yPtr = dlPtr->y; if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) { *heightPtr = dInfoPtr->maxY - dlPtr->y; @@ -4221,6 +4338,41 @@ TkTextDLineInfo(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr, basePtr) return 0; } +static void +ElideBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr, + widthPtr, heightPtr) + TkTextDispChunk *chunkPtr; /* Chunk containing desired char. */ + int index; /* Index of desired character within + * the chunk. */ + int y; /* Topmost pixel in area allocated + * for this line. */ + int lineHeight; /* Height of line, in pixels. */ + int baseline; /* Location of line's baseline, in + * pixels measured down from y. */ + int *xPtr, *yPtr; /* Gets filled in with coords of + * character's upper-left pixel. + * X-coord is in same coordinate + * system as chunkPtr->x. */ + int *widthPtr; /* Gets filled in with width of + * character, in pixels. */ + int *heightPtr; /* Gets filled in with height of + * character, in pixels. */ +{ + *xPtr = chunkPtr->x; + *yPtr = y; + *widthPtr = *heightPtr = 0; +} + + +static int +ElideMeasureProc(chunkPtr, x) + TkTextDispChunk *chunkPtr; /* Chunk containing desired coord. */ + int x; /* X-coordinate, in same coordinate + * system as chunkPtr->x. */ +{ + return 0 /*chunkPtr->numBytes - 1*/; +} + /* *-------------------------------------------------------------- * @@ -4228,7 +4380,7 @@ TkTextDLineInfo(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr, basePtr) * * This procedure is the "layoutProc" for character segments. * - * Results: +n * Results: * If there is something to display for the chunk then a * non-zero value is returned and the fields of chunkPtr * will be filled in (see the declaration of TkTextDispChunk @@ -4245,29 +4397,29 @@ TkTextDLineInfo(textPtr, indexPtr, xPtr, yPtr, widthPtr, heightPtr, basePtr) */ int -TkTextCharLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars, +TkTextCharLayoutProc(textPtr, indexPtr, segPtr, byteOffset, maxX, maxBytes, noCharsYet, wrapMode, chunkPtr) TkText *textPtr; /* Text widget being layed out. */ TkTextIndex *indexPtr; /* Index of first character to lay out * (corresponds to segPtr and offset). */ TkTextSegment *segPtr; /* Segment being layed out. */ - int offset; /* Offset within segment of first character - * to consider. */ + int byteOffset; /* Byte offset within segment of first + * character to consider. */ int maxX; /* Chunk must not occupy pixels at this * position or higher. */ - int maxChars; /* Chunk must not include more than this + int maxBytes; /* Chunk must not include more than this * many characters. */ int noCharsYet; /* Non-zero means no characters have been * assigned to this display line yet. */ - Tk_Uid wrapMode; /* How to handle line wrapping: tkTextCharUid, - * tkTextNoneUid, or tkTextWordUid. */ + TkWrapMode wrapMode; /* How to handle line wrapping: TEXT_WRAPMODE_CHAR, + * TEXT_WRAPMODE_NONE, or TEXT_WRAPMODE_WORD. */ register TkTextDispChunk *chunkPtr; /* Structure to fill in with information * about this chunk. The x field has already * been set by the caller. */ { Tk_Font tkfont; - int nextX, charsThatFit, count; + int nextX, bytesThatFit, count; CharInfo *ciPtr; char *p; TkTextSegment *nextPtr; @@ -4285,17 +4437,19 @@ TkTextCharLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars, * is a white space character. */ - p = segPtr->body.chars + offset; + p = segPtr->body.chars + byteOffset; tkfont = chunkPtr->stylePtr->sValuePtr->tkfont; - charsThatFit = MeasureChars(tkfont, p, maxChars, chunkPtr->x, maxX, 0, + bytesThatFit = MeasureChars(tkfont, p, maxBytes, chunkPtr->x, maxX, 0, &nextX); - if (charsThatFit < maxChars) { - if ((charsThatFit == 0) && noCharsYet) { - charsThatFit = 1; - MeasureChars(tkfont, p, 1, chunkPtr->x, INT_MAX, 0, &nextX); + if (bytesThatFit < maxBytes) { + if ((bytesThatFit == 0) && noCharsYet) { + Tcl_UniChar ch; + + bytesThatFit = MeasureChars(tkfont, p, Tcl_UtfToUniChar(p, &ch), + chunkPtr->x, -1, 0, &nextX); } - if ((nextX < maxX) && ((p[charsThatFit] == ' ') - || (p[charsThatFit] == '\t'))) { + if ((nextX < maxX) && ((p[bytesThatFit] == ' ') + || (p[bytesThatFit] == '\t'))) { /* * Space characters are funny, in that they are considered * to fit if there is at least one pixel of space left on the @@ -4303,17 +4457,17 @@ TkTextCharLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars, */ nextX = maxX; - charsThatFit++; + bytesThatFit++; } - if (p[charsThatFit] == '\n') { + if (p[bytesThatFit] == '\n') { /* * A newline character takes up no space, so if the previous * character fits then so does the newline. */ - charsThatFit++; + bytesThatFit++; } - if (charsThatFit == 0) { + if (bytesThatFit == 0) { return 0; } } @@ -4330,19 +4484,19 @@ TkTextCharLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars, chunkPtr->undisplayProc = CharUndisplayProc; chunkPtr->measureProc = CharMeasureProc; chunkPtr->bboxProc = CharBboxProc; - chunkPtr->numChars = charsThatFit; + chunkPtr->numBytes = bytesThatFit; chunkPtr->minAscent = fm.ascent + chunkPtr->stylePtr->sValuePtr->offset; chunkPtr->minDescent = fm.descent - chunkPtr->stylePtr->sValuePtr->offset; chunkPtr->minHeight = 0; chunkPtr->width = nextX - chunkPtr->x; chunkPtr->breakIndex = -1; ciPtr = (CharInfo *) ckalloc((unsigned) - (sizeof(CharInfo) - 3 + charsThatFit)); + (sizeof(CharInfo) - 3 + bytesThatFit)); chunkPtr->clientData = (ClientData) ciPtr; - ciPtr->numChars = charsThatFit; - strncpy(ciPtr->chars, p, (size_t) charsThatFit); - if (p[charsThatFit-1] == '\n') { - ciPtr->numChars--; + ciPtr->numBytes = bytesThatFit; + strncpy(ciPtr->chars, p, (size_t) bytesThatFit); + if (p[bytesThatFit - 1] == '\n') { + ciPtr->numBytes--; } /* @@ -4352,22 +4506,22 @@ TkTextCharLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars, * is not a character segment. */ - if (wrapMode != tkTextWordUid) { - chunkPtr->breakIndex = chunkPtr->numChars; + if (wrapMode != TEXT_WRAPMODE_WORD) { + chunkPtr->breakIndex = chunkPtr->numBytes; } else { - for (count = charsThatFit, p += charsThatFit-1; count > 0; + for (count = bytesThatFit, p += bytesThatFit - 1; count > 0; count--, p--) { if (isspace(UCHAR(*p))) { chunkPtr->breakIndex = count; break; } } - if ((charsThatFit+offset) == segPtr->size) { + if ((bytesThatFit + byteOffset) == segPtr->size) { for (nextPtr = segPtr->nextPtr; nextPtr != NULL; nextPtr = nextPtr->nextPtr) { if (nextPtr->size != 0) { if (nextPtr->typePtr != &tkTextCharType) { - chunkPtr->breakIndex = chunkPtr->numChars; + chunkPtr->breakIndex = chunkPtr->numBytes; } break; } @@ -4414,7 +4568,7 @@ CharDisplayProc(chunkPtr, x, y, height, baseline, display, dst, screenY) CharInfo *ciPtr = (CharInfo *) chunkPtr->clientData; TextStyle *stylePtr; StyleValues *sValuePtr; - int offsetChars, offsetX; + int offsetBytes, offsetX; if ((x + chunkPtr->width) <= 0) { /* @@ -4436,30 +4590,29 @@ CharDisplayProc(chunkPtr, x, y, height, baseline, display, dst, screenY) */ offsetX = x; - offsetChars = 0; + offsetBytes = 0; if (x < 0) { - offsetChars = MeasureChars(sValuePtr->tkfont, ciPtr->chars, - ciPtr->numChars, x, 0, x - chunkPtr->x, &offsetX); + offsetBytes = MeasureChars(sValuePtr->tkfont, ciPtr->chars, + ciPtr->numBytes, x, 0, x - chunkPtr->x, &offsetX); } /* * Draw the text, underline, and overstrike for this chunk. */ - if (ciPtr->numChars > offsetChars) { - int numChars = ciPtr->numChars - offsetChars; - char *string = ciPtr->chars + offsetChars; + if (!sValuePtr->elide && (ciPtr->numBytes > offsetBytes) && (stylePtr->fgGC != None)) { + int numBytes = ciPtr->numBytes - offsetBytes; + char *string = ciPtr->chars + offsetBytes; - if ((numChars > 0) && (string[numChars - 1] == '\t')) { - numChars--; + if ((numBytes > 0) && (string[numBytes - 1] == '\t')) { + numBytes--; } Tk_DrawChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, string, - numChars, offsetX, y + baseline - sValuePtr->offset); + numBytes, offsetX, y + baseline - sValuePtr->offset); if (sValuePtr->underline) { Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, - ciPtr->chars + offsetChars, offsetX, - y + baseline - sValuePtr->offset, - 0, numChars); + ciPtr->chars + offsetBytes, offsetX, + y + baseline - sValuePtr->offset, 0, numBytes); } if (sValuePtr->overstrike) { @@ -4467,10 +4620,10 @@ CharDisplayProc(chunkPtr, x, y, height, baseline, display, dst, screenY) Tk_GetFontMetrics(sValuePtr->tkfont, &fm); Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, - ciPtr->chars + offsetChars, offsetX, + ciPtr->chars + offsetBytes, offsetX, y + baseline - sValuePtr->offset - fm.descent - (fm.ascent * 3) / 10, - 0, numChars); + 0, numBytes); } } } @@ -4532,7 +4685,8 @@ CharMeasureProc(chunkPtr, x) int endX; return MeasureChars(chunkPtr->stylePtr->sValuePtr->tkfont, ciPtr->chars, - chunkPtr->numChars-1, chunkPtr->x, x, 0, &endX); + chunkPtr->numBytes - 1, chunkPtr->x, x, 0, &endX); + /* CHAR OFFSET */ } /* @@ -4559,11 +4713,11 @@ CharMeasureProc(chunkPtr, x) */ static void -CharBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr, +CharBboxProc(chunkPtr, byteIndex, y, lineHeight, baseline, xPtr, yPtr, widthPtr, heightPtr) TkTextDispChunk *chunkPtr; /* Chunk containing desired char. */ - int index; /* Index of desired character within - * the chunk. */ + int byteIndex; /* Byte offset of desired character + * within the chunk. */ int y; /* Topmost pixel in area allocated * for this line. */ int lineHeight; /* Height of line, in pixels. */ @@ -4582,10 +4736,10 @@ CharBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr, int maxX; maxX = chunkPtr->width + chunkPtr->x; - MeasureChars(chunkPtr->stylePtr->sValuePtr->tkfont, ciPtr->chars, index, - chunkPtr->x, 1000000, 0, xPtr); + MeasureChars(chunkPtr->stylePtr->sValuePtr->tkfont, ciPtr->chars, + byteIndex, chunkPtr->x, -1, 0, xPtr); - if (index == ciPtr->numChars) { + if (byteIndex == ciPtr->numBytes) { /* * This situation only happens if the last character in a line * is a space character, in which case it absorbs all of the @@ -4593,8 +4747,8 @@ CharBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr, */ *widthPtr = maxX - *xPtr; - } else if ((ciPtr->chars[index] == '\t') - && (index == (ciPtr->numChars-1))) { + } else if ((ciPtr->chars[byteIndex] == '\t') + && (byteIndex == ciPtr->numBytes - 1)) { /* * The desired character is a tab character that terminates a * chunk; give it all the space left in the chunk. @@ -4603,7 +4757,7 @@ CharBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr, *widthPtr = maxX - *xPtr; } else { MeasureChars(chunkPtr->stylePtr->sValuePtr->tkfont, - ciPtr->chars + index, 1, *xPtr, 1000000, 0, widthPtr); + ciPtr->chars + byteIndex, 1, *xPtr, -1, 0, widthPtr); if (*widthPtr > maxX) { *widthPtr = maxX - *xPtr; } else { @@ -4738,7 +4892,7 @@ AdjustForTab(textPtr, tabArrayPtr, index, chunkPtr) continue; } ciPtr = (CharInfo *) chunkPtr2->clientData; - for (p = ciPtr->chars, i = 0; i < ciPtr->numChars; p++, i++) { + for (p = ciPtr->chars, i = 0; i < ciPtr->numBytes; p++, i++) { if (isdigit(UCHAR(*p))) { gotDigit = 1; } else if ((*p == '.') || (*p == ',')) { @@ -4759,7 +4913,7 @@ AdjustForTab(textPtr, tabArrayPtr, index, chunkPtr) ciPtr = (CharInfo *) decimalChunkPtr->clientData; MeasureChars(decimalChunkPtr->stylePtr->sValuePtr->tkfont, - ciPtr->chars, decimal, decimalChunkPtr->x, 1000000, 0, &curX); + ciPtr->chars, decimal, decimalChunkPtr->x, -1, 0, &curX); desired = tabX - (curX - x); goto update; } else { @@ -4784,7 +4938,7 @@ AdjustForTab(textPtr, tabArrayPtr, index, chunkPtr) update: delta = desired - x; - MeasureChars(textPtr->tkfont, " ", 1, 0, INT_MAX, 0, &spaceWidth); + MeasureChars(textPtr->tkfont, " ", 1, 0, -1, 0, &spaceWidth); if (delta < spaceWidth) { delta = spaceWidth; } @@ -4889,7 +5043,7 @@ SizeOfTab(textPtr, tabArrayPtr, index, x, maxX) } done: - MeasureChars(textPtr->tkfont, " ", 1, 0, INT_MAX, 0, &spaceWidth); + MeasureChars(textPtr->tkfont, " ", 1, 0, -1, 0, &spaceWidth); if (result < spaceWidth) { result = spaceWidth; } @@ -4953,7 +5107,7 @@ NextTabStop(textPtr, tkfont, x, tabOrigin) * * Determine the number of characters from the string that will fit * in the given horizontal span. The measurement is done under the - * assumption that Tk_DisplayChars will be used to actually display + * assumption that Tk_DrawTextLayout will be used to actually display * the characters. * * If tabs are encountered in the string, they will be expanded @@ -4964,7 +5118,7 @@ NextTabStop(textPtr, tkfont, x, tabOrigin) * is specified. * * Results: - * The return value is the number of characters from source + * The return value is the number of bytes from source * that fit in the span given by startX and maxX. *nextXPtr * is filled in with the x-coordinate at which the first * character that didn't fit would be drawn, if it were to @@ -4977,11 +5131,11 @@ NextTabStop(textPtr, tkfont, x, tabOrigin) */ static int -MeasureChars(tkfont, source, maxChars, startX, maxX, tabOrigin, nextXPtr) +MeasureChars(tkfont, source, maxBytes, startX, maxX, tabOrigin, nextXPtr) Tk_Font tkfont; /* Font in which to draw characters. */ CONST char *source; /* Characters to be displayed. Need not * be NULL-terminated. */ - int maxChars; /* Maximum # of characters to consider from + int maxBytes; /* Maximum # of bytes to consider from * source. */ int startX; /* X-position at which first character will * be drawn. */ @@ -4998,7 +5152,7 @@ MeasureChars(tkfont, source, maxChars, startX, maxX, tabOrigin, nextXPtr) ch = 0; /* lint. */ curX = startX; special = source; - end = source + maxChars; + end = source + maxBytes; for (start = source; start < end; ) { if (start >= special) { /* @@ -5018,7 +5172,7 @@ MeasureChars(tkfont, source, maxChars, startX, maxX, tabOrigin, nextXPtr) * string). Process characters between start and special. */ - if (curX >= maxX) { + if ((maxX >= 0) && (curX >= maxX)) { break; } start += Tk_MeasureChars(tkfont, start, special - start, maxX - curX, @@ -5043,3 +5197,4 @@ MeasureChars(tkfont, source, maxChars, startX, maxX, tabOrigin, nextXPtr) *nextXPtr = curX; return start - source; } + diff --git a/tk/generic/tkTextImage.c b/tk/generic/tkTextImage.c index 2083d101895..01757b071f8 100644 --- a/tk/generic/tkTextImage.c +++ b/tk/generic/tkTextImage.c @@ -5,7 +5,7 @@ * nested inside text widgets. It also implements the "image" * widget command for texts. * - * Copyright (c) 1996 Sun Microsystems, Inc. + * Copyright (c) 1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -62,7 +62,7 @@ static void EmbImageDisplayProc _ANSI_ARGS_(( static int EmbImageLayoutProc _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, TkTextSegment *segPtr, int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, + int noCharsYet, TkWrapMode wrapMode, TkTextDispChunk *chunkPtr)); static void EmbImageProc _ANSI_ARGS_((ClientData clientData, int x, int y, int width, int height, @@ -221,7 +221,7 @@ TkTextImageCmd(textPtr, interp, argc, argv) lineIndex = TkBTreeLineIndex(index.linePtr); if (lineIndex == TkBTreeNumLines(textPtr->tree)) { lineIndex--; - TkTextMakeIndex(textPtr->tree, lineIndex, 1000000, &index); + TkTextMakeByteIndex(textPtr->tree, lineIndex, 1000000, &index); } /* @@ -288,7 +288,7 @@ TkTextImageCmd(textPtr, interp, argc, argv) * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message.. + * returned, then the interp's result contains an error message.. * * Side effects: * Configuration information for the embedded image changes, @@ -384,7 +384,7 @@ EmbImageConfigure(textPtr, eiPtr, argc, argv) Tcl_DStringAppend(&newName,name, -1); if (conflict) { - char buf[10]; + char buf[4 + TCL_INTEGER_SPACE]; sprintf(buf, "#%d",count+1); Tcl_DStringAppend(&newName,buf, -1); } @@ -604,8 +604,8 @@ EmbImageLayoutProc(textPtr, indexPtr, eiPtr, offset, maxX, maxChars, * many characters. */ int noCharsYet; /* Non-zero means no characters have been * assigned to this line yet. */ - Tk_Uid wrapMode; /* Wrap mode to use for line: tkTextCharUid, - * tkTextNoneUid, or tkTextWordUid. */ + TkWrapMode wrapMode; /* Wrap mode to use for line: TEXT_WRAPMODE_CHAR, + * TEXT_WRAPMODE_NONE, or TEXT_WRAPMODE_WORD. */ register TkTextDispChunk *chunkPtr; /* Structure to fill in with information * about this chunk. The x field has already @@ -630,7 +630,7 @@ EmbImageLayoutProc(textPtr, indexPtr, eiPtr, offset, maxX, maxChars, height += 2*eiPtr->body.ei.padY; } if ((width > (maxX - chunkPtr->x)) - && !noCharsYet && (textPtr->wrapMode != tkTextNoneUid)) { + && !noCharsYet && (textPtr->wrapMode != TEXT_WRAPMODE_NONE)) { return 0; } @@ -642,7 +642,7 @@ EmbImageLayoutProc(textPtr, indexPtr, eiPtr, offset, maxX, maxChars, chunkPtr->undisplayProc = (Tk_ChunkUndisplayProc *) NULL; chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL; chunkPtr->bboxProc = EmbImageBboxProc; - chunkPtr->numChars = 1; + chunkPtr->numBytes = 1; if (eiPtr->body.ei.align == ALIGN_BASELINE) { chunkPtr->minAscent = height - eiPtr->body.ei.padY; chunkPtr->minDescent = eiPtr->body.ei.padY; @@ -857,7 +857,7 @@ TkTextImageIndex(textPtr, name, indexPtr) eiPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); indexPtr->tree = textPtr->tree; indexPtr->linePtr = eiPtr->body.ei.linePtr; - indexPtr->charIndex = TkTextSegToOffset(eiPtr, indexPtr->linePtr); + indexPtr->byteIndex = TkTextSegToOffset(eiPtr, indexPtr->linePtr); return 1; } @@ -893,6 +893,7 @@ EmbImageProc(clientData, x, y, width, height, imgWidth, imgHeight) index.tree = eiPtr->body.ei.textPtr->tree; index.linePtr = eiPtr->body.ei.linePtr; - index.charIndex = TkTextSegToOffset(eiPtr, eiPtr->body.ei.linePtr); + index.byteIndex = TkTextSegToOffset(eiPtr, eiPtr->body.ei.linePtr); TkTextChanged(eiPtr->body.ei.textPtr, &index, &index); } + diff --git a/tk/generic/tkTextIndex.c b/tk/generic/tkTextIndex.c index f2e9b0316ab..0b59b536c07 100644 --- a/tk/generic/tkTextIndex.c +++ b/tk/generic/tkTextIndex.c @@ -5,7 +5,7 @@ * text widgets. * * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -34,27 +34,118 @@ static char * StartEnd _ANSI_ARGS_(( char *string, TkTextIndex *indexPtr)); /* - *-------------------------------------------------------------- + *--------------------------------------------------------------------------- * - * TkTextMakeIndex -- + * TkTextMakeByteIndex -- * - * Given a line index and a character index, look things up - * in the B-tree and fill in a TkTextIndex structure. + * Given a line index and a byte index, look things up in the B-tree + * and fill in a TkTextIndex structure. * * Results: - * The structure at *indexPtr is filled in with information - * about the character at lineIndex and charIndex (or the - * closest existing character, if the specified one doesn't - * exist), and indexPtr is returned as result. + * The structure at *indexPtr is filled in with information about the + * character at lineIndex and byteIndex (or the closest existing + * character, if the specified one doesn't exist), and indexPtr is + * returned as result. * * Side effects: * None. * - *-------------------------------------------------------------- + *--------------------------------------------------------------------------- */ TkTextIndex * -TkTextMakeIndex(tree, lineIndex, charIndex, indexPtr) +TkTextMakeByteIndex(tree, lineIndex, byteIndex, indexPtr) + TkTextBTree tree; /* Tree that lineIndex and charIndex refer + * to. */ + int lineIndex; /* Index of desired line (0 means first + * line of text). */ + int byteIndex; /* Byte index of desired character. */ + TkTextIndex *indexPtr; /* Structure to fill in. */ +{ + TkTextSegment *segPtr; + int index; + char *p, *start; + Tcl_UniChar ch; + + indexPtr->tree = tree; + if (lineIndex < 0) { + lineIndex = 0; + byteIndex = 0; + } + if (byteIndex < 0) { + byteIndex = 0; + } + indexPtr->linePtr = TkBTreeFindLine(tree, lineIndex); + if (indexPtr->linePtr == NULL) { + indexPtr->linePtr = TkBTreeFindLine(tree, TkBTreeNumLines(tree)); + byteIndex = 0; + } + if (byteIndex == 0) { + indexPtr->byteIndex = byteIndex; + return indexPtr; + } + + /* + * Verify that the index is within the range of the line and points + * to a valid character boundary. + */ + + index = 0; + for (segPtr = indexPtr->linePtr->segPtr; ; segPtr = segPtr->nextPtr) { + if (segPtr == NULL) { + /* + * Use the index of the last character in the line. Since + * the last character on the line is guaranteed to be a '\n', + * we can back up a constant sizeof(char) bytes. + */ + + indexPtr->byteIndex = index - sizeof(char); + break; + } + if (index + segPtr->size > byteIndex) { + indexPtr->byteIndex = byteIndex; + if ((byteIndex > index) && (segPtr->typePtr == &tkTextCharType)) { + /* + * Prevent UTF-8 character from being split up by ensuring + * that byteIndex falls on a character boundary. If index + * falls in the middle of a UTF-8 character, it will be + * adjusted to the end of that UTF-8 character. + */ + + start = segPtr->body.chars + (byteIndex - index); + p = Tcl_UtfPrev(start, segPtr->body.chars); + p += Tcl_UtfToUniChar(p, &ch); + indexPtr->byteIndex += p - start; + } + break; + } + index += segPtr->size; + } + return indexPtr; +} + +/* + *--------------------------------------------------------------------------- + * + * TkTextMakeCharIndex -- + * + * Given a line index and a character index, look things up in the + * B-tree and fill in a TkTextIndex structure. + * + * Results: + * The structure at *indexPtr is filled in with information about the + * character at lineIndex and charIndex (or the closest existing + * character, if the specified one doesn't exist), and indexPtr is + * returned as result. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +TkTextIndex * +TkTextMakeCharIndex(tree, lineIndex, charIndex, indexPtr) TkTextBTree tree; /* Tree that lineIndex and charIndex refer * to. */ int lineIndex; /* Index of desired line (0 means first @@ -63,7 +154,9 @@ TkTextMakeIndex(tree, lineIndex, charIndex, indexPtr) TkTextIndex *indexPtr; /* Structure to fill in. */ { register TkTextSegment *segPtr; - int index; + char *p, *start, *end; + int index, offset; + Tcl_UniChar ch; indexPtr->tree = tree; if (lineIndex < 0) { @@ -84,53 +177,76 @@ TkTextMakeIndex(tree, lineIndex, charIndex, indexPtr) * If not, just use the index of the last character in the line. */ - for (index = 0, segPtr = indexPtr->linePtr->segPtr; ; - segPtr = segPtr->nextPtr) { + index = 0; + for (segPtr = indexPtr->linePtr->segPtr; ; segPtr = segPtr->nextPtr) { if (segPtr == NULL) { - indexPtr->charIndex = index-1; + /* + * Use the index of the last character in the line. Since + * the last character on the line is guaranteed to be a '\n', + * we can back up a constant sizeof(char) bytes. + */ + + indexPtr->byteIndex = index - sizeof(char); break; } - index += segPtr->size; - if (index > charIndex) { - indexPtr->charIndex = charIndex; - break; + if (segPtr->typePtr == &tkTextCharType) { + /* + * Turn character offset into a byte offset. + */ + + start = segPtr->body.chars; + end = start + segPtr->size; + for (p = start; p < end; p += offset) { + if (charIndex == 0) { + indexPtr->byteIndex = index; + return indexPtr; + } + charIndex--; + offset = Tcl_UtfToUniChar(p, &ch); + index += offset; + } + } else { + if (charIndex < segPtr->size) { + indexPtr->byteIndex = index; + break; + } + charIndex -= segPtr->size; + index += segPtr->size; } } return indexPtr; } /* - *-------------------------------------------------------------- + *--------------------------------------------------------------------------- * * TkTextIndexToSeg -- * - * Given an index, this procedure returns the segment and - * offset within segment for the index. + * Given an index, this procedure returns the segment and offset + * within segment for the index. * * Results: - * The return value is a pointer to the segment referred to - * by indexPtr; this will always be a segment with non-zero - * size. The variable at *offsetPtr is set to hold the - * integer offset within the segment of the character - * given by indexPtr. + * The return value is a pointer to the segment referred to by + * indexPtr; this will always be a segment with non-zero size. The + * variable at *offsetPtr is set to hold the integer offset within + * the segment of the character given by indexPtr. * * Side effects: * None. * - *-------------------------------------------------------------- + *--------------------------------------------------------------------------- */ TkTextSegment * TkTextIndexToSeg(indexPtr, offsetPtr) - TkTextIndex *indexPtr; /* Text index. */ - int *offsetPtr; /* Where to store offset within - * segment, or NULL if offset isn't - * wanted. */ + CONST TkTextIndex *indexPtr;/* Text index. */ + int *offsetPtr; /* Where to store offset within segment, or + * NULL if offset isn't wanted. */ { - register TkTextSegment *segPtr; + TkTextSegment *segPtr; int offset; - for (offset = indexPtr->charIndex, segPtr = indexPtr->linePtr->segPtr; + for (offset = indexPtr->byteIndex, segPtr = indexPtr->linePtr->segPtr; offset >= segPtr->size; offset -= segPtr->size, segPtr = segPtr->nextPtr) { /* Empty loop body. */ @@ -142,30 +258,29 @@ TkTextIndexToSeg(indexPtr, offsetPtr) } /* - *-------------------------------------------------------------- + *--------------------------------------------------------------------------- * * TkTextSegToOffset -- * - * Given a segment pointer and the line containing it, this - * procedure returns the offset of the segment within its - * line. + * Given a segment pointer and the line containing it, this procedure + * returns the offset of the segment within its line. * * Results: - * The return value is the offset (within its line) of the - * first character in segPtr. + * The return value is the offset (within its line) of the first + * character in segPtr. * * Side effects: * None. * - *-------------------------------------------------------------- + *--------------------------------------------------------------------------- */ int TkTextSegToOffset(segPtr, linePtr) - TkTextSegment *segPtr; /* Segment whose offset is desired. */ - TkTextLine *linePtr; /* Line containing segPtr. */ + CONST TkTextSegment *segPtr;/* Segment whose offset is desired. */ + CONST TkTextLine *linePtr; /* Line containing segPtr. */ { - TkTextSegment *segPtr2; + CONST TkTextSegment *segPtr2; int offset; offset = 0; @@ -177,23 +292,22 @@ TkTextSegToOffset(segPtr, linePtr) } /* - *---------------------------------------------------------------------- + *--------------------------------------------------------------------------- * * TkTextGetIndex -- * - * Given a string, return the line and character indices that - * it describes. + * Given a string, return the index that is described. * * Results: - * The return value is a standard Tcl return result. If - * TCL_OK is returned, then everything went well and the index - * at *indexPtr is filled in; otherwise TCL_ERROR is returned - * and an error message is left in interp->result. + * The return value is a standard Tcl return result. If TCL_OK is + * returned, then everything went well and the index at *indexPtr is + * filled in; otherwise TCL_ERROR is returned and an error message + * is left in the interp's result. * * Side effects: * None. * - *---------------------------------------------------------------------- + *--------------------------------------------------------------------------- */ int @@ -203,8 +317,7 @@ TkTextGetIndex(interp, textPtr, string, indexPtr) char *string; /* Textual description of position. */ TkTextIndex *indexPtr; /* Index structure to fill in. */ { - register char *p; - char *end, *endOfBase; + char *p, *end, *endOfBase; Tcl_HashEntry *hPtr; TkTextTag *tagPtr; TkTextSearch search; @@ -259,8 +372,8 @@ TkTextGetIndex(interp, textPtr, string, indexPtr) goto tryxy; } tagPtr = (TkTextTag *) Tcl_GetHashValue(hPtr); - TkTextMakeIndex(textPtr->tree, 0, 0, &first); - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, + TkTextMakeByteIndex(textPtr->tree, 0, 0, &first); + TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &last); TkBTreeStartSearch(&first, &last, tagPtr, &search); if (!TkBTreeCharTagged(&first, tagPtr) && !TkBTreeNextTag(&search)) { @@ -324,7 +437,7 @@ TkTextGetIndex(interp, textPtr, string, indexPtr) } endOfBase = end; } - TkTextMakeIndex(textPtr->tree, lineIndex, charIndex, indexPtr); + TkTextMakeCharIndex(textPtr->tree, lineIndex, charIndex, indexPtr); goto gotBase; } @@ -353,7 +466,7 @@ TkTextGetIndex(interp, textPtr, string, indexPtr) * Base position is end of text. */ - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), + TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, indexPtr); goto gotBase; } else { @@ -420,13 +533,12 @@ TkTextGetIndex(interp, textPtr, string, indexPtr) } /* - *---------------------------------------------------------------------- + *--------------------------------------------------------------------------- * * TkTextPrintIndex -- - * * - * This procedure generates a string description of an index, - * suitable for reading in again later. + * This procedure generates a string description of an index, suitable + * for reading in again later. * * Results: * The characters pointed to by string are modified. @@ -434,49 +546,69 @@ TkTextGetIndex(interp, textPtr, string, indexPtr) * Side effects: * None. * - *---------------------------------------------------------------------- + *--------------------------------------------------------------------------- */ void TkTextPrintIndex(indexPtr, string) - TkTextIndex *indexPtr; /* Pointer to index. */ + CONST TkTextIndex *indexPtr;/* Pointer to index. */ char *string; /* Place to store the position. Must have * at least TK_POS_CHARS characters. */ { + TkTextSegment *segPtr; + int numBytes, charIndex; + + numBytes = indexPtr->byteIndex; + charIndex = 0; + for (segPtr = indexPtr->linePtr->segPtr; ; segPtr = segPtr->nextPtr) { + if (numBytes <= segPtr->size) { + break; + } + if (segPtr->typePtr == &tkTextCharType) { + charIndex += Tcl_NumUtfChars(segPtr->body.chars, segPtr->size); + } else { + charIndex += segPtr->size; + } + numBytes -= segPtr->size; + } + if (segPtr->typePtr == &tkTextCharType) { + charIndex += Tcl_NumUtfChars(segPtr->body.chars, numBytes); + } else { + charIndex += numBytes; + } sprintf(string, "%d.%d", TkBTreeLineIndex(indexPtr->linePtr) + 1, - indexPtr->charIndex); + charIndex); } /* - *-------------------------------------------------------------- + *--------------------------------------------------------------------------- * * TkTextIndexCmp -- * - * Compare two indices to see which one is earlier in - * the text. + * Compare two indices to see which one is earlier in the text. * * Results: - * The return value is 0 if index1Ptr and index2Ptr refer - * to the same position in the file, -1 if index1Ptr refers - * to an earlier position than index2Ptr, and 1 otherwise. + * The return value is 0 if index1Ptr and index2Ptr refer to the same + * position in the file, -1 if index1Ptr refers to an earlier position + * than index2Ptr, and 1 otherwise. * * Side effects: * None. * - *-------------------------------------------------------------- + *--------------------------------------------------------------------------- */ int TkTextIndexCmp(index1Ptr, index2Ptr) - TkTextIndex *index1Ptr; /* First index. */ - TkTextIndex *index2Ptr; /* Second index. */ + CONST TkTextIndex *index1Ptr; /* First index. */ + CONST TkTextIndex *index2Ptr; /* Second index. */ { int line1, line2; if (index1Ptr->linePtr == index2Ptr->linePtr) { - if (index1Ptr->charIndex < index2Ptr->charIndex) { + if (index1Ptr->byteIndex < index2Ptr->byteIndex) { return -1; - } else if (index1Ptr->charIndex > index2Ptr->charIndex) { + } else if (index1Ptr->byteIndex > index2Ptr->byteIndex) { return 1; } else { return 0; @@ -494,23 +626,23 @@ TkTextIndexCmp(index1Ptr, index2Ptr) } /* - *---------------------------------------------------------------------- + *--------------------------------------------------------------------------- * * ForwBack -- * - * This procedure handles +/- modifiers for indices to adjust - * the index forwards or backwards. + * This procedure handles +/- modifiers for indices to adjust the + * index forwards or backwards. * * Results: - * If the modifier in string is successfully parsed then the - * return value is the address of the first character after the - * modifier, and *indexPtr is updated to reflect the modifier. - * If there is a syntax error in the modifier then NULL is returned. + * If the modifier in string is successfully parsed then the return + * value is the address of the first character after the modifier, + * and *indexPtr is updated to reflect the modifier. If there is a + * syntax error in the modifier then NULL is returned. * * Side effects: * None. * - *---------------------------------------------------------------------- + *--------------------------------------------------------------------------- */ static char * @@ -550,7 +682,7 @@ ForwBack(string, indexPtr) */ units = p; - while ((*p != 0) && !isspace(UCHAR(*p)) && (*p != '+') && (*p != '-')) { + while ((*p != '\0') && !isspace(UCHAR(*p)) && (*p != '+') && (*p != '-')) { p++; } length = p - units; @@ -578,7 +710,18 @@ ForwBack(string, indexPtr) lineIndex = 0; } } - TkTextMakeIndex(indexPtr->tree, lineIndex, indexPtr->charIndex, + /* + * This doesn't work quite right if using a proportional font or + * UTF-8 characters with varying numbers of bytes. The cursor will + * bop around, keeping a constant number of bytes (not characters) + * from the left edge (but making sure not to split any UTF-8 + * characters), regardless of the x-position the index corresponds + * to. The proper way to do this is to get the x-position of the + * index and then pick the character at the same x-position in the + * new line. + */ + + TkTextMakeByteIndex(indexPtr->tree, lineIndex, indexPtr->byteIndex, indexPtr); } else { return NULL; @@ -587,44 +730,42 @@ ForwBack(string, indexPtr) } /* - *---------------------------------------------------------------------- + *--------------------------------------------------------------------------- * - * TkTextIndexForwChars -- + * TkTextIndexForwBytes -- * - * Given an index for a text widget, this procedure creates a - * new index that points "count" characters ahead of the source - * index. + * Given an index for a text widget, this procedure creates a new + * index that points "count" bytes ahead of the source index. * * Results: - * *dstPtr is modified to refer to the character "count" characters - * after srcPtr, or to the last character in the file if there aren't - * "count" characters left in the file. + * *dstPtr is modified to refer to the character "count" bytes after + * srcPtr, or to the last character in the TkText if there aren't + * "count" bytes left. * * Side effects: * None. * - *---------------------------------------------------------------------- + *--------------------------------------------------------------------------- */ - /* ARGSUSED */ void -TkTextIndexForwChars(srcPtr, count, dstPtr) - TkTextIndex *srcPtr; /* Source index. */ - int count; /* How many characters forward to - * move. May be negative. */ - TkTextIndex *dstPtr; /* Destination index: gets modified. */ +TkTextIndexForwBytes(srcPtr, byteCount, dstPtr) + CONST TkTextIndex *srcPtr; /* Source index. */ + int byteCount; /* How many bytes forward to move. May be + * negative. */ + TkTextIndex *dstPtr; /* Destination index: gets modified. */ { TkTextLine *linePtr; TkTextSegment *segPtr; int lineLength; - if (count < 0) { - TkTextIndexBackChars(srcPtr, -count, dstPtr); + if (byteCount < 0) { + TkTextIndexBackBytes(srcPtr, -byteCount, dstPtr); return; } *dstPtr = *srcPtr; - dstPtr->charIndex += count; + dstPtr->byteIndex += byteCount; while (1) { /* * Compute the length of the current line. @@ -641,13 +782,13 @@ TkTextIndexForwChars(srcPtr, count, dstPtr) * Otherwise go on to the next line. */ - if (dstPtr->charIndex < lineLength) { + if (dstPtr->byteIndex < lineLength) { return; } - dstPtr->charIndex -= lineLength; + dstPtr->byteIndex -= lineLength; linePtr = TkBTreeNextLine(dstPtr->linePtr); if (linePtr == NULL) { - dstPtr->charIndex = lineLength - 1; + dstPtr->byteIndex = lineLength - 1; return; } dstPtr->linePtr = linePtr; @@ -655,44 +796,133 @@ TkTextIndexForwChars(srcPtr, count, dstPtr) } /* - *---------------------------------------------------------------------- + *--------------------------------------------------------------------------- * - * TkTextIndexBackChars -- + * TkTextIndexForwChars -- * - * Given an index for a text widget, this procedure creates a - * new index that points "count" characters earlier than the - * source index. + * Given an index for a text widget, this procedure creates a new + * index that points "count" characters ahead of the source index. * * Results: * *dstPtr is modified to refer to the character "count" characters - * before srcPtr, or to the first character in the file if there aren't - * "count" characters earlier than srcPtr. + * after srcPtr, or to the last character in the TkText if there + * aren't "count" characters left in the file. * * Side effects: * None. * - *---------------------------------------------------------------------- + *--------------------------------------------------------------------------- */ void -TkTextIndexBackChars(srcPtr, count, dstPtr) - TkTextIndex *srcPtr; /* Source index. */ - int count; /* How many characters backward to - * move. May be negative. */ - TkTextIndex *dstPtr; /* Destination index: gets modified. */ +TkTextIndexForwChars(srcPtr, charCount, dstPtr) + CONST TkTextIndex *srcPtr; /* Source index. */ + int charCount; /* How many characters forward to move. + * May be negative. */ + TkTextIndex *dstPtr; /* Destination index: gets modified. */ +{ + TkTextLine *linePtr; + TkTextSegment *segPtr; + int byteOffset; + char *start, *end, *p; + Tcl_UniChar ch; + + if (charCount < 0) { + TkTextIndexBackChars(srcPtr, -charCount, dstPtr); + return; + } + + *dstPtr = *srcPtr; + + /* + * Find seg that contains src byteIndex. + * Move forward specified number of chars. + */ + + segPtr = TkTextIndexToSeg(dstPtr, &byteOffset); + while (1) { + /* + * Go through each segment in line looking for specified character + * index. + */ + + for ( ; segPtr != NULL; segPtr = segPtr->nextPtr) { + if (segPtr->typePtr == &tkTextCharType) { + start = segPtr->body.chars + byteOffset; + end = segPtr->body.chars + segPtr->size; + for (p = start; p < end; p += Tcl_UtfToUniChar(p, &ch)) { + if (charCount == 0) { + dstPtr->byteIndex += (p - start); + return; + } + charCount--; + } + } else { + if (charCount < segPtr->size - byteOffset) { + dstPtr->byteIndex += charCount; + return; + } + charCount -= segPtr->size - byteOffset; + } + dstPtr->byteIndex += segPtr->size - byteOffset; + byteOffset = 0; + } + + /* + * Go to the next line. If we are at the end of the text item, + * back up one byte (for the terminal '\n' character) and return + * that index. + */ + + linePtr = TkBTreeNextLine(dstPtr->linePtr); + if (linePtr == NULL) { + dstPtr->byteIndex -= sizeof(char); + return; + } + dstPtr->linePtr = linePtr; + dstPtr->byteIndex = 0; + segPtr = dstPtr->linePtr->segPtr; + } +} + +/* + *--------------------------------------------------------------------------- + * + * TkTextIndexBackBytes -- + * + * Given an index for a text widget, this procedure creates a new + * index that points "count" bytes earlier than the source index. + * + * Results: + * *dstPtr is modified to refer to the character "count" bytes before + * srcPtr, or to the first character in the TkText if there aren't + * "count" bytes earlier than srcPtr. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +void +TkTextIndexBackBytes(srcPtr, byteCount, dstPtr) + CONST TkTextIndex *srcPtr; /* Source index. */ + int byteCount; /* How many bytes backward to move. May be + * negative. */ + TkTextIndex *dstPtr; /* Destination index: gets modified. */ { TkTextSegment *segPtr; int lineIndex; - if (count < 0) { - TkTextIndexForwChars(srcPtr, -count, dstPtr); + if (byteCount < 0) { + TkTextIndexForwBytes(srcPtr, -byteCount, dstPtr); return; } *dstPtr = *srcPtr; - dstPtr->charIndex -= count; + dstPtr->byteIndex -= byteCount; lineIndex = -1; - while (dstPtr->charIndex < 0) { + while (dstPtr->byteIndex < 0) { /* * Move back one line in the text. If we run off the beginning * of the file then just return the first character in the text. @@ -702,7 +932,7 @@ TkTextIndexBackChars(srcPtr, count, dstPtr) lineIndex = TkBTreeLineIndex(dstPtr->linePtr); } if (lineIndex == 0) { - dstPtr->charIndex = 0; + dstPtr->byteIndex = 0; return; } lineIndex--; @@ -714,12 +944,128 @@ TkTextIndexBackChars(srcPtr, count, dstPtr) for (segPtr = dstPtr->linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { - dstPtr->charIndex += segPtr->size; + dstPtr->byteIndex += segPtr->size; } } } /* + *--------------------------------------------------------------------------- + * + * TkTextIndexBackChars -- + * + * Given an index for a text widget, this procedure creates a new + * index that points "count" characters earlier than the source index. + * + * Results: + * *dstPtr is modified to refer to the character "count" characters + * before srcPtr, or to the first character in the file if there + * aren't "count" characters earlier than srcPtr. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +void +TkTextIndexBackChars(srcPtr, charCount, dstPtr) + CONST TkTextIndex *srcPtr; /* Source index. */ + int charCount; /* How many characters backward to move. + * May be negative. */ + TkTextIndex *dstPtr; /* Destination index: gets modified. */ +{ + TkTextSegment *segPtr, *oldPtr; + int lineIndex, segSize; + char *p, *start, *end; + + if (charCount <= 0) { + TkTextIndexForwChars(srcPtr, -charCount, dstPtr); + return; + } + + *dstPtr = *srcPtr; + + /* + * Find offset within seg that contains byteIndex. + * Move backward specified number of chars. + */ + + lineIndex = -1; + + segSize = dstPtr->byteIndex; + for (segPtr = dstPtr->linePtr->segPtr; ; segPtr = segPtr->nextPtr) { + if (segSize <= segPtr->size) { + break; + } + segSize -= segPtr->size; + } + while (1) { + if (segPtr->typePtr == &tkTextCharType) { + start = segPtr->body.chars; + end = segPtr->body.chars + segSize; + for (p = end; ; p = Tcl_UtfPrev(p, start)) { + if (charCount == 0) { + dstPtr->byteIndex -= (end - p); + return; + } + if (p == start) { + break; + } + charCount--; + } + } else { + if (charCount <= segSize) { + dstPtr->byteIndex -= charCount; + return; + } + charCount -= segSize; + } + dstPtr->byteIndex -= segSize; + + /* + * Move back into previous segment. + */ + + oldPtr = segPtr; + segPtr = dstPtr->linePtr->segPtr; + if (segPtr != oldPtr) { + for ( ; segPtr->nextPtr != oldPtr; segPtr = segPtr->nextPtr) { + /* Empty body. */ + } + segSize = segPtr->size; + continue; + } + + /* + * Move back to previous line. + */ + + if (lineIndex < 0) { + lineIndex = TkBTreeLineIndex(dstPtr->linePtr); + } + if (lineIndex == 0) { + dstPtr->byteIndex = 0; + return; + } + lineIndex--; + dstPtr->linePtr = TkBTreeFindLine(dstPtr->tree, lineIndex); + + /* + * Compute the length of the line and add that to dstPtr->byteIndex. + */ + + oldPtr = dstPtr->linePtr->segPtr; + for (segPtr = oldPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { + dstPtr->byteIndex += segPtr->size; + oldPtr = segPtr; + } + segPtr = oldPtr; + segSize = segPtr->size; + } +} + +/* *---------------------------------------------------------------------- * * StartEnd -- @@ -762,15 +1108,15 @@ StartEnd(string, indexPtr) length = p-string; if ((*string == 'l') && (strncmp(string, "lineend", length) == 0) && (length >= 5)) { - indexPtr->charIndex = 0; + indexPtr->byteIndex = 0; for (segPtr = indexPtr->linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { - indexPtr->charIndex += segPtr->size; + indexPtr->byteIndex += segPtr->size; } - indexPtr->charIndex -= 1; + indexPtr->byteIndex -= sizeof(char); } else if ((*string == 'l') && (strncmp(string, "linestart", length) == 0) && (length >= 5)) { - indexPtr->charIndex = 0; + indexPtr->byteIndex = 0; } else if ((*string == 'w') && (strncmp(string, "wordend", length) == 0) && (length >= 5)) { int firstChar = 1; @@ -791,7 +1137,7 @@ StartEnd(string, indexPtr) firstChar = 0; } offset += 1; - indexPtr->charIndex += 1; + indexPtr->byteIndex += sizeof(char); if (offset >= segPtr->size) { segPtr = TkTextIndexToSeg(indexPtr, &offset); } @@ -820,10 +1166,10 @@ StartEnd(string, indexPtr) firstChar = 0; } offset -= 1; - indexPtr->charIndex -= 1; + indexPtr->byteIndex -= sizeof(char); if (offset < 0) { - if (indexPtr->charIndex < 0) { - indexPtr->charIndex = 0; + if (indexPtr->byteIndex < 0) { + indexPtr->byteIndex = 0; goto done; } segPtr = TkTextIndexToSeg(indexPtr, &offset); @@ -838,3 +1184,4 @@ StartEnd(string, indexPtr) done: return p; } + diff --git a/tk/generic/tkTextMark.c b/tk/generic/tkTextMark.c index 87f6079abab..c2e262a4c92 100644 --- a/tk/generic/tkTextMark.c +++ b/tk/generic/tkTextMark.c @@ -39,7 +39,7 @@ static void MarkCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, static int MarkLayoutProc _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, TkTextSegment *segPtr, int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, + int noCharsYet, TkWrapMode wrapMode, TkTextDispChunk *chunkPtr)); static int MarkFindNext _ANSI_ARGS_((Tcl_Interp *interp, TkText *textPtr, char *markName)); @@ -134,9 +134,9 @@ TkTextMarkCmd(textPtr, interp, argc, argv) markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); if (argc == 4) { if (markPtr->typePtr == &tkTextRightMarkType) { - interp->result = "right"; + Tcl_SetResult(interp, "right", TCL_STATIC); } else { - interp->result = "left"; + Tcl_SetResult(interp, "left", TCL_STATIC); } return TCL_OK; } @@ -319,10 +319,10 @@ TkTextMarkSegToIndex(textPtr, markPtr, indexPtr) indexPtr->tree = textPtr->tree; indexPtr->linePtr = markPtr->body.mark.linePtr; - indexPtr->charIndex = 0; + indexPtr->byteIndex = 0; for (segPtr = indexPtr->linePtr->segPtr; segPtr != markPtr; segPtr = segPtr->nextPtr) { - indexPtr->charIndex += segPtr->size; + indexPtr->byteIndex += segPtr->size; } } @@ -454,7 +454,7 @@ MarkLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars, * many characters. */ int noCharsYet; /* Non-zero means no characters have been * assigned to this line yet. */ - Tk_Uid wrapMode; /* Not used. */ + TkWrapMode wrapMode; /* Not used. */ register TkTextDispChunk *chunkPtr; /* Structure to fill in with information * about this chunk. The x field has already @@ -468,7 +468,7 @@ MarkLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars, chunkPtr->undisplayProc = InsertUndisplayProc; chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL; chunkPtr->bboxProc = (Tk_ChunkBboxProc *) NULL; - chunkPtr->numChars = 0; + chunkPtr->numBytes = 0; chunkPtr->minAscent = 0; chunkPtr->minDescent = 0; chunkPtr->minHeight = 0; @@ -669,7 +669,7 @@ MarkFindNext(interp, textPtr, string) return TCL_ERROR; } for (offset = 0, segPtr = index.linePtr->segPtr; - segPtr != NULL && offset < index.charIndex; + segPtr != NULL && offset < index.byteIndex; offset += segPtr->size, segPtr = segPtr->nextPtr) { /* Empty loop body */ ; } @@ -692,7 +692,7 @@ MarkFindNext(interp, textPtr, string) if (index.linePtr == (TkTextLine *) NULL) { return TCL_OK; } - index.charIndex = 0; + index.byteIndex = 0; segPtr = index.linePtr->segPtr; } } @@ -742,7 +742,7 @@ MarkFindPrev(interp, textPtr, string) return TCL_ERROR; } for (offset = 0, segPtr = index.linePtr->segPtr; - segPtr != NULL && offset < index.charIndex; + segPtr != NULL && offset < index.byteIndex; offset += segPtr->size, segPtr = segPtr->nextPtr) { /* Empty loop body */ ; } @@ -773,3 +773,4 @@ MarkFindPrev(interp, textPtr, string) segPtr = NULL; } } + diff --git a/tk/generic/tkTextTag.c b/tk/generic/tkTextTag.c index e3ae2451683..f623b93026e 100644 --- a/tk/generic/tkTextTag.c +++ b/tk/generic/tkTextTag.c @@ -6,7 +6,7 @@ * related to tags. * * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -16,13 +16,9 @@ #include "default.h" #include "tkPort.h" -#include "tk.h" +#include "tkInt.h" #include "tkText.h" -/* - * Information used for parsing tag configuration information: - */ - static Tk_ConfigSpec tagConfigSpecs[] = { {TK_CONFIG_BORDER, "-background", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TkTextTag, border), TK_CONFIG_NULL_OK}, @@ -30,7 +26,10 @@ static Tk_ConfigSpec tagConfigSpecs[] = { (char *) NULL, Tk_Offset(TkTextTag, bgStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-borderwidth", (char *) NULL, (char *) NULL, "0", Tk_Offset(TkTextTag, bdString), - TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK}, + TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK}, + {TK_CONFIG_STRING, "-elide", (char *) NULL, (char *) NULL, + "0", Tk_Offset(TkTextTag, elideString), + TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK}, {TK_CONFIG_BITMAP, "-fgstipple", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TkTextTag, fgStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL, @@ -63,9 +62,9 @@ static Tk_ConfigSpec tagConfigSpecs[] = { {TK_CONFIG_STRING, "-underline", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TkTextTag, underlineString), TK_CONFIG_NULL_OK}, - {TK_CONFIG_UID, "-wrap", (char *) NULL, (char *) NULL, + {TK_CONFIG_CUSTOM, "-wrap", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TkTextTag, wrapMode), - TK_CONFIG_NULL_OK}, + TK_CONFIG_NULL_OK, &textWrapModeOption}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; @@ -235,9 +234,22 @@ TkTextTagCmd(textPtr, interp, argc, argv) command = Tk_GetBinding(interp, textPtr->bindingTable, (ClientData) tagPtr, argv[4]); if (command == NULL) { - return TCL_ERROR; + char *string = Tcl_GetStringResult(interp); + + /* + * Ignore missing binding errors. This is a special hack + * that relies on the error message returned by FindSequence + * in tkBind.c. + */ + + if (string[0] != '\0') { + return TCL_ERROR; + } else { + Tcl_ResetResult(interp); + } + } else { + Tcl_SetResult(interp, command, TCL_STATIC); } - interp->result = command; } else { Tk_GetAllBindings(interp, textPtr->bindingTable, (ClientData) tagPtr); @@ -378,14 +390,11 @@ TkTextTagCmd(textPtr, interp, argc, argv) return TCL_ERROR; } } - if ((tagPtr->wrapMode != NULL) - && (tagPtr->wrapMode != tkTextCharUid) - && (tagPtr->wrapMode != tkTextNoneUid) - && (tagPtr->wrapMode != tkTextWordUid)) { - Tcl_AppendResult(interp, "bad wrap mode \"", tagPtr->wrapMode, - "\": must be char, none, or word", (char *) NULL); - tagPtr->wrapMode = NULL; - return TCL_ERROR; + if (tagPtr->elideString != NULL) { + if (Tcl_GetBoolean(interp, tagPtr->elideString, + &tagPtr->elide) != TCL_OK) { + return TCL_ERROR; + } } /* @@ -419,7 +428,8 @@ TkTextTagCmd(textPtr, interp, argc, argv) || (tagPtr->spacing3String != NULL) || (tagPtr->tabString != NULL) || (tagPtr->underlineString != NULL) - || (tagPtr->wrapMode != NULL)) { + || (tagPtr->elideString != NULL) + || (tagPtr->wrapMode != TEXT_WRAPMODE_NULL)) { tagPtr->affectsDisplay = 1; } TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, @@ -448,10 +458,10 @@ TkTextTagCmd(textPtr, interp, argc, argv) TkTextRedrawTag(textPtr, (TkTextIndex *) NULL, (TkTextIndex *) NULL, tagPtr, 1); } - TkBTreeTag(TkTextMakeIndex(textPtr->tree, 0, 0, &first), - TkTextMakeIndex(textPtr->tree, - TkBTreeNumLines(textPtr->tree), 0, &last), - tagPtr, 0); + TkTextMakeByteIndex(textPtr->tree, 0, 0, &first); + TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), + 0, &last), + TkBTreeTag(&first, &last, tagPtr, 0); Tcl_DeleteHashEntry(hPtr); if (textPtr->bindingTable != NULL) { Tk_DeleteAllBindings(textPtr->bindingTable, @@ -552,7 +562,7 @@ TkTextTagCmd(textPtr, interp, argc, argv) if (TkTextGetIndex(interp, textPtr, argv[4], &index1) != TCL_OK) { return TCL_ERROR; } - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), + TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &last); if (argc == 5) { index2 = last; @@ -582,7 +592,7 @@ TkTextTagCmd(textPtr, interp, argc, argv) * skip to the end of this tagged range. */ - for (segPtr = index1.linePtr->segPtr, offset = index1.charIndex; + for (segPtr = index1.linePtr->segPtr, offset = index1.byteIndex; offset >= 0; offset -= segPtr->size, segPtr = segPtr->nextPtr) { if ((offset == 0) && (segPtr->typePtr == &tkTextToggleOnType) @@ -631,7 +641,7 @@ TkTextTagCmd(textPtr, interp, argc, argv) return TCL_ERROR; } if (argc == 5) { - TkTextMakeIndex(textPtr->tree, 0, 0, &index2); + TkTextMakeByteIndex(textPtr->tree, 0, 0, &index2); } else if (TkTextGetIndex(interp, textPtr, argv[5], &index2) != TCL_OK) { return TCL_ERROR; @@ -651,7 +661,7 @@ TkTextTagCmd(textPtr, interp, argc, argv) } if (tSearch.segPtr->typePtr == &tkTextToggleOnType) { TkTextPrintIndex(&tSearch.curIndex, position1); - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), + TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &last); TkBTreeStartSearch(&tSearch.curIndex, &last, tagPtr, &tSearch); TkBTreeNextTag(&tSearch); @@ -711,8 +721,8 @@ TkTextTagCmd(textPtr, interp, argc, argv) if (tagPtr == NULL) { return TCL_OK; } - TkTextMakeIndex(textPtr->tree, 0, 0, &first); - TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), + TkTextMakeByteIndex(textPtr->tree, 0, 0, &first); + TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &last); TkBTreeStartSearch(&first, &last, tagPtr, &tSearch); if (TkBTreeCharTagged(&first, tagPtr)) { @@ -811,7 +821,9 @@ TkTextCreateTag(textPtr, tagName) tagPtr->tabArrayPtr = NULL; tagPtr->underlineString = NULL; tagPtr->underline = 0; - tagPtr->wrapMode = NULL; + tagPtr->elideString = NULL; + tagPtr->elide = 0; + tagPtr->wrapMode = TEXT_WRAPMODE_NULL; tagPtr->affectsDisplay = 0; textPtr->numTags++; Tcl_SetHashValue(hPtr, tagPtr); @@ -828,7 +840,7 @@ TkTextCreateTag(textPtr, tagName) * Results: * If tagName is defined in textPtr, a pointer to its TkTextTag * structure is returned. Otherwise NULL is returned and an - * error message is recorded in interp->result unless interp + * error message is recorded in the interp's result unless interp * is NULL. * * Side effects: @@ -1374,3 +1386,4 @@ TkTextPickCurrent(textPtr, eventPtr) ckfree((char *) copyArrayPtr); } } + diff --git a/tk/generic/tkTextWind.c b/tk/generic/tkTextWind.c index cc9f7ba0820..9624403cf2c 100644 --- a/tk/generic/tkTextWind.c +++ b/tk/generic/tkTextWind.c @@ -6,7 +6,7 @@ * widget command for texts. * * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -81,7 +81,7 @@ static void EmbWinDisplayProc _ANSI_ARGS_(( static int EmbWinLayoutProc _ANSI_ARGS_((TkText *textPtr, TkTextIndex *indexPtr, TkTextSegment *segPtr, int offset, int maxX, int maxChars, - int noCharsYet, Tk_Uid wrapMode, + int noCharsYet, TkWrapMode wrapMode, TkTextDispChunk *chunkPtr)); static void EmbWinStructureProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); @@ -244,7 +244,7 @@ TkTextWindowCmd(textPtr, interp, argc, argv) lineIndex = TkBTreeLineIndex(index.linePtr); if (lineIndex == TkBTreeNumLines(textPtr->tree)) { lineIndex--; - TkTextMakeIndex(textPtr->tree, lineIndex, 1000000, &index); + TkTextMakeByteIndex(textPtr->tree, lineIndex, 1000000, &index); } /* @@ -311,7 +311,7 @@ TkTextWindowCmd(textPtr, interp, argc, argv) * * Results: * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then interp->result contains an error message.. + * returned, then the interp's result contains an error message.. * * Side effects: * Configuration information for the embedded window changes, @@ -541,7 +541,7 @@ EmbWinStructureProc(clientData, eventPtr) ewPtr->body.ew.tkwin = NULL; index.tree = ewPtr->body.ew.textPtr->tree; index.linePtr = ewPtr->body.ew.linePtr; - index.charIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr); + index.byteIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr); TkTextChanged(ewPtr->body.ew.textPtr, &index, &index); } @@ -575,7 +575,7 @@ EmbWinRequestProc(clientData, tkwin) index.tree = ewPtr->body.ew.textPtr->tree; index.linePtr = ewPtr->body.ew.linePtr; - index.charIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr); + index.byteIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr); TkTextChanged(ewPtr->body.ew.textPtr, &index, &index); } @@ -620,7 +620,7 @@ EmbWinLostSlaveProc(clientData, tkwin) ewPtr->body.ew.tkwin = NULL; index.tree = ewPtr->body.ew.textPtr->tree; index.linePtr = ewPtr->body.ew.linePtr; - index.charIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr); + index.byteIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr); TkTextChanged(ewPtr->body.ew.textPtr, &index, &index); } @@ -744,8 +744,8 @@ EmbWinLayoutProc(textPtr, indexPtr, ewPtr, offset, maxX, maxChars, * many characters. */ int noCharsYet; /* Non-zero means no characters have been * assigned to this line yet. */ - Tk_Uid wrapMode; /* Wrap mode to use for line: tkTextCharUid, - * tkTextNoneUid, or tkTextWordUid. */ + TkWrapMode wrapMode; /* Wrap mode to use for line: TEXT_WRAPMODE_CHAR, + * TEXT_WRAPMODE_NONE, or TEXT_WRAPMODE_WORD. */ register TkTextDispChunk *chunkPtr; /* Structure to fill in with information * about this chunk. The x field has already @@ -778,7 +778,7 @@ EmbWinLayoutProc(textPtr, indexPtr, ewPtr, offset, maxX, maxChars, goto gotWindow; } Tcl_DStringInit(&name); - Tcl_DStringAppend(&name, textPtr->interp->result, -1); + Tcl_DStringAppend(&name, Tcl_GetStringResult(textPtr->interp), -1); Tcl_ResetResult(textPtr->interp); ewPtr->body.ew.tkwin = Tk_NameToWindow(textPtr->interp, Tcl_DStringValue(&name), textPtr->tkwin); @@ -835,7 +835,7 @@ EmbWinLayoutProc(textPtr, indexPtr, ewPtr, offset, maxX, maxChars, height = Tk_ReqHeight(ewPtr->body.ew.tkwin) + 2*ewPtr->body.ew.padY; } if ((width > (maxX - chunkPtr->x)) - && !noCharsYet && (textPtr->wrapMode != tkTextNoneUid)) { + && !noCharsYet && (textPtr->wrapMode != TEXT_WRAPMODE_NONE)) { return 0; } @@ -847,7 +847,7 @@ EmbWinLayoutProc(textPtr, indexPtr, ewPtr, offset, maxX, maxChars, chunkPtr->undisplayProc = EmbWinUndisplayProc; chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL; chunkPtr->bboxProc = EmbWinBboxProc; - chunkPtr->numChars = 1; + chunkPtr->numBytes = 1; if (ewPtr->body.ew.align == ALIGN_BASELINE) { chunkPtr->minAscent = height - ewPtr->body.ew.padY; chunkPtr->minDescent = ewPtr->body.ew.padY; @@ -1171,6 +1171,7 @@ TkTextWindowIndex(textPtr, name, indexPtr) ewPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); indexPtr->tree = textPtr->tree; indexPtr->linePtr = ewPtr->body.ew.linePtr; - indexPtr->charIndex = TkTextSegToOffset(ewPtr, indexPtr->linePtr); + indexPtr->byteIndex = TkTextSegToOffset(ewPtr, indexPtr->linePtr); return 1; } + diff --git a/tk/generic/tkTrig.c b/tk/generic/tkTrig.c index cf4b8b80c0b..b9f0628242a 100644 --- a/tk/generic/tkTrig.c +++ b/tk/generic/tkTrig.c @@ -7,7 +7,7 @@ * used by canvases. * * Copyright (c) 1992-1994 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -1066,6 +1066,14 @@ TkMakeBezierCurve(canvas, pointPtr, numPoints, numSteps, xPoints, dblPoints) * just put the first point into the output. */ + if (!pointPtr) { + /* Of pointPtr == NULL, this function returns an upper limit. + * of the array size to store the coordinates. This can be + * used to allocate storage, before the actual coordinates + * are calculated. */ + return 1 + numPoints * numSteps; + } + outputPoints = 0; if ((pointPtr[0] == pointPtr[numCoords-2]) && (pointPtr[1] == pointPtr[numCoords-1])) { @@ -1195,7 +1203,7 @@ TkMakeBezierCurve(canvas, pointPtr, numPoints, numSteps, xPoints, dblPoints) * * Results: * None. Postscript commands to generate the path are appended - * to interp->result. + * to the interp's result. * * Side effects: * None. @@ -1465,3 +1473,4 @@ TkGetButtPoints(p1, p2, width, project, m1, m2) } } } + diff --git a/tk/generic/tkUtil.c b/tk/generic/tkUtil.c index 407837438e6..cbb49e6d8bb 100644 --- a/tk/generic/tkUtil.c +++ b/tk/generic/tkUtil.c @@ -6,7 +6,7 @@ * a focus highlight. * * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -16,6 +16,501 @@ #include "tkInt.h" #include "tkPort.h" + +/* + * The structure below defines the implementation of the "statekey" + * Tcl object, used for quickly finding a mapping in a TkStateMap. + */ + +static Tcl_ObjType stateKeyType = { + "statekey", /* name */ + (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */ + (Tcl_DupInternalRepProc *) NULL, /* dupIntRepProc */ + (Tcl_UpdateStringProc *) NULL, /* updateStringProc */ + (Tcl_SetFromAnyProc *) NULL /* setFromAnyProc */ +}; + + +/* + *-------------------------------------------------------------- + * + * TkStateParseProc -- + * + * This procedure is invoked during option processing to handle + * the "-state" and "-default" options. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The state for a given item gets replaced by the state + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +int +TkStateParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + int c; + int flags = (int)clientData; + size_t length; + + register Tk_State *statePtr = (Tk_State *) (widgRec + offset); + + if(value == NULL || *value == 0) { + *statePtr = TK_STATE_NULL; + return TCL_OK; + } + + c = value[0]; + length = strlen(value); + + if ((c == 'n') && (strncmp(value, "normal", length) == 0)) { + *statePtr = TK_STATE_NORMAL; + return TCL_OK; + } + if ((c == 'd') && (strncmp(value, "disabled", length) == 0)) { + *statePtr = TK_STATE_DISABLED; + return TCL_OK; + } + if ((c == 'a') && (flags&1) && (strncmp(value, "active", length) == 0)) { + *statePtr = TK_STATE_ACTIVE; + return TCL_OK; + } + if ((c == 'h') && (flags&2) && (strncmp(value, "hidden", length) == 0)) { + *statePtr = TK_STATE_HIDDEN; + return TCL_OK; + } + + Tcl_AppendResult(interp, "bad ", (flags&4)?"-default" : "state", + " value \"", value, "\": must be normal", + (char *) NULL); + if (flags&1) { + Tcl_AppendResult(interp, ", active",(char *) NULL); + } + if (flags&2) { + Tcl_AppendResult(interp, ", hidden",(char *) NULL); + } + if (flags&3) { + Tcl_AppendResult(interp, ",",(char *) NULL); + } + Tcl_AppendResult(interp, " or disabled",(char *) NULL); + *statePtr = TK_STATE_NORMAL; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * TkStatePrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-state" + * configuration option. + * + * Results: + * The return value is a string describing the state for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +char * +TkStatePrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register Tk_State *statePtr = (Tk_State *) (widgRec + offset); + + if (*statePtr==TK_STATE_NORMAL) { + return "normal"; + } else if (*statePtr==TK_STATE_DISABLED) { + return "disabled"; + } else if (*statePtr==TK_STATE_HIDDEN) { + return "hidden"; + } else if (*statePtr==TK_STATE_ACTIVE) { + return "active"; + } else { + return ""; + } +} + +/* + *-------------------------------------------------------------- + * + * TkOrientParseProc -- + * + * This procedure is invoked during option processing to handle + * the "-orient" option. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The orientation for a given item gets replaced by the orientation + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +int +TkOrientParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* some flags.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + CONST char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + int c; + size_t length; + + register int *orientPtr = (int *) (widgRec + offset); + + if(value == NULL || *value == 0) { + *orientPtr = 0; + return TCL_OK; + } + + c = value[0]; + length = strlen(value); + + if ((c == 'h') && (strncmp(value, "horizontal", length) == 0)) { + *orientPtr = 0; + return TCL_OK; + } + if ((c == 'v') && (strncmp(value, "vertical", length) == 0)) { + *orientPtr = 1; + return TCL_OK; + } + Tcl_AppendResult(interp, "bad orientation \"", value, + "\": must be vertical or horizontal", + (char *) NULL); + *orientPtr = 0; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * TkOrientPrintProc -- + * + * This procedure is invoked by the Tk configuration code + * to produce a printable string for the "-orient" + * configuration option. + * + * Results: + * The return value is a string describing the orientation for + * the item referred to by "widgRec". In addition, *freeProcPtr + * is filled in with the address of a procedure to call to free + * the result string when it's no longer needed (or NULL to + * indicate that the string doesn't need to be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +char * +TkOrientPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register int *statePtr = (int *) (widgRec + offset); + + if (*statePtr) { + return "vertical"; + } else { + return "horizontal"; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkOffsetParseProc -- + * + * Converts the offset of a stipple or tile into the Tk_TSOffset structure. + * + *---------------------------------------------------------------------- + */ + +int +TkOffsetParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* not used */ + Tcl_Interp *interp; /* Interpreter to send results back to */ + Tk_Window tkwin; /* Window on same display as tile */ + CONST char *value; /* Name of image */ + char *widgRec; /* Widget structure record */ + int offset; /* Offset of tile in record */ +{ + Tk_TSOffset *offsetPtr = (Tk_TSOffset *)(widgRec + offset); + Tk_TSOffset tsoffset; + CONST char *q, *p; + int result; + + if ((value == NULL) || (*value == 0)) { + tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_MIDDLE; + goto goodTSOffset; + } + tsoffset.flags = 0; + p = value; + + switch(value[0]) { + case '#': + if (((int)clientData) & TK_OFFSET_RELATIVE) { + tsoffset.flags = TK_OFFSET_RELATIVE; + p++; break; + } + goto badTSOffset; + case 'e': + switch(value[1]) { + case '\0': + tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_MIDDLE; + goto goodTSOffset; + case 'n': + if (value[2]!='d' || value[3]!='\0') {goto badTSOffset;} + tsoffset.flags = INT_MAX; + goto goodTSOffset; + } + case 'w': + if (value[1] != '\0') {goto badTSOffset;} + tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_MIDDLE; + goto goodTSOffset; + case 'n': + if ((value[1] != '\0') && (value[2] != '\0')) { + goto badTSOffset; + } + switch(value[1]) { + case '\0': tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_TOP; + goto goodTSOffset; + case 'w': tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_TOP; + goto goodTSOffset; + case 'e': tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_TOP; + goto goodTSOffset; + } + goto badTSOffset; + case 's': + if ((value[1] != '\0') && (value[2] != '\0')) { + goto badTSOffset; + } + switch(value[1]) { + case '\0': tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_BOTTOM; + goto goodTSOffset; + case 'w': tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_BOTTOM; + goto goodTSOffset; + case 'e': tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_BOTTOM; + goto goodTSOffset; + } + goto badTSOffset; + case 'c': + if (strncmp(value, "center", strlen(value)) != 0) { + goto badTSOffset; + } + tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_MIDDLE; + goto goodTSOffset; + } + if ((q = strchr(p,',')) == NULL) { + if (((int)clientData) & TK_OFFSET_INDEX) { + if (Tcl_GetInt(interp, (char *) p, &tsoffset.flags) != TCL_OK) { + Tcl_ResetResult(interp); + goto badTSOffset; + } + tsoffset.flags |= TK_OFFSET_INDEX; + goto goodTSOffset; + } + goto badTSOffset; + } + *((char *) q) = 0; + result = Tk_GetPixels(interp, tkwin, (char *) p, &tsoffset.xoffset); + *((char *) q) = ','; + if (result != TCL_OK) { + return TCL_ERROR; + } + if (Tk_GetPixels(interp, tkwin, (char *) q+1, &tsoffset.yoffset) != TCL_OK) { + return TCL_ERROR; + } + + +goodTSOffset: + /* below is a hack to allow the stipple/tile offset to be stored + * in the internal tile structure. Most of the times, offsetPtr + * is a pointer to an already existing tile structure. However + * if this structure is not already created, we must do it + * with Tk_GetTile()!!!!; + */ + + memcpy(offsetPtr,&tsoffset, sizeof(Tk_TSOffset)); + return TCL_OK; + +badTSOffset: + Tcl_AppendResult(interp, "bad offset \"", value, + "\": expected \"x,y\"", (char *) NULL); + if (((int) clientData) & TK_OFFSET_RELATIVE) { + Tcl_AppendResult(interp, ", \"#x,y\"", (char *) NULL); + } + if (((int) clientData) & TK_OFFSET_INDEX) { + Tcl_AppendResult(interp, ", <index>", (char *) NULL); + } + Tcl_AppendResult(interp, ", n, ne, e, se, s, sw, w, nw, or center", + (char *) NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * TkOffsetPrintProc -- + * + * Returns the offset of the tile. + * + * Results: + * The offset of the tile is returned. + * + *---------------------------------------------------------------------- + */ + +char * +TkOffsetPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* not used */ + Tk_Window tkwin; /* not used */ + char *widgRec; /* Widget structure record */ + int offset; /* Offset of tile in record */ + Tcl_FreeProc **freeProcPtr; /* not used */ +{ + Tk_TSOffset *offsetPtr = (Tk_TSOffset *)(widgRec + offset); + char *p, *q; + + if ((offsetPtr->flags) & TK_OFFSET_INDEX) { + if ((offsetPtr->flags) >= INT_MAX) { + return "end"; + } + p = (char *) ckalloc(32); + sprintf(p, "%d",(offsetPtr->flags & (~TK_OFFSET_INDEX))); + *freeProcPtr = TCL_DYNAMIC; + return p; + } + if ((offsetPtr->flags) & TK_OFFSET_TOP) { + if ((offsetPtr->flags) & TK_OFFSET_LEFT) { + return "nw"; + } else if ((offsetPtr->flags) & TK_OFFSET_CENTER) { + return "n"; + } else if ((offsetPtr->flags) & TK_OFFSET_RIGHT) { + return "ne"; + } + } else if ((offsetPtr->flags) & TK_OFFSET_MIDDLE) { + if ((offsetPtr->flags) & TK_OFFSET_LEFT) { + return "w"; + } else if ((offsetPtr->flags) & TK_OFFSET_CENTER) { + return "center"; + } else if ((offsetPtr->flags) & TK_OFFSET_RIGHT) { + return "e"; + } + } else if ((offsetPtr->flags) & TK_OFFSET_BOTTOM) { + if ((offsetPtr->flags) & TK_OFFSET_LEFT) { + return "sw"; + } else if ((offsetPtr->flags) & TK_OFFSET_CENTER) { + return "s"; + } else if ((offsetPtr->flags) & TK_OFFSET_RIGHT) { + return "se"; + } + } + q = p = (char *) ckalloc(32); + if ((offsetPtr->flags) & TK_OFFSET_RELATIVE) { + *q++ = '#'; + } + sprintf(q, "%d,%d",offsetPtr->xoffset, offsetPtr->yoffset); + *freeProcPtr = TCL_DYNAMIC; + return p; +} + + +/* + *---------------------------------------------------------------------- + * + * TkPixelParseProc -- + * + * Converts the name of an image into a tile. + * + *---------------------------------------------------------------------- + */ + +int +TkPixelParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* if non-NULL, negative values are + * allowed as well */ + Tcl_Interp *interp; /* Interpreter to send results back to */ + Tk_Window tkwin; /* Window on same display as tile */ + CONST char *value; /* Name of image */ + char *widgRec; /* Widget structure record */ + int offset; /* Offset of tile in record */ +{ + double *doublePtr = (double *)(widgRec + offset); + int result; + + result = TkGetDoublePixels(interp, tkwin, value, doublePtr); + + if ((result == TCL_OK) && (clientData == NULL) && (*doublePtr < 0.0)) { + Tcl_AppendResult(interp, "bad screen distance \"", value, + "\"", (char *) NULL); + return TCL_ERROR; + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TkPixelPrintProc -- + * + * Returns the name of the tile. + * + * Results: + * The name of the tile is returned. + * + *---------------------------------------------------------------------- + */ + +char * +TkPixelPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* not used */ + Tk_Window tkwin; /* not used */ + char *widgRec; /* Widget structure record */ + int offset; /* Offset of tile in record */ + Tcl_FreeProc **freeProcPtr; /* not used */ +{ + double *doublePtr = (double *)(widgRec + offset); + char *p; + + p = (char *) ckalloc(24); + Tcl_PrintDouble((Tcl_Interp *) NULL, *doublePtr, p); + *freeProcPtr = TCL_DYNAMIC; + return p; +} /* *---------------------------------------------------------------------- @@ -50,22 +545,6 @@ TkDrawInsetFocusHighlight(tkwin, gc, width, drawable, padding) { XRectangle rects[4]; - /* - * On the Macintosh the highlight ring needs to be "padded" - * out by one pixel. Unfortunantly, none of the Tk widgets - * had a notion of padding between the focus ring and the - * widget. So we add this padding here. This introduces - * two things to worry about: - * - * 1) The widget must draw the background color covering - * the focus ring area before calling Tk_DrawFocus. - * 2) It is impossible to draw a focus ring of width 1. - * (For the Macintosh Look & Feel use width of 3) - */ -#ifdef MAC_TCL - width--; -#endif - rects[0].x = padding; rects[0].y = padding; rects[0].width = Tk_Width(tkwin) - (2 * padding); @@ -93,6 +572,12 @@ TkDrawInsetFocusHighlight(tkwin, gc, width, drawable, padding) * This procedure draws a rectangular ring around the outside of * a widget to indicate that it has received the input focus. * + * This function is now deprecated. Use TkpDrawHighlightBorder instead, + * since this function does not handle drawing the Focus ring properly + * on the Macintosh - you need to know the background GC as well + * as the foreground since the Mac focus ring separated from the widget + * by a 1 pixel border. + * * Results: * None. * @@ -132,7 +617,7 @@ Tk_DrawFocusHighlight(tkwin, gc, width, drawable) * took. If TK_SCROLL_MOVETO, *dblPtr is filled in with the * desired position; if TK_SCROLL_PAGES or TK_SCROLL_UNITS, * *intPtr is filled in with the number of lines to move (may be - * negative); if TK_SCROLL_ERROR, interp->result contains an + * negative); if TK_SCROLL_ERROR, the interp's result contains an * error message. * * Side effects: @@ -197,6 +682,85 @@ Tk_GetScrollInfo(interp, argc, argv, dblPtr, intPtr) } /* + *---------------------------------------------------------------------- + * + * Tk_GetScrollInfoObj -- + * + * This procedure is invoked to parse "xview" and "yview" + * scrolling commands for widgets using the new scrolling + * command syntax ("moveto" or "scroll" options). + * + * Results: + * The return value is either TK_SCROLL_MOVETO, TK_SCROLL_PAGES, + * TK_SCROLL_UNITS, or TK_SCROLL_ERROR. This indicates whether + * the command was successfully parsed and what form the command + * took. If TK_SCROLL_MOVETO, *dblPtr is filled in with the + * desired position; if TK_SCROLL_PAGES or TK_SCROLL_UNITS, + * *intPtr is filled in with the number of lines to move (may be + * negative); if TK_SCROLL_ERROR, the interp's result contains an + * error message. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Tk_GetScrollInfoObj(interp, objc, objv, dblPtr, intPtr) + Tcl_Interp *interp; /* Used for error reporting. */ + int objc; /* # arguments for command. */ + Tcl_Obj *CONST objv[]; /* Arguments for command. */ + double *dblPtr; /* Filled in with argument "moveto" + * option, if any. */ + int *intPtr; /* Filled in with number of pages + * or lines to scroll, if any. */ +{ + int c; + size_t length; + char *arg2, *arg4; + + arg2 = Tcl_GetString(objv[2]); + length = strlen(arg2); + c = arg2[0]; + if ((c == 'm') && (strncmp(arg2, "moveto", length) == 0)) { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "moveto fraction"); + return TK_SCROLL_ERROR; + } + if (Tcl_GetDoubleFromObj(interp, objv[3], dblPtr) != TCL_OK) { + return TK_SCROLL_ERROR; + } + return TK_SCROLL_MOVETO; + } else if ((c == 's') + && (strncmp(arg2, "scroll", length) == 0)) { + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "scroll number units|pages"); + return TK_SCROLL_ERROR; + } + if (Tcl_GetIntFromObj(interp, objv[3], intPtr) != TCL_OK) { + return TK_SCROLL_ERROR; + } + arg4 = Tcl_GetString(objv[4]); + length = (strlen(arg4)); + c = arg4[0]; + if ((c == 'p') && (strncmp(arg4, "pages", length) == 0)) { + return TK_SCROLL_PAGES; + } else if ((c == 'u') + && (strncmp(arg4, "units", length) == 0)) { + return TK_SCROLL_UNITS; + } else { + Tcl_AppendResult(interp, "bad argument \"", arg4, + "\": must be units or pages", (char *) NULL); + return TK_SCROLL_ERROR; + } + } + Tcl_AppendResult(interp, "unknown option \"", arg2, + "\": must be moveto or scroll", (char *) NULL); + return TK_SCROLL_ERROR; +} + +/* *--------------------------------------------------------------------------- * * TkComputeAnchor -- @@ -310,7 +874,7 @@ TkFindStateString(mapPtr, numKey) * Returns the numKey associated with the last element (the NULL * string one) in the table if strKey was not equal to any of the * string keys in the table. In that case, an error message is - * also left in interp->result (if interp is not NULL). + * also left in the interp's result (if interp is not NULL). * * Side effects. * None. @@ -319,30 +883,73 @@ TkFindStateString(mapPtr, numKey) */ int -TkFindStateNum(interp, field, mapPtr, strKey) +TkFindStateNum(interp, option, mapPtr, strKey) Tcl_Interp *interp; /* Interp for error reporting. */ - CONST char *field; /* String to use when constructing error. */ + CONST char *option; /* String to use when constructing error. */ CONST TkStateMap *mapPtr; /* Lookup table. */ CONST char *strKey; /* String to try to find in lookup table. */ { CONST TkStateMap *mPtr; - if (mapPtr->strKey == NULL) { - panic("TkFindStateNum: no choices in lookup table"); + for (mPtr = mapPtr; mPtr->strKey != NULL; mPtr++) { + if (strcmp(strKey, mPtr->strKey) == 0) { + return mPtr->numKey; + } } + if (interp != NULL) { + mPtr = mapPtr; + Tcl_AppendResult(interp, "bad ", option, " value \"", strKey, + "\": must be ", mPtr->strKey, (char *) NULL); + for (mPtr++; mPtr->strKey != NULL; mPtr++) { + Tcl_AppendResult(interp, + ((mPtr[1].strKey != NULL) ? ", " : ", or "), + mPtr->strKey, (char *) NULL); + } + } + return mPtr->numKey; +} +int +TkFindStateNumObj(interp, optionPtr, mapPtr, keyPtr) + Tcl_Interp *interp; /* Interp for error reporting. */ + Tcl_Obj *optionPtr; /* String to use when constructing error. */ + CONST TkStateMap *mapPtr; /* Lookup table. */ + Tcl_Obj *keyPtr; /* String key to find in lookup table. */ +{ + CONST TkStateMap *mPtr; + CONST char *key; + CONST Tcl_ObjType *typePtr; + + if ((keyPtr->typePtr == &stateKeyType) + && (keyPtr->internalRep.twoPtrValue.ptr1 == (VOID *) mapPtr)) { + return (int) keyPtr->internalRep.twoPtrValue.ptr2; + } + + key = Tcl_GetStringFromObj(keyPtr, NULL); for (mPtr = mapPtr; mPtr->strKey != NULL; mPtr++) { - if (strcmp(strKey, mPtr->strKey) == 0) { + if (strcmp(key, mPtr->strKey) == 0) { + typePtr = keyPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(keyPtr); + } + keyPtr->internalRep.twoPtrValue.ptr1 = (VOID *) mapPtr; + keyPtr->internalRep.twoPtrValue.ptr2 = (VOID *) mPtr->numKey; + keyPtr->typePtr = &stateKeyType; return mPtr->numKey; } } if (interp != NULL) { mPtr = mapPtr; - Tcl_AppendResult(interp, "bad ", field, " value \"", strKey, + Tcl_AppendResult(interp, "bad ", + Tcl_GetStringFromObj(optionPtr, NULL), " value \"", key, "\": must be ", mPtr->strKey, (char *) NULL); for (mPtr++; mPtr->strKey != NULL; mPtr++) { - Tcl_AppendResult(interp, ", ", mPtr->strKey, (char *) NULL); + Tcl_AppendResult(interp, + ((mPtr[1].strKey != NULL) ? ", " : ", or "), + mPtr->strKey, (char *) NULL); } } return mPtr->numKey; } + + diff --git a/tk/generic/tkVisual.c b/tk/generic/tkVisual.c index 4b9457814a2..a2d717a119d 100644 --- a/tk/generic/tkVisual.c +++ b/tk/generic/tkVisual.c @@ -6,7 +6,7 @@ * prototype implementation by Paul Mackerras. * * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -74,7 +74,7 @@ struct TkColormap { * Results: * The return value is normally a pointer to a visual. If an * error occurred in looking up the visual, NULL is returned and - * an error message is left in interp->result. The depth of the + * an error message is left in the interp's result. The depth of the * visual is returned to *depthPtr under normal returns. If * colormapPtr is non-NULL, then this procedure also finds a * suitable colormap for use with the visual in tkwin, and it @@ -243,7 +243,8 @@ Tk_GetVisual(interp, tkwin, string, depthPtr, colormapPtr) visInfoList = XGetVisualInfo(Tk_Display(tkwin), mask, &template, &numVisuals); if (visInfoList == NULL) { - interp->result = "couldn't find an appropriate visual"; + Tcl_SetResult(interp, "couldn't find an appropriate visual", + TCL_STATIC); return NULL; } @@ -352,7 +353,7 @@ Tk_GetVisual(interp, tkwin, string, depthPtr, colormapPtr) * Results: * The return value is normally the X resource identifier for the * colormap. If an error occurs, None is returned and an error - * message is placed in interp->result. + * message is placed in the interp's result. * * Side effects: * A reference count is incremented for the colormap, so @@ -538,3 +539,4 @@ Tk_PreserveColormap(display, colormap) } } } + diff --git a/tk/generic/tkWindow.c b/tk/generic/tkWindow.c index 2da31fd6e2d..5f3a8a0c517 100644 --- a/tk/generic/tkWindow.c +++ b/tk/generic/tkWindow.c @@ -18,38 +18,30 @@ #include "tkPort.h" #include "tkInt.h" -/* - * Count of number of main windows currently open in this process. - */ - -static int numMainWindows; - -/* - * First in list of all main windows managed by this process. - */ - -TkMainInfo *tkMainWindowList = NULL; - -/* - * List of all displays currently in use. - */ - -TkDisplay *tkDisplayList = NULL; +#if !defined(__WIN32__) && !defined(MAC_TCL) +#include "tkUnixInt.h" +#endif -/* - * Have statics in this module been initialized? - */ -static int initialized = 0; +typedef struct ThreadSpecificData { + int numMainWindows; /* Count of numver of main windows currently + * open in this thread. */ + TkMainInfo *mainWindowList; + /* First in list of all main windows managed + * by this thread. */ + TkDisplay *displayList; + /* List of all displays currently in use by + * the current thread. */ + int initialized; /* 0 means the structures above need + * initializing. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; -/* - * The variables below hold several uid's that are used in many places - * in the toolkit. +/* + * The Mutex below is used to lock access to the Tk_Uid structs above. */ -Tk_Uid tkDisabledUid = NULL; -Tk_Uid tkActiveUid = NULL; -Tk_Uid tkNormalUid = NULL; +TCL_DECLARE_MUTEX(windowMutex) /* * Default values for "changes" and "atts" fields of TkWindows. Note @@ -94,6 +86,10 @@ typedef struct { int isSafe; /* If !0, this command will be exposed in * a safe interpreter. Otherwise it will be * hidden in a safe interpreter. */ + int passMainWindow; /* 0 means provide NULL clientData to + * command procedure; 1 means pass main + * window as clientData to command + * procedure. */ } TkCmd; static TkCmd commands[] = { @@ -101,62 +97,67 @@ static TkCmd commands[] = { * Commands that are part of the intrinsics: */ - {"bell", NULL, Tk_BellObjCmd, 0}, - {"bind", Tk_BindCmd, NULL, 1}, - {"bindtags", Tk_BindtagsCmd, NULL, 1}, - {"clipboard", Tk_ClipboardCmd, NULL, 0}, - {"destroy", Tk_DestroyCmd, NULL, 1}, - {"event", Tk_EventCmd, NULL, 1}, - {"focus", Tk_FocusCmd, NULL, 1}, - {"font", NULL, Tk_FontObjCmd, 1}, - {"grab", Tk_GrabCmd, NULL, 0}, - {"grid", Tk_GridCmd, NULL, 1}, - {"image", NULL, Tk_ImageCmd, 1}, - {"lower", Tk_LowerCmd, NULL, 1}, - {"option", Tk_OptionCmd, NULL, 1}, - {"pack", Tk_PackCmd, NULL, 1}, - {"place", Tk_PlaceCmd, NULL, 1}, - {"raise", Tk_RaiseCmd, NULL, 1}, - {"selection", Tk_SelectionCmd, NULL, 0}, - {"tk", NULL, Tk_TkObjCmd, 0}, - {"tkwait", Tk_TkwaitCmd, NULL, 1}, - {"tk_chooseColor", Tk_ChooseColorCmd, NULL, 0}, - {"tk_getOpenFile", Tk_GetOpenFileCmd, NULL, 0}, - {"tk_getSaveFile", Tk_GetSaveFileCmd, NULL, 0}, - {"tk_messageBox", Tk_MessageBoxCmd, NULL, 0}, - {"update", Tk_UpdateCmd, NULL, 1}, - {"winfo", NULL, Tk_WinfoObjCmd, 1}, - {"wm", Tk_WmCmd, NULL, 0}, + {"bell", NULL, Tk_BellObjCmd, 0, 1}, + {"bind", Tk_BindCmd, NULL, 1, 1}, + {"bindtags", Tk_BindtagsCmd, NULL, 1, 1}, + {"clipboard", Tk_ClipboardCmd, NULL, 0, 1}, + {"destroy", NULL, Tk_DestroyObjCmd, 1, 1}, + {"event", NULL, Tk_EventObjCmd, 1, 1}, + {"focus", NULL, Tk_FocusObjCmd, 1, 1}, + {"font", NULL, Tk_FontObjCmd, 1, 1}, + {"grab", Tk_GrabCmd, NULL, 0, 1}, + {"grid", Tk_GridCmd, NULL, 1, 1}, + {"image", NULL, Tk_ImageObjCmd, 1, 1}, + {"lower", NULL, Tk_LowerObjCmd, 1, 1}, + {"option", NULL, Tk_OptionObjCmd, 1, 1}, + {"pack", Tk_PackCmd, NULL, 1, 1}, + {"place", Tk_PlaceCmd, NULL, 1, 1}, + {"raise", NULL, Tk_RaiseObjCmd, 1, 1}, + {"selection", Tk_SelectionCmd, NULL, 0, 1}, + {"tk", NULL, Tk_TkObjCmd, 0, 1}, + {"tkwait", Tk_TkwaitCmd, NULL, 1, 1}, +#if defined(__WIN32__) || defined(MAC_TCL) + {"tk_chooseColor", NULL, Tk_ChooseColorObjCmd, 0, 1}, + {"tk_chooseDirectory", NULL, Tk_ChooseDirectoryObjCmd, 0, 1}, + {"tk_getOpenFile", NULL, Tk_GetOpenFileObjCmd, 0, 1}, + {"tk_getSaveFile", NULL, Tk_GetSaveFileObjCmd, 0, 1}, +#endif +#ifdef __WIN32__ + {"tk_messageBox", NULL, Tk_MessageBoxObjCmd, 0, 1}, +#endif + {"update", NULL, Tk_UpdateObjCmd, 1, 1}, + {"winfo", NULL, Tk_WinfoObjCmd, 1, 1}, + {"wm", Tk_WmCmd, NULL, 0, 1}, /* * Widget class commands. */ - {"button", Tk_ButtonCmd, NULL, 1}, - {"canvas", Tk_CanvasCmd, NULL, 1}, - {"checkbutton", Tk_CheckbuttonCmd, NULL, 1}, - {"entry", Tk_EntryCmd, NULL, 1}, - {"frame", Tk_FrameCmd, NULL, 1}, - {"label", Tk_LabelCmd, NULL, 1}, - {"listbox", Tk_ListboxCmd, NULL, 1}, - {"menu", Tk_MenuCmd, NULL, 0}, - {"menubutton", Tk_MenubuttonCmd, NULL, 1}, - {"message", Tk_MessageCmd, NULL, 1}, - {"radiobutton", Tk_RadiobuttonCmd, NULL, 1}, - {"scale", Tk_ScaleCmd, NULL, 1}, - {"scrollbar", Tk_ScrollbarCmd, NULL, 1}, - {"text", Tk_TextCmd, NULL, 1}, - {"toplevel", Tk_ToplevelCmd, NULL, 0}, + + {"button", NULL, Tk_ButtonObjCmd, 1, 0}, + {"canvas", NULL, Tk_CanvasObjCmd, 1, 1}, + {"checkbutton", NULL, Tk_CheckbuttonObjCmd, 1, 0}, + {"entry", NULL, Tk_EntryObjCmd, 1, 0}, + {"frame", NULL, Tk_FrameObjCmd, 1, 1}, + {"label", NULL, Tk_LabelObjCmd, 1, 0}, + {"listbox", NULL, Tk_ListboxObjCmd, 1, 0}, + {"menubutton", NULL, Tk_MenubuttonObjCmd, 1, 0}, + {"message", Tk_MessageCmd, NULL, 1, 1}, + {"radiobutton", NULL, Tk_RadiobuttonObjCmd, 1, 0}, + {"scale", NULL, Tk_ScaleObjCmd, 1, 0}, + {"scrollbar", Tk_ScrollbarCmd, NULL, 1, 1}, + {"text", Tk_TextCmd, NULL, 1, 1}, + {"toplevel", NULL, Tk_ToplevelObjCmd, 0, 1}, /* * Misc. */ #ifdef MAC_TCL - {"unsupported1", TkUnsupported1Cmd, NULL, 1}, + {"unsupported1", TkUnsupported1Cmd, NULL, 1, 1}, #endif {(char *) NULL, (int (*) _ANSI_ARGS_((ClientData, Tcl_Interp *, int, char **))) NULL, NULL, 0} }; - + /* * The variables and table below are used to parse arguments from * the "argv" variable in Tk_Init. @@ -221,7 +222,7 @@ static void UnlinkWindow _ANSI_ARGS_((TkWindow *winPtr)); * The return value is a token for the new window, or NULL if * an error prevented the new window from being created. If * NULL is returned, an error message will be left in - * interp->result. + * the interp's result. * * Side effects: * A new window structure is allocated locally. An X @@ -249,12 +250,11 @@ CreateTopLevelWindow(interp, parent, name, screenName) register TkWindow *winPtr; register TkDisplay *dispPtr; int screenId; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - if (!initialized) { - initialized = 1; - tkActiveUid = Tk_GetUid("active"); - tkDisabledUid = Tk_GetUid("disabled"); - tkNormalUid = Tk_GetUid("normal"); + if (!tsdPtr->initialized) { + tsdPtr->initialized = 1; /* * Create built-in image types. @@ -268,7 +268,7 @@ CreateTopLevelWindow(interp, parent, name, screenName) */ Tk_CreatePhotoImageFormat(&tkImgFmtGIF); - Tk_CreatePhotoImageFormat(&tkImgFmtPPM); + Tk_CreateOldPhotoImageFormat(&tkImgFmtPPM); /* * Create exit handler to delete all windows when the application @@ -331,7 +331,7 @@ CreateTopLevelWindow(interp, parent, name, screenName) * Results: * The return value is a pointer to information about the display, * or NULL if the display couldn't be opened. In this case, an - * error message is left in interp->result. The location at + * error message is left in the interp's result. The location at * *screenPtr is overwritten with the screen number parsed from * screenName. * @@ -354,6 +354,8 @@ GetScreen(interp, screenName, screenPtr) char *p; int screenId; size_t length; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * Separate the screen number from the rest of the display @@ -364,8 +366,9 @@ GetScreen(interp, screenName, screenPtr) screenName = TkGetDefaultScreenName(interp, screenName); if (screenName == NULL) { - interp->result = - "no display name and no $DISPLAY environment variable"; + Tcl_SetResult(interp, + "no display name and no $DISPLAY environment variable", + TCL_STATIC); return (TkDisplay *) NULL; } length = strlen(screenName); @@ -384,7 +387,7 @@ GetScreen(interp, screenName, screenPtr) * then open a new connection. */ - for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) { + for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) { if (dispPtr == NULL) { dispPtr = TkpOpenDisplay(screenName); if (dispPtr == NULL) { @@ -392,29 +395,35 @@ GetScreen(interp, screenName, screenPtr) screenName, "\"", (char *) NULL); return (TkDisplay *) NULL; } - dispPtr->nextPtr = tkDisplayList; + dispPtr->nextPtr = TkGetDisplayList(); dispPtr->name = (char *) ckalloc((unsigned) (length+1)); dispPtr->lastEventTime = CurrentTime; - strncpy(dispPtr->name, screenName, length); - dispPtr->name[length] = '\0'; + dispPtr->borderInit = 0; + dispPtr->atomInit = 0; dispPtr->bindInfoStale = 1; dispPtr->modeModMask = 0; dispPtr->metaModMask = 0; dispPtr->altModMask = 0; dispPtr->numModKeyCodes = 0; dispPtr->modKeyCodes = NULL; - OpenIM(dispPtr); + dispPtr->bitmapInit = 0; + dispPtr->bitmapAutoNumber = 0; + dispPtr->numIdSearches = 0; + dispPtr->numSlowSearches = 0; + dispPtr->colorInit = 0; + dispPtr->stressPtr = NULL; + dispPtr->cursorInit = 0; + dispPtr->cursorString[0] = '\0'; + dispPtr->cursorFont = None; dispPtr->errorPtr = NULL; dispPtr->deleteCount = 0; - dispPtr->commTkwin = NULL; - dispPtr->selectionInfoPtr = NULL; - dispPtr->multipleAtom = None; - dispPtr->clipWindow = NULL; - dispPtr->clipboardActive = 0; - dispPtr->clipboardAppPtr = NULL; - dispPtr->clipTargetPtr = NULL; - dispPtr->atomInit = 0; - dispPtr->cursorFont = None; + dispPtr->delayedMotionPtr = NULL; + dispPtr->focusDebug = 0; + dispPtr->implicitWinPtr = NULL; + dispPtr->focusPtr = NULL; + dispPtr->gcInit = 0; + dispPtr->geomInit = 0; + dispPtr->uidInit = 0; dispPtr->grabWinPtr = NULL; dispPtr->eventualGrabWinPtr = NULL; dispPtr->buttonWinPtr = NULL; @@ -422,18 +431,38 @@ GetScreen(interp, screenName, screenPtr) dispPtr->firstGrabEventPtr = NULL; dispPtr->lastGrabEventPtr = NULL; dispPtr->grabFlags = 0; - TkInitXId(dispPtr); + dispPtr->mouseButtonState = 0; + dispPtr->warpInProgress = 0; + dispPtr->warpWindow = None; + dispPtr->warpX = 0; + dispPtr->warpY = 0; + dispPtr->gridInit = 0; + dispPtr->imageId = 0; + dispPtr->packInit = 0; + dispPtr->placeInit = 0; + dispPtr->selectionInfoPtr = NULL; + dispPtr->multipleAtom = None; + dispPtr->clipWindow = NULL; + dispPtr->clipboardActive = 0; + dispPtr->clipboardAppPtr = NULL; + dispPtr->clipTargetPtr = NULL; + dispPtr->commTkwin = NULL; + dispPtr->wmTracing = 0; + dispPtr->firstWmPtr = NULL; + dispPtr->foregroundWmPtr = NULL; dispPtr->destroyCount = 0; dispPtr->lastDestroyRequest = 0; dispPtr->cmapPtr = NULL; - dispPtr->implicitWinPtr = NULL; - dispPtr->focusPtr = NULL; - dispPtr->stressPtr = NULL; - dispPtr->delayedMotionPtr = NULL; Tcl_InitHashTable(&dispPtr->winTable, TCL_ONE_WORD_KEYS); + dispPtr->refCount = 0; - - tkDisplayList = dispPtr; + strncpy(dispPtr->name, screenName, length); + dispPtr->name[length] = '\0'; + dispPtr->useInputMethods = 0; + OpenIM(dispPtr); + TkInitXId(dispPtr); + + tsdPtr->displayList = dispPtr; break; } if ((strncmp(dispPtr->name, screenName, length) == 0) @@ -442,7 +471,10 @@ GetScreen(interp, screenName, screenPtr) } } if (screenId >= ScreenCount(dispPtr->display)) { - sprintf(interp->result, "bad screen number \"%d\"", screenId); + char buf[32 + TCL_INTEGER_SPACE]; + + sprintf(buf, "bad screen number \"%d\"", screenId); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return (TkDisplay *) NULL; } *screenPtr = screenId; @@ -472,8 +504,10 @@ TkGetDisplay(display) Display *display; /* X's display pointer */ { TkDisplay *dispPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - for (dispPtr = tkDisplayList; dispPtr != NULL; + for (dispPtr = tsdPtr->displayList; dispPtr != NULL; dispPtr = dispPtr->nextPtr) { if (dispPtr->display == display) { break; @@ -485,6 +519,58 @@ TkGetDisplay(display) /* *-------------------------------------------------------------- * + * TkGetDisplayList -- + * + * This procedure returns a pointer to the thread-local + * list of TkDisplays corresponding to the open displays. + * + * Results: + * The return value is a pointer to the first TkDisplay + * structure in thread-local-storage. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +TkDisplay * +TkGetDisplayList() +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + return tsdPtr->displayList; +} + +/* + *-------------------------------------------------------------- + * + * TkGetMainInfoList -- + * + * This procedure returns a pointer to the list of structures + * containing information about all main windows for the + * current thread. + * + * Results: + * The return value is a pointer to the first TkMainInfo + * structure in thread local storage. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +TkMainInfo * +TkGetMainInfoList() +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + return tsdPtr->mainWindowList; +} +/* + *-------------------------------------------------------------- + * * TkAllocWindow -- * * This procedure creates and initializes a TkWindow structure. @@ -675,7 +761,7 @@ NameWindow(interp, winPtr, parentPtr, name) * The return value is a token for the new window, or NULL if * an error prevented the new window from being created. If * NULL is returned, an error message will be left in - * interp->result. + * the interp's result. * * Side effects: * A new window structure is allocated locally; "interp" is @@ -703,6 +789,9 @@ TkCreateMainWindow(interp, screenName, baseName) register TkMainInfo *mainPtr; register TkWindow *winPtr; register TkCmd *cmdPtr; + ClientData clientData; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * Panic if someone updated the TkWindow structure without @@ -734,6 +823,7 @@ TkCreateMainWindow(interp, screenName, baseName) mainPtr->refCount = 1; mainPtr->interp = interp; Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS); + TkEventInit(); TkBindInit(mainPtr); TkFontPkgInit(mainPtr); mainPtr->tlFocusPtr = NULL; @@ -745,8 +835,8 @@ TkCreateMainWindow(interp, screenName, baseName) TCL_LINK_BOOLEAN) != TCL_OK) { Tcl_ResetResult(interp); } - mainPtr->nextPtr = tkMainWindowList; - tkMainWindowList = mainPtr; + mainPtr->nextPtr = tsdPtr->mainWindowList; + tsdPtr->mainWindowList = mainPtr; winPtr->mainPtr = mainPtr; hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, ".", &dummy); Tcl_SetHashValue(hPtr, winPtr); @@ -774,12 +864,17 @@ TkCreateMainWindow(interp, screenName, baseName) if ((cmdPtr->cmdProc == NULL) && (cmdPtr->objProc == NULL)) { panic("TkCreateMainWindow: builtin command with NULL string and object procs"); } + if (cmdPtr->passMainWindow) { + clientData = (ClientData) tkwin; + } else { + clientData = (ClientData) NULL; + } if (cmdPtr->cmdProc != NULL) { Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc, - (ClientData) tkwin, (void (*) _ANSI_ARGS_((ClientData))) NULL); + clientData, (void (*) _ANSI_ARGS_((ClientData))) NULL); } else { Tcl_CreateObjCommand(interp, cmdPtr->name, cmdPtr->objProc, - (ClientData) tkwin, NULL); + clientData, NULL); } if (isSafe) { if (!(cmdPtr->isSafe)) { @@ -788,6 +883,8 @@ TkCreateMainWindow(interp, screenName, baseName) } } + TkCreateMenuCmd(interp); + /* * Set variables for the intepreter. */ @@ -795,7 +892,7 @@ TkCreateMainWindow(interp, screenName, baseName) Tcl_SetVar(interp, "tk_patchLevel", TK_PATCH_LEVEL, TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "tk_version", TK_VERSION, TCL_GLOBAL_ONLY); - numMainWindows++; + tsdPtr->numMainWindows++; return tkwin; } @@ -811,7 +908,7 @@ TkCreateMainWindow(interp, screenName, baseName) * The return value is a token for the new window. This * is not the same as X's token for the window. If an error * occurred in creating the window (e.g. no such display or - * screen), then an error message is left in interp->result and + * screen), then an error message is left in the interp's result and * NULL is returned. * * Side effects: @@ -825,7 +922,7 @@ TkCreateMainWindow(interp, screenName, baseName) Tk_Window Tk_CreateWindow(interp, parent, name, screenName) Tcl_Interp *interp; /* Interpreter to use for error reporting. - * Interp->result is assumed to be + * the interp's result is assumed to be * initialized by the caller. */ Tk_Window parent; /* Token for parent of new window. */ char *name; /* Name for new window. Must be unique @@ -878,7 +975,7 @@ Tk_CreateWindow(interp, parent, name, screenName) * The return value is a token for the new window. This * is not the same as X's token for the window. If an error * occurred in creating the window (e.g. no such display or - * screen), then an error message is left in interp->result and + * screen), then an error message is left in the interp's result and * NULL is returned. * * Side effects: @@ -892,7 +989,7 @@ Tk_CreateWindow(interp, parent, name, screenName) Tk_Window Tk_CreateWindowFromPath(interp, tkwin, pathName, screenName) Tcl_Interp *interp; /* Interpreter to use for error reporting. - * Interp->result is assumed to be + * the interp's result is assumed to be * initialized by the caller. */ Tk_Window tkwin; /* Token for any window in application * that is to contain new window. */ @@ -1011,6 +1108,8 @@ Tk_DestroyWindow(tkwin) TkWindow *winPtr = (TkWindow *) tkwin; TkDisplay *dispPtr = winPtr->dispPtr; XEvent event; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (winPtr->flags & TK_ALREADY_DEAD) { /* @@ -1054,19 +1153,19 @@ Tk_DestroyWindow(tkwin) if (winPtr->mainPtr->winPtr == winPtr) { dispPtr->refCount--; - if (tkMainWindowList == winPtr->mainPtr) { - tkMainWindowList = winPtr->mainPtr->nextPtr; + if (tsdPtr->mainWindowList == winPtr->mainPtr) { + tsdPtr->mainWindowList = winPtr->mainPtr->nextPtr; } else { TkMainInfo *prevPtr; - for (prevPtr = tkMainWindowList; + for (prevPtr = tsdPtr->mainWindowList; prevPtr->nextPtr != winPtr->mainPtr; prevPtr = prevPtr->nextPtr) { /* Empty loop body. */ } prevPtr->nextPtr = winPtr->mainPtr->nextPtr; } - numMainWindows--; + tsdPtr->numMainWindows--; } /* @@ -1222,8 +1321,8 @@ Tk_DestroyWindow(tkwin) Tcl_DeleteHashTable(&winPtr->mainPtr->nameTable); TkBindFree(winPtr->mainPtr); - TkFontPkgFree(winPtr->mainPtr); TkDeleteAllImages(winPtr->mainPtr); + TkFontPkgFree(winPtr->mainPtr); /* * When embedding Tk into other applications, make sure @@ -1257,7 +1356,7 @@ Tk_DestroyWindow(tkwin) * Splice this display out of the list of displays. */ - for (theDispPtr = tkDisplayList, backDispPtr = NULL; + for (theDispPtr = displayList, backDispPtr = NULL; (theDispPtr != winPtr->dispPtr) && (theDispPtr != NULL); theDispPtr = theDispPtr->nextPtr) { @@ -1267,7 +1366,7 @@ Tk_DestroyWindow(tkwin) panic("could not find display to close!"); } if (backDispPtr == NULL) { - tkDisplayList = theDispPtr->nextPtr; + displayList = theDispPtr->nextPtr; } else { backDispPtr->nextPtr = theDispPtr->nextPtr; } @@ -1993,7 +2092,7 @@ TkSetClassProcs(tkwin, procs, instanceData) * Results: * The return result is either a token for the window corresponding * to "name", or else NULL to indicate that there is no such - * window. In this case, an error message is left in interp->result. + * window. In this case, an error message is left in the interp's result. * * Side effects: * None. @@ -2010,6 +2109,15 @@ Tk_NameToWindow(interp, pathName, tkwin) { Tcl_HashEntry *hPtr; + if (tkwin == NULL) { + /* + * Either we're not really in Tk, or the main window was destroyed and + * we're on our way out of the application + */ + Tcl_AppendResult(interp, "NULL main window", (char *)NULL); + return NULL; + } + hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->nameTable, pathName); if (hPtr == NULL) { @@ -2048,7 +2156,7 @@ Tk_IdToWindow(display, window) TkDisplay *dispPtr; Tcl_HashEntry *hPtr; - for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) { + for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) { if (dispPtr == NULL) { return NULL; } @@ -2165,9 +2273,6 @@ Tk_RestackWindow(tkwin, aboveBelow, other) { TkWindow *winPtr = (TkWindow *) tkwin; TkWindow *otherPtr = (TkWindow *) other; - XWindowChanges changes; - unsigned int mask; - /* * Special case: if winPtr is a top-level window then just find @@ -2175,8 +2280,6 @@ Tk_RestackWindow(tkwin, aboveBelow, other) * otherPtr without changing any of Tk's childLists. */ - changes.stack_mode = aboveBelow; - mask = CWStackMode; if (winPtr->flags & TK_TOP_LEVEL) { while ((otherPtr != NULL) && !(otherPtr->flags & TK_TOP_LEVEL)) { otherPtr = otherPtr->parentPtr; @@ -2248,6 +2351,10 @@ Tk_RestackWindow(tkwin, aboveBelow, other) */ if (winPtr->window != None) { + XWindowChanges changes; + unsigned int mask; + + mask = CWStackMode; changes.stack_mode = Above; for (otherPtr = winPtr->nextPtr; otherPtr != NULL; otherPtr = otherPtr->nextPtr) { @@ -2274,7 +2381,7 @@ Tk_RestackWindow(tkwin, aboveBelow, other) * Results: * If interp has a Tk application associated with it, the main * window for the application is returned. Otherwise NULL is - * returned and an error message is left in interp->result. + * returned and an error message is left in the interp's result. * * Side effects: * None. @@ -2289,14 +2396,16 @@ Tk_MainWindow(interp) * reporting also. */ { TkMainInfo *mainPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - for (mainPtr = tkMainWindowList; mainPtr != NULL; + for (mainPtr = tsdPtr->mainWindowList; mainPtr != NULL; mainPtr = mainPtr->nextPtr) { if (mainPtr->interp == interp) { return (Tk_Window) mainPtr->winPtr; } } - interp->result = "this isn't a Tk application"; + Tcl_SetResult(interp, "this isn't a Tk application", TCL_STATIC); return NULL; } @@ -2407,7 +2516,10 @@ OpenIM(dispPtr) int Tk_GetNumMainWindows() { - return numMainWindows; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + return tsdPtr->numMainWindows; } /* @@ -2433,8 +2545,10 @@ DeleteWindowsExitProc(clientData) { TkDisplay *displayPtr, *nextPtr; Tcl_Interp *interp; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - while (tkMainWindowList != NULL) { + while (tsdPtr->mainWindowList != NULL) { /* * We must protect the interpreter while deleting the window, * because of <Destroy> bindings which could destroy the interpreter @@ -2442,14 +2556,14 @@ DeleteWindowsExitProc(clientData) * the call stack pointing at deleted memory, causing core dumps. */ - interp = tkMainWindowList->winPtr->mainPtr->interp; + interp = tsdPtr->mainWindowList->winPtr->mainPtr->interp; Tcl_Preserve((ClientData) interp); - Tk_DestroyWindow((Tk_Window) tkMainWindowList->winPtr); + Tk_DestroyWindow((Tk_Window) tsdPtr->mainWindowList->winPtr); Tcl_Release((ClientData) interp); } - displayPtr = tkDisplayList; - tkDisplayList = NULL; + displayPtr = tsdPtr->displayList; + tsdPtr->displayList = NULL; /* * Iterate destroying the displays until no more displays remain. @@ -2458,9 +2572,9 @@ DeleteWindowsExitProc(clientData) * as well as the old ones. */ - for (displayPtr = tkDisplayList; + for (displayPtr = tsdPtr->displayList; displayPtr != NULL; - displayPtr = tkDisplayList) { + displayPtr = tsdPtr->displayList) { /* * Now iterate over the current list of open displays, and first @@ -2471,7 +2585,8 @@ DeleteWindowsExitProc(clientData) * if it needs to dispatch a message. */ - for (tkDisplayList = NULL; displayPtr != NULL; displayPtr = nextPtr) { + for (tsdPtr->displayList = NULL; displayPtr != NULL; + displayPtr = nextPtr) { nextPtr = displayPtr->nextPtr; if (displayPtr->name != (char *) NULL) { ckfree(displayPtr->name); @@ -2481,12 +2596,9 @@ DeleteWindowsExitProc(clientData) } } - numMainWindows = 0; - tkMainWindowList = NULL; - initialized = 0; - tkDisabledUid = NULL; - tkActiveUid = NULL; - tkNormalUid = NULL; + tsdPtr->numMainWindows = 0; + tsdPtr->mainWindowList = NULL; + tsdPtr->initialized = 0; } /* @@ -2504,7 +2616,7 @@ DeleteWindowsExitProc(clientData) * the arguments that are extracted). * * Results: - * Returns a standard Tcl completion code and sets interp->result + * Returns a standard Tcl completion code and sets the interp's result * if there is an error. * * Side effects: @@ -2529,7 +2641,7 @@ Tk_Init(interp) * invokes the internal procedure that does the real work. * * Results: - * Returns a standard Tcl completion code and sets interp->result + * Returns a standard Tcl completion code and sets the interp's result * if there is an error. * * Side effects: @@ -2582,6 +2694,9 @@ Tk_SafeInit(interp) return Initialize(interp); } + +extern TkStubs tkStubs; + /* *---------------------------------------------------------------------- * @@ -2589,8 +2704,8 @@ Tk_SafeInit(interp) * * * Results: - * A standard Tcl result. Also leaves an error message in interp->result - * if there was an error. + * A standard Tcl result. Also leaves an error message in the interp's + * result if there was an error. * * Side effects: * Depends on the initialization scripts that are invoked. @@ -2606,7 +2721,19 @@ Initialize(interp) int argc, code; char **argv, *args[20]; Tcl_DString class; - char buffer[30]; + ThreadSpecificData *tsdPtr; + + /* + * Ensure that we are getting the matching version of Tcl. This is + * really only an issue when Tk is loaded dynamically. + */ + + if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { + return TCL_ERROR; + } + + tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * Start by initializing all the static variables to default acceptable @@ -2614,6 +2741,7 @@ Initialize(interp) * code. */ + Tcl_MutexLock(&windowMutex); synchronize = 0; name = NULL; display = NULL; @@ -2648,6 +2776,7 @@ Initialize(interp) if (master == NULL) { Tcl_DStringFree(&ds); Tcl_AppendResult(interp, "NULL master", (char *) NULL); + Tcl_MutexUnlock(&windowMutex); return TCL_ERROR; } if (!Tcl_IsSafe(master)) { @@ -2661,6 +2790,7 @@ Initialize(interp) if (Tcl_GetInterpPath(master, interp) != TCL_OK) { Tcl_AppendResult(interp, "error in Tcl_GetInterpPath", (char *) NULL); + Tcl_MutexUnlock(&windowMutex); return TCL_ERROR; } /* @@ -2684,6 +2814,7 @@ Initialize(interp) Tcl_AppendResult(interp, "not allowed to start Tk by master's safe::TkInit", (char *) NULL); + Tcl_MutexUnlock(&windowMutex); return TCL_ERROR; } Tcl_DStringFree(&ds); @@ -2705,10 +2836,13 @@ Initialize(interp) } argv = NULL; if (p != NULL) { + char buffer[TCL_INTEGER_SPACE]; + if (Tcl_SplitList(interp, p, &argc, &argv) != TCL_OK) { argError: Tcl_AddErrorInfo(interp, "\n (processing arguments in argv variable)"); + Tcl_MutexUnlock(&windowMutex); return TCL_ERROR; } if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv, @@ -2741,8 +2875,8 @@ Initialize(interp) } p = Tcl_DStringValue(&class); - if (islower(UCHAR(*p))) { - *p = toupper(UCHAR(*p)); + if (*p) { + Tcl_UtfToTitle(p); } /* @@ -2766,7 +2900,7 @@ Initialize(interp) * that it will be available to subprocesses created by us. */ - if (numMainWindows == 0) { + if (tsdPtr->numMainWindows == 0) { Tcl_SetVar2(interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY); } } @@ -2813,15 +2947,28 @@ Initialize(interp) } geometry = NULL; } + Tcl_MutexUnlock(&windowMutex); + if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) { code = TCL_ERROR; goto done; } - code = Tcl_PkgProvide(interp, "Tk", TK_VERSION); + + /* + * Provide Tk and its stub table. + */ + + code = Tcl_PkgProvideEx(interp, "Tk", TK_VERSION, (ClientData) &tkStubs); if (code != TCL_OK) { goto done; } +#ifdef Tk_InitStubs +#undef Tk_InitStubs +#endif + + Tk_InitStubs(interp, TK_VERSION, 1); + /* * Invoke platform-specific initialization. */ @@ -2834,3 +2981,5 @@ Initialize(interp) } return code; } + + diff --git a/tk/generic/tkXId.c b/tk/generic/tkXId.c new file mode 100644 index 00000000000..8cf397d9dd4 --- /dev/null +++ b/tk/generic/tkXId.c @@ -0,0 +1,495 @@ +/* + * tkXId.c -- + * + * This file provides a replacement function for the default X + * resource allocator (_XAllocID). The problem with the default + * allocator is that it never re-uses ids, which causes long-lived + * applications to crash when X resource identifiers wrap around. + * The replacement functions in this file re-use old identifiers + * to prevent this problem. + * + * The code in this file is based on similar implementations by + * George C. Kaplan and Michael Hoegeman. + * + * Copyright (c) 1993 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: @(#) tkXId.c 1.16 96/02/28 21:56:40 + */ + +/* + * The definition below is needed on some systems so that we can access + * the resource_alloc field of Display structures in order to replace + * the resource allocator. + */ + +#define XLIB_ILLEGAL_ACCESS 1 + +#include "tkInt.h" +#include "tkPort.h" + +/* + * A structure of the following type is used to hold one or more + * available resource identifiers. There is a list of these structures + * for each display. + */ + +#define IDS_PER_STACK 10 +typedef struct TkIdStack { + XID ids[IDS_PER_STACK]; /* Array of free identifiers. */ + int numUsed; /* Indicates how many of the entries + * in ids are currently in use. */ + TkDisplay *dispPtr; /* Display to which ids belong. */ + struct TkIdStack *nextPtr; /* Next bunch of free identifiers + * for the same display. */ +} TkIdStack; + +/* + * Forward declarations for procedures defined in this file: + */ + +static XID AllocXId _ANSI_ARGS_((Display *display)); +static Tk_RestrictAction CheckRestrictProc _ANSI_ARGS_(( + ClientData clientData, XEvent *eventPtr)); +static void WindowIdCleanup _ANSI_ARGS_((ClientData clientData)); +static void WindowIdCleanup2 _ANSI_ARGS_((ClientData clientData)); + +/* + *---------------------------------------------------------------------- + * + * TkInitXId -- + * + * This procedure is called to initialize the id allocator for + * a given display. + * + * Results: + * None. + * + * Side effects: + * The official allocator for the display is set up to be Tk_AllocXID. + * + *---------------------------------------------------------------------- + */ + +void +TkInitXId(dispPtr) + TkDisplay *dispPtr; /* Tk's information about the + * display. */ +{ + dispPtr->idStackPtr = NULL; + dispPtr->defaultAllocProc = dispPtr->display->resource_alloc; + dispPtr->display->resource_alloc = AllocXId; + dispPtr->windowStackPtr = NULL; + dispPtr->idCleanupScheduled = 0; +} + +/* + *---------------------------------------------------------------------- + * + * AllocXId -- + * + * This procedure is invoked by Xlib as the resource allocator + * for a display. + * + * Results: + * The return value is an X resource identifier that isn't currently + * in use. + * + * Side effects: + * The identifier is removed from the stack of free identifiers, + * if it was previously on the stack. + * + *---------------------------------------------------------------------- + */ + +static XID +AllocXId(display) + Display *display; /* Display for which to allocate. */ +{ + TkDisplay *dispPtr; + TkIdStack *stackPtr; + + /* + * Find Tk's information about the display. + */ + + dispPtr = TkGetDisplay(display); + + /* + * If the topmost chunk on the stack is empty then free it. Then + * check for a free id on the stack and return it if it exists. + */ + + stackPtr = dispPtr->idStackPtr; + if (stackPtr != NULL) { + while (stackPtr->numUsed == 0) { + dispPtr->idStackPtr = stackPtr->nextPtr; + ckfree((char *) stackPtr); + stackPtr = dispPtr->idStackPtr; + if (stackPtr == NULL) { + goto defAlloc; + } + } + stackPtr->numUsed--; + return stackPtr->ids[stackPtr->numUsed]; + } + + /* + * No free ids in the stack: just get one from the default + * allocator. + */ + + defAlloc: + return (*dispPtr->defaultAllocProc)(display); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_FreeXId -- + * + * This procedure is called to indicate that an X resource identifier + * is now free. + * + * Results: + * None. + * + * Side effects: + * The identifier is added to the stack of free identifiers for its + * display, so that it can be re-used. + * + *---------------------------------------------------------------------- + */ + +void +Tk_FreeXId(display, xid) + Display *display; /* Display for which xid was + * allocated. */ + XID xid; /* Identifier that is no longer + * in use. */ +{ + TkDisplay *dispPtr; + TkIdStack *stackPtr; + + /* + * Find Tk's information about the display. + */ + + dispPtr = TkGetDisplay(display); + + /* + * Add a new chunk to the stack if the current chunk is full. + */ + + stackPtr = dispPtr->idStackPtr; + if ((stackPtr == NULL) || (stackPtr->numUsed >= IDS_PER_STACK)) { + stackPtr = (TkIdStack *) ckalloc(sizeof(TkIdStack)); + stackPtr->numUsed = 0; + stackPtr->dispPtr = dispPtr; + stackPtr->nextPtr = dispPtr->idStackPtr; + dispPtr->idStackPtr = stackPtr; + } + + /* + * Add the id to the current chunk. + */ + + stackPtr->ids[stackPtr->numUsed] = xid; + stackPtr->numUsed++; +} + +/* + *---------------------------------------------------------------------- + * + * TkFreeWindowId -- + * + * This procedure is invoked instead of TkFreeXId for window ids. + * See below for the reason why. + * + * Results: + * None. + * + * Side effects: + * The id given by w will eventually be freed, so that it can be + * reused for other resources. + * + * Design: + * Freeing window ids is very tricky because there could still be + * events pending for a window in the event queue (or even in the + * server) at the time the window is destroyed. If the window + * id were to get reused immediately for another window, old + * events could "drop in" on the new window, causing unexpected + * behavior. + * + * Thus we have to wait to re-use a window id until we know that + * there are no events left for it. Right now this is done in + * two steps. First, we wait until we know that the server + * has seen the XDestroyWindow request, so we can be sure that + * it won't generate more events for the window and that any + * existing events are in our queue. Second, we make sure that + * there are no events whatsoever in our queue (this is conservative + * but safe). + * + * The first step is done by remembering the request id of the + * XDestroyWindow request and using LastKnownRequestProcessed to + * see what events the server has processed. If multiple windows + * get destroyed at about the same time, we just remember the + * most recent request number for any of them (again, conservative + * but safe). + * + * There are a few other complications as well. When Tk destroys a + * sub-tree of windows, it only issues a single XDestroyWindow call, + * at the very end for the root of the subtree. We can't free any of + * the window ids until the final XDestroyWindow call. To make sure + * that this happens, we have to keep track of deletions in progress, + * hence the need for the "destroyCount" field of the display. + * + * One final problem. Some servers, like Sun X11/News servers still + * seem to have problems with ids getting reused too quickly. I'm + * not completely sure why this is a problem, but delaying the + * recycling of ids appears to eliminate it. Therefore, we wait + * an additional few seconds, even after "the coast is clear" + * before reusing the ids. + * + *---------------------------------------------------------------------- + */ + +void +TkFreeWindowId(dispPtr, w) + TkDisplay *dispPtr; /* Display that w belongs to. */ + Window w; /* X identifier for window on dispPtr. */ +{ + TkIdStack *stackPtr; + + /* + * Put the window id on a separate stack of window ids, rather + * than the main stack, so it won't get reused right away. Add + * a new chunk to the stack if the current chunk is full. + */ + + stackPtr = dispPtr->windowStackPtr; + if ((stackPtr == NULL) || (stackPtr->numUsed >= IDS_PER_STACK)) { + stackPtr = (TkIdStack *) ckalloc(sizeof(TkIdStack)); + stackPtr->numUsed = 0; + stackPtr->dispPtr = dispPtr; + stackPtr->nextPtr = dispPtr->windowStackPtr; + dispPtr->windowStackPtr = stackPtr; + } + + /* + * Add the id to the current chunk. + */ + + stackPtr->ids[stackPtr->numUsed] = w; + stackPtr->numUsed++; + + /* + * Schedule a call to WindowIdCleanup if one isn't already + * scheduled. + */ + + if (!dispPtr->idCleanupScheduled) { + dispPtr->idCleanupScheduled = 1; + Tcl_CreateTimerHandler(100, WindowIdCleanup, (ClientData *) dispPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * WindowIdCleanup -- + * + * See if we can now free up all the accumulated ids of + * deleted windows. + * + * Results: + * None. + * + * Side effects: + * If it's safe to move the window ids back to the main free + * list, we schedule this to happen after a few mores seconds + * of delay. If it's not safe to move them yet, a timer handler + * gets invoked to try again later. + * + *---------------------------------------------------------------------- + */ + +static void +WindowIdCleanup(clientData) + ClientData clientData; /* Pointer to TkDisplay for display */ +{ + TkDisplay *dispPtr = (TkDisplay *) clientData; + int anyEvents, delta; + Tk_RestrictProc *oldProc; + ClientData oldData; + + dispPtr->idCleanupScheduled = 0; + + /* + * See if it's safe to recycle the window ids. It's safe if: + * (a) no deletions are in progress. + * (b) the server has seen all of the requests up to the last + * XDestroyWindow request. + * (c) there are no events in the event queue; the only way to + * test for this right now is to create a restrict proc that + * will filter the events, then call Tcl_DoOneEvent to see if + * the procedure gets invoked. + */ + + if (dispPtr->destroyCount > 0) { + goto tryAgain; + } + delta = LastKnownRequestProcessed(dispPtr->display) + - dispPtr->lastDestroyRequest; + if (delta < 0) { + XSync(dispPtr->display, False); + } + anyEvents = 0; + oldProc = Tk_RestrictEvents(CheckRestrictProc, (ClientData) &anyEvents, + &oldData); + Tcl_DoOneEvent(TCL_DONT_WAIT|TCL_WINDOW_EVENTS); + Tk_RestrictEvents(oldProc, oldData, &oldData); + if (anyEvents) { + goto tryAgain; + } + + /* + * These ids look safe to recycle, but we still need to delay a bit + * more (see comments for TkFreeWindowId). Schedule the final freeing. + */ + + if (dispPtr->windowStackPtr != NULL) { + Tcl_CreateTimerHandler(5000, WindowIdCleanup2, + (ClientData) dispPtr->windowStackPtr); + dispPtr->windowStackPtr = NULL; + } + return; + + /* + * It's still not safe to free up the ids. Try again a bit later. + */ + + tryAgain: + dispPtr->idCleanupScheduled = 1; + Tcl_CreateTimerHandler(500, WindowIdCleanup, (ClientData *) dispPtr); +} + +/* + *---------------------------------------------------------------------- + * + * WindowIdCleanup2 -- + * + * This procedure is the last one in the chain that recycles + * window ids. It takes all of the ids indicated by its + * argument and adds them back to the main id free list. + * + * Results: + * None. + * + * Side effects: + * Window ids get added to the main free list for their display. + * + *---------------------------------------------------------------------- + */ + +static void +WindowIdCleanup2(clientData) + ClientData clientData; /* Pointer to TkIdStack list. */ +{ + TkIdStack *stackPtr = (TkIdStack *) clientData; + TkIdStack *lastPtr; + + lastPtr = stackPtr; + while (lastPtr->nextPtr != NULL) { + lastPtr = lastPtr->nextPtr; + } + lastPtr->nextPtr = stackPtr->dispPtr->idStackPtr; + stackPtr->dispPtr->idStackPtr = stackPtr; +} + +/* + *---------------------------------------------------------------------- + * + * CheckRestrictProc -- + * + * This procedure is a restrict procedure, called by Tcl_DoOneEvent + * to filter X events. All it does is to set a flag to indicate + * that there are X events present. + * + * Results: + * Sets the integer pointed to by the argument, then returns + * TK_DEFER_EVENT. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tk_RestrictAction +CheckRestrictProc(clientData, eventPtr) + ClientData clientData; /* Pointer to flag to set. */ + XEvent *eventPtr; /* Event to filter; not used. */ +{ + int *flag = (int *) clientData; + *flag = 1; + return TK_DEFER_EVENT; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetPixmap -- + * + * Same as the XCreatePixmap procedure except that it manages + * resource identifiers better. + * + * Results: + * Returns a new pixmap. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Pixmap +Tk_GetPixmap(display, d, width, height, depth) + Display *display; /* Display for new pixmap. */ + Drawable d; /* Drawable where pixmap will be used. */ + int width, height; /* Dimensions of pixmap. */ + int depth; /* Bits per pixel for pixmap. */ +{ + return XCreatePixmap(display, d, (unsigned) width, (unsigned) height, + (unsigned) depth); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_FreePixmap -- + * + * Same as the XFreePixmap procedure except that it also marks + * the resource identifier as free. + * + * Results: + * None. + * + * Side effects: + * The pixmap is freed in the X server and its resource identifier + * is saved for re-use. + * + *---------------------------------------------------------------------- + */ + +void +Tk_FreePixmap(display, pixmap) + Display *display; /* Display for which pixmap was allocated. */ + Pixmap pixmap; /* Identifier for pixmap. */ +{ + XFreePixmap(display, pixmap); + Tk_FreeXId(display, (XID) pixmap); +} |