diff options
author | stanton <stanton@noemail.net> | 1998-09-29 00:25:04 (GMT) |
---|---|---|
committer | stanton <stanton@noemail.net> | 1998-09-29 00:25:04 (GMT) |
commit | f110d4e2a4b45b23f037e22b18041093a18a028f (patch) | |
tree | 99c199f65b7d32755dc8f0ee5cc773bd922a74a6 /mac | |
parent | 44fe62a9cda522475be53f14654970aaa3d4a648 (diff) | |
download | tk-f110d4e2a4b45b23f037e22b18041093a18a028f.zip tk-f110d4e2a4b45b23f037e22b18041093a18a028f.tar.gz tk-f110d4e2a4b45b23f037e22b18041093a18a028f.tar.bz2 |
initial tk8.1a2 version
FossilOrigin-Name: 644396f2dabc649ad5784768cfe962017d991df1
Diffstat (limited to 'mac')
-rw-r--r-- | mac/MW_TkHeader.pch | 78 | ||||
-rw-r--r-- | mac/README | 107 | ||||
-rw-r--r-- | mac/bugs.doc | 8 | ||||
-rw-r--r-- | mac/tkMac.h | 39 | ||||
-rw-r--r-- | mac/tkMacAppInit.c | 6 | ||||
-rw-r--r-- | mac/tkMacBitmap.c | 29 | ||||
-rw-r--r-- | mac/tkMacButton.c | 428 | ||||
-rw-r--r-- | mac/tkMacClipboard.c | 4 | ||||
-rw-r--r-- | mac/tkMacConfig.c | 45 | ||||
-rw-r--r-- | mac/tkMacCursor.c | 60 | ||||
-rw-r--r-- | mac/tkMacDefault.h | 5 | ||||
-rw-r--r-- | mac/tkMacDialog.c | 776 | ||||
-rw-r--r-- | mac/tkMacEmbed.c | 186 | ||||
-rw-r--r-- | mac/tkMacFont.c | 1984 | ||||
-rw-r--r-- | mac/tkMacHLEvents.c | 8 | ||||
-rw-r--r-- | mac/tkMacInit.c | 4 | ||||
-rw-r--r-- | mac/tkMacInt.h | 21 | ||||
-rw-r--r-- | mac/tkMacKeyboard.c | 70 | ||||
-rw-r--r-- | mac/tkMacLibrary.r | 4 | ||||
-rw-r--r-- | mac/tkMacMenu.c | 546 | ||||
-rw-r--r-- | mac/tkMacPort.h | 5 | ||||
-rw-r--r-- | mac/tkMacProjects.sit.hqx | 800 | ||||
-rw-r--r-- | mac/tkMacResource.r | 24 | ||||
-rw-r--r-- | mac/tkMacSend.c | 330 | ||||
-rw-r--r-- | mac/tkMacShLib.exp | 2 | ||||
-rw-r--r-- | mac/tkMacSubwindows.c | 130 | ||||
-rw-r--r-- | mac/tkMacTest.c | 3 | ||||
-rw-r--r-- | mac/tkMacWindowMgr.c | 126 | ||||
-rw-r--r-- | mac/tkMacWm.c | 222 | ||||
-rw-r--r-- | mac/tkMacXStubs.c | 7 |
30 files changed, 4534 insertions, 1523 deletions
diff --git a/mac/MW_TkHeader.pch b/mac/MW_TkHeader.pch index 7b7e2a4..a049f62 100644 --- a/mac/MW_TkHeader.pch +++ b/mac/MW_TkHeader.pch @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) MW_TkHeader.pch 1.26 97/11/20 19:37:29 + * SCCS: @(#) MW_TkHeader.pch 1.29 98/02/18 16:23:13 */ /* @@ -31,42 +31,13 @@ #pragma precompile_target "MW_TkHeader68K" #endif -/* - * Macintosh Tcl must be compiled with certain compiler options to - * ensure that it will work correctly. The following pragmas are - * used to ensure that those options are set correctly. An error - * will occur at compile time if they are not set correctly. - */ +#include "tclMacCommonDefines.h" -#if !__option(enumsalwaysint) -#error Tcl requires the Metrowerks setting "Enums always ints". -#endif - -#if !defined(__POWERPC__) -#if !__option(far_data) -#error Tcl requires the Metrowerks setting "Far data". -#endif -#endif - -#if !defined(__POWERPC__) -#if !__option(fourbyteints) -#error Tcl requires the Metrowerks setting "4 byte ints". -#endif -#endif - -#if !defined(__POWERPC__) -#if !__option(IEEEdoubles) -#error Tcl requires the Metrowerks setting "8 byte doubles". -#endif +#ifdef TCL_DEBUG +#define TK_TEST #endif /* - * The define is used most everywhere to tell Tk (or any Tk - * extensions) that we are compiling for the Macintosh platform. - */ -#define MAC_TCL - -/* * The following defines are for the Xlib.h file to force * it to generate prototypes in the way we need it. This is * defined here in case X.h & company are ever included before @@ -77,47 +48,6 @@ #define NeedWidePrototypes 0 /* - * The following defines control the behavior of the Macintosh - * Universial Headers. - */ - -#define SystemSevenOrLater 1 -#define STRICT_CONTROLS 0 -#define STRICT_WINDOWS 0 - -/* - * The appearance manager has not yet been shiped by Apple (10/29/97). - * It's currently in beta testing which is why we were able to write - * some code that depends on it. If you have access to the appearance - * manager you can define the symbol HAVE_APPEARANCE below to compile - * the code that uses the new appearance manager. - */ - -/* #define HAVE_APPEARANCE 1 */ - -/* - * Define the following symbol if you want - * comprehensive debugging turned on. - */ - -/* #define TCL_DEBUG */ - -#ifdef TCL_DEBUG -# define TCL_MEM_DEBUG -# define TK_TEST -# define TCL_TEST -#endif - -/* - * Apple's Universal Headers 2.0 & 3.0 change alot of names and constants. - * We will switch to the new names as soon as we can be reasonably sure the - * number of people with older versions of CodeWarrior, who will then not be - * able to build Tcl/Tk, is negligible. - */ - -#define OLDROUTINENAMES 1 - -/* * Place any includes below that will are needed by the majority of the * and is OK to be in any file in the system. */ @@ -1,10 +1,11 @@ -Tk 8.0 for Macintosh +Tk 8.1 for Macintosh -by Ray Johnson +by Ray Johnson and Jim Ingham Sun Microsystems Laboratories rjohnson@eng.sun.com +jim.ingham@sun.com -SCCS: @(#) README 1.30 97/11/20 22:06:57 +SCCS: @(#) README 1.33 98/02/18 11:23:12 1. Introduction --------------- @@ -18,50 +19,12 @@ directory. 2. What's new? ------------- -Native Look & Feel!!! We now try really hard to support the -Macintosh Look & Feel with Tcl/Tk 8.0. We aren't finished but -it look pretty good. Let me know what are the most "un-mac like" -problems and I'll fix them as quickly as I can. - -The button, checkbutton, radiobutton, and scrollbar widgets actually -use the Mac toolbox controls. This means that they will track the -look&feel if you use extension that change the appearance of -applications (like Aaron.) We also use "system" colors so the default -backgrounds etc. will also change colors. We plan to support this -feature - so let me know if something doesn't work quite right. -Unfortunantly, we are not able to change the colors of buttons under -MacOS 8. We are working on a solution to this. -In the meantime, if you really must have colored buttons, turn off the -"System-wide platinum appearance" option in the Appearance Control Panel, -and you will get the System 7, colorable, buttons back. - -We also now support native menus! By using the new -menu option -on toplevels you can have a menubar that is cross platform. You -can also place Tk menus in the Apple and Help menus! Check out -the documentation for more details. Syd Polk <icepick@eng.sun.com> is -the author of the new menu code. Feel free to contact him if you -have questions or comments about the menu mechanism. - -The "tk_messageBox" command on the Macintosh is now much more -mac-like. I'll probably still need to adjust this more - but it -looks a hell of alot better than it did before. - -I've also added a command that allows you to get more native window -styles. However, we have yet to decide on a cross platform solution -to the problem of varying window styles. None the less, I thought -it would be use full to add the capability in an unsupported means -to tide you over until a better solution is available. The command -is called "unsupported1". It can be used in the following way: - - toplevel .foo; unsupported1 style .foo zoomDocProc - -The above command will create a document window with a zoom box. -Type "unsupported1 style . ???" to get a list of the supported -styles. The command works like "wm overrideredirect" - you must -make the call before the window is mapped. - -As always - report the bugs you find - including asthetic ones -in the look & feel of widgets. +All the widgets will now display internationalized text! + +The widget configuration package has been changed to support the new object +model introduced with the 8.0 compiler. For now the old configuration +package is retained, and in fact, only the menu and button widgets use +the new package. 3. Mac specific features ------------------------ @@ -94,8 +57,8 @@ pointers to where you can find more information about the feature. Mac version of Tk allows you to use several Mac specific icons. See the GetBitmap.3 man page for a complete list. -* The send command does not yet work on the Macintosh. We hope to - have it available in Tk 8.1. +* The send command works among interpreters in the same application. We hope to + have the complete implementation available in Tk 8.1. * The -use and -container options almost work. The focus bugs that were in Tk8.0 final have been fixed. But there are still some @@ -109,7 +72,7 @@ Macintosh Tk is distributed in three different forms. This should make it easier to only download what you need. The packages are as follows: -mactk8.0.sea.hqx +mactk8.1.sea.hqx This distribution is a "binary" only release. It contains an installer program that will install a 68k, PowerPC, or Fat @@ -117,13 +80,13 @@ mactk8.0.sea.hqx the Tcl & Tk libraries in the Extensions folder inside your System Folder. (No "INIT"'s or Control Pannels are installed.) -mactcltk-full-8.0.sea.hqx +mactcltk-full-8.1.sea.hqx This release contains the full release of Tcl and Tk for the Macintosh plus the More Files package on which Macintosh Tcl and Tk rely. -mactk-source-8.0.sea.hqx +mactk-source-8.1.sea.hqx This release contains the complete source to Tk for the Macintosh In addition, Metrowerks CodeWarrior libraries and project files @@ -172,44 +135,36 @@ available (see below). In order to compile Macintosh Tk you must have the following items: - CodeWarrior Pro 1 or higher (CodeWarrior release 9 or higher can work - and we have project files, but we are depricating support) - Mac Tcl 8.0 (source) + CodeWarrior Pro 2 or higher + Mac Tcl 8.1 (source) (which requires More Files 1.4.2 or 1.4.3) - Mac Tk 8.0 (source) + Mac Tk 8.1 (source) The project files included with the Mac Tcl source should work fine. The only thing you may need to update are the access paths. -As with Tcl, there is something in the initial release of the CW Pro 2 -linker that rendersthe CFM68K version of Wish very unstable. I am -working with Metrowerks to resolve the issue. +As with Tcl, you need to upgrade to the 2.0.1 version of the C +compilers or later to build the CFM68K version of Tcl/Tk. Special notes: * Check out the file bugs.doc for information about known bugs. * We are starting to support the new Appearance Manager that shipped - with MacOS 8. At this point, the only feature that we are using is - the API to Iconify windows (so that wm iconify will work). However, - as of the release of Tk8.0p1, the SDK from Apple is still in Beta, so - we cannot ship it. So support for the Appearance Manager is turned off - in the source version of Tk8.0p1. - If you want to build Tk, and want to get the Appearance Manager features, - then need to do the following: - 1) get the SDK from Apple - 2) Uncomment the #define HAVE_APPEARANCE line in tk8.0:mac:MW_TkHeader.pch - 3) Add the Appearance.lib to tk8.0:mac:TkShells.¼, and put the include - directory of the SDK on your path in this project, and TkLibraries.¼. + with MacOS 8. wm iconify uses it, and the coloring of the + backgrounds of radiobuttons & checkbuttons now works under + Appearance. Tk correctly checks the Gestalt for Appearance, so you + do not have to install it on your target machines. However, you do + have to have the header and stub files to build it. These come with + CWPro 2, and are also available now from Apple. + 7. About Dialog --------------- -There is now a way to replace the default dialog box for the Wish -application. If you create the tcl procedure "tkAboutDialog" it will -be called instead of creating the default dialog box. Your procedure -is then responsible for displaying a window, removing it, etc. This -interface is experimental and may change in the future - tell me what -you think of it. +The prefered method for replacing the about dialog is to replace the +main menubar of the application, using the -menu option for the "." +window. Then add a cascade called .mainMenu.apple to your mainMenu, +and you can put an about item in here WITH YOUR OWN LABEL! 8. Apple Events --------------- diff --git a/mac/bugs.doc b/mac/bugs.doc index e522d8c..5e5a3e8 100644 --- a/mac/bugs.doc +++ b/mac/bugs.doc @@ -4,7 +4,7 @@ by Ray Johnson Sun Microsystems Laboratories rjohnson@eng.sun.com -SCCS: @(#) bugs.doc 1.10 97/11/03 17:16:00 +SCCS: @(#) bugs.doc 1.11 98/02/18 13:24:41 We are now very close to passing the test suite for Tk. We are very interested in finding remaining bugs that still linger. Please let us @@ -26,7 +26,11 @@ Known bugs: container, so you can watch that instead. All the focus bugs in Tk8.0 have been fixed, however. -* The send command is not yet implemented. +* The send command is only implemented within the same app. + +* You cannot color buttons, and the indicators for radiobuttons and + checkbuttons under Appearance. They will always use the current + Theme color. But, then, you are not supposed to... * Drawing is not really correct. This shows up mostly in the canvas when line widths are greater than one. Unfortunantly, this will not diff --git a/mac/tkMac.h b/mac/tkMac.h index ce41c81..87c005a 100644 --- a/mac/tkMac.h +++ b/mac/tkMac.h @@ -8,13 +8,15 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacInt.h 1.58 97/05/06 16:45:18 + * SCCS: %Z% %M% %I% %E% %U% */ #ifndef _TKMAC #define _TKMAC #include <Windows.h> +#include <QDOffscreen.h> +#include "tkInt.h" /* * "export" is a MetroWerks specific pragma. It flags the linker that @@ -32,21 +34,46 @@ EXTERN QDGlobalsPtr tcl_macQdPtr; +/* + * Structures and function types for handling Netscape-type in process + * embedding where Tk does not control the top-level + */ +typedef int (Tk_MacEmbedRegisterWinProc) (int winID, Tk_Window window); +typedef GWorldPtr (Tk_MacEmbedGetGrafPortProc) (Tk_Window window); +typedef int (Tk_MacEmbedMakeContainerExistProc) (Tk_Window window); +typedef void (Tk_MacEmbedGetClipProc) (Tk_Window window, RgnHandle rgn); +typedef void (Tk_MacEmbedGetOffsetInParentProc) (Tk_Window window, Point *ulCorner); + /* - * The following functions are needed to create a shell, and so they must be exported - * from the Tk library. However, these are not the final form of these interfaces, so - * they are not currently supported as public interfaces. + * Mac Specific functions that are available to extension writers. */ + +EXTERN void Tk_MacSetEmbedHandler _ANSI_ARGS_(( + Tk_MacEmbedRegisterWinProc *registerWinProcPtr, + Tk_MacEmbedGetGrafPortProc *getPortProcPtr, + Tk_MacEmbedMakeContainerExistProc *containerExistProcPtr, + Tk_MacEmbedGetClipProc *getClipProc, + Tk_MacEmbedGetOffsetInParentProc *getOffsetProc)); + +EXTERN void Tk_MacTurnOffMenus _ANSI_ARGS_ (()); +EXTERN void Tk_MacTkOwnsCursor _ANSI_ARGS_ ((int tkOwnsIt)); + /* * These functions are currently in tkMacInt.h. They are just copied over here * so they can be exported. */ EXTERN void TkMacInitMenus _ANSI_ARGS_((Tcl_Interp *interp)); -EXTERN void TkMacInitAppleEvents _ANSI_ARGS_((Tcl_Interp *interp)); +EXTERN void TkMacInitAppleEvents _ANSI_ARGS_((Tcl_Interp *interp)); + +EXTERN int TkMacConvertEvent _ANSI_ARGS_((EventRecord *eventPtr)); +EXTERN int TkMacConvertTkEvent _ANSI_ARGS_((EventRecord *eventPtr, + Window window)); +EXTERN void TkGenWMConfigureEvent _ANSI_ARGS_((Tk_Window tkwin, + int x, int y, int width, int height, int flags)); +EXTERN void TkMacInvalClipRgns _ANSI_ARGS_((TkWindow *winPtr)); -EXTERN int TkMacConvertEvent _ANSI_ARGS_((EventRecord *eventPtr)); #pragma export reset diff --git a/mac/tkMacAppInit.c b/mac/tkMacAppInit.c index ebc2c18..226127f 100644 --- a/mac/tkMacAppInit.c +++ b/mac/tkMacAppInit.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacAppInit.c 1.35 97/07/28 11:18:55 + * SCCS: @(#) tkMacAppInit.c 1.36 97/11/07 21:20:46 */ #include <Gestalt.h> @@ -108,7 +108,7 @@ main( * * 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: * Depends on the startup script. @@ -307,7 +307,7 @@ SetupMainInterp( return TCL_OK; error: - panic(interp->result); + panic(Tcl_GetStringResult(interp)); return TCL_ERROR; } diff --git a/mac/tkMacBitmap.c b/mac/tkMacBitmap.c index fd08193..6571d43 100644 --- a/mac/tkMacBitmap.c +++ b/mac/tkMacBitmap.c @@ -3,12 +3,12 @@ * * This file handles the implementation of native bitmaps. * - * 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. * - * SCCS: @(#) tkMacBitmap.c 1.4 96/12/13 11:13:16 + * SCCS: @(#) tkMacBitmap.c 1.7 98/01/22 17:00:58 */ #include "tkPort.h" @@ -82,7 +82,7 @@ static BuiltInIcon builtInIcons[] = { * * 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 @@ -128,7 +128,7 @@ TkpDefineNativeBitmaps() * * 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 @@ -188,7 +188,7 @@ TkpCreateNativeBitmap( * * 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 @@ -210,19 +210,28 @@ TkpGetNativeAppBitmap( GWorldPtr destPort; Rect destRect; Handle resource; - int type; + int type, destWrote; + Str255 nativeName; + + /* + * macRoman is the encoding that the resource fork uses. + */ + + Tcl_UtfToExternal(NULL, Tcl_GetEncoding(NULL, "macRoman"), name, + strlen(name), 0, NULL, + (char *) &nativeName[1], + 255, NULL, &destWrote, NULL); /* Internalize native */ + nativeName[0] = destWrote; - c2pstr(name); - resource = GetNamedResource('cicn', (StringPtr) name); + resource = GetNamedResource('cicn', nativeName); if (resource != NULL) { type = TYPE3; } else { - resource = GetNamedResource('ICON', (StringPtr) name); + resource = GetNamedResource('ICON', nativeName); if (resource != NULL) { type = TYPE2; } } - p2cstr((StringPtr) name); if (resource == NULL) { return NULL; diff --git a/mac/tkMacButton.c b/mac/tkMacButton.c index 767baff..287c2ef 100644 --- a/mac/tkMacButton.c +++ b/mac/tkMacButton.c @@ -2,20 +2,21 @@ * tkMacButton.c -- * * This file implements the Macintosh specific portion of the - * button widgets. + * button widgets. * * 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. * - * SCCS: @(#) tkMacButton.c 1.18 97/11/20 18:27:21 + * SCCS: @(#) tkMacButton.c 1.20 98/02/18 10:48:42 */ #include "tkButton.h" #include "tkMacInt.h" #include <Controls.h> #include <LowMem.h> +#include <Appearance.h> /* * Some defines used to control what type of control is drawn. @@ -43,18 +44,36 @@ static CCTabHandle radioTabHandle; static PixMapHandle oldPixPtr; /* + * These functions are used when Appearance is present. + * By embedding all our controls in a userPane control, + * we can color the background of the text in radiobuttons + * and checkbuttons. Thanks to Peter Gontier of Apple DTS + * for help on this one. + */ + +static ControlRef userPaneHandle; +static RGBColor gUserPaneBackground = { ~0, ~0, ~0}; +static pascal OSErr SetUserPaneDrawProc(ControlRef control, + ControlUserPaneDrawProcPtr upp); +static pascal OSErr SetUserPaneSetUpSpecialBackgroundProc(ControlRef control, + ControlUserPaneBackgroundProcPtr upp); +static pascal void UserPaneDraw(ControlRef control, ControlPartCode cpc); +static pascal void UserPaneBackgroundProc(ControlHandle, + ControlBackgroundPtr info); + +/* * Forward declarations for procedures defined later in this file: */ -static int UpdateControlColors _ANSI_ARGS_((TkButton *butPtr, - ControlRef controlHandle, CCTabHandle ccTabHandle, - RGBColor *saveColorPtr)); -static void DrawBufferedControl _ANSI_ARGS_((TkButton *butPtr, - GWorldPtr destPort)); -static void ChangeBackgroundWindowColor _ANSI_ARGS_(( - WindowRef macintoshWindow, RGBColor rgbColor, - RGBColor *oldColor)); -static void ButtonExitProc _ANSI_ARGS_((ClientData clientData)); +static int UpdateControlColors _ANSI_ARGS_((TkButton *butPtr, + ControlRef controlHandle, CCTabHandle ccTabHandle, + RGBColor *saveColorPtr)); +static void DrawBufferedControl _ANSI_ARGS_((TkButton *butPtr, + GWorldPtr destPort)); +static void ChangeBackgroundWindowColor _ANSI_ARGS_(( + WindowRef macintoshWindow, RGBColor rgbColor, + RGBColor *oldColor)); +static void ButtonExitProc _ANSI_ARGS_((ClientData clientData)); /* * The class procedure table for the button widgets. @@ -137,15 +156,16 @@ TkpDisplayButton( } border = butPtr->normalBorder; - if ((butPtr->state == tkDisabledUid) && (butPtr->disabledFg != NULL)) { + if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { gc = butPtr->disabledGC; - } else if ((butPtr->type == TYPE_BUTTON) && (butPtr->state == tkActiveUid)) { + } else if ((butPtr->type == TYPE_BUTTON) + && (butPtr->state == STATE_ACTIVE)) { gc = butPtr->activeTextGC; border = butPtr->activeBorder; } else { gc = butPtr->normalTextGC; } - if ((butPtr->flags & SELECTED) && (butPtr->state != tkActiveUid) + if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE) && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) { border = butPtr->selectBorder; } @@ -173,9 +193,18 @@ TkpDisplayButton( pixmap = Tk_GetPixmap(butPtr->display, Tk_WindowId(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); - Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, - Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); - + /* + * See the comment in UpdateControlColors as to why we use the + * highlightbackground for the border of Macintosh buttons. + */ + + if (butPtr->type == TYPE_BUTTON) { + Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); + } else { + Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); + } if (butPtr->type == TYPE_LABEL) { drawType = DRAW_LABEL; @@ -274,7 +303,7 @@ TkpDisplayButton( * must temporarily modify the GC. */ - if ((butPtr->state == tkDisabledUid) + if ((butPtr->state == STATE_DISABLED) && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) { if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn && (butPtr->selectBorder != NULL)) { @@ -361,7 +390,7 @@ TkpComputeButtonGeometry( * highlight width as there is also one pixel of spacing. */ - if (butPtr->defaultState != tkDisabledUid) { + if (butPtr->defaultState != DEFAULT_DISABLED) { butPtr->inset += butPtr->highlightWidth; } butPtr->indicatorSpace = 0; @@ -388,8 +417,8 @@ TkpComputeButtonGeometry( } else { Tk_FreeTextLayout(butPtr->textLayout); butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, - butPtr->text, -1, butPtr->wrapLength, butPtr->justify, 0, - &butPtr->textWidth, &butPtr->textHeight); + Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, + butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); width = butPtr->textWidth; height = butPtr->textHeight; @@ -491,36 +520,74 @@ DrawBufferedControl( /* * Create a dummy window that we can draw to. We will - * actually replace this windows bitmap with a the one + * actually replace this window's bitmap with the one * we want to draw to at a later time. This window and * the data structures attached to it are only deallocated * on exit of the application. */ - - windowRef = NewCWindow(NULL, &geometry, "\pempty", false, + + windowRef = NewCWindow(NULL, &geometry, "\pempty", false, zoomDocProc, (WindowRef) -1, true, 0); if (windowRef == NULL) { panic("Can't allocate buffer window."); } - + /* * Now add the three standard controls to hidden window. We * only create one of each and reuse them for every widget in * Tk. + * Under Appearance, we have to embed the controls in a UserPane + * control, so that we can color the background text in + * radiobuttons and checkbuttons. */ SetPort(windowRef); - buttonHandle = NewControl(windowRef, &geometry, "\p", - false, 1, 0, 1, pushButProc, (SInt32) 0); - checkHandle = NewControl(windowRef, &geometry, "\p", - false, 1, 0, 1, checkBoxProc, (SInt32) 0); - radioHandle = NewControl(windowRef, &geometry, "\p", - false, 1, 0, 1, radioButProc, (SInt32) 0); - ((CWindowPeek) windowRef)->visible = true; - - buttonTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); - checkTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); - radioTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); + + if (TkMacHaveAppearance()) { + + OSErr err; + ControlRef dontCare; + + /* Adding UserPaneBackgroundProcs to the root control does + * not seem to work, so we have to add another UserPane to + * the root control. + */ + + err = CreateRootControl(windowRef, &dontCare); + if (err != noErr) { + panic("Can't create root control in DrawBufferedControl"); + } + + userPaneHandle = NewControl(windowRef, &geometry, "\p", + true, kControlSupportsEmbedding|kControlHasSpecialBackground, + 0, 1, kControlUserPaneProc, (SInt32) 5); + SetUserPaneSetUpSpecialBackgroundProc(userPaneHandle, + UserPaneBackgroundProc); + SetUserPaneDrawProc(userPaneHandle, UserPaneDraw); + + buttonHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, kControlPushButtonProc, (SInt32) 6); + EmbedControl(buttonHandle, userPaneHandle); + checkHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, kControlCheckBoxProc, (SInt32) 7); + EmbedControl(checkHandle, userPaneHandle); + radioHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, kControlRadioButtonProc, (SInt32) 8); + EmbedControl(radioHandle, userPaneHandle); + ((CWindowPeek) windowRef)->visible = true; + } else { + buttonHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, pushButProc, (SInt32) 0); + checkHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, checkBoxProc, (SInt32) 0); + radioHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, radioButProc, (SInt32) 0); + ((CWindowPeek) windowRef)->visible = true; + + buttonTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); + checkTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); + radioTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); + } /* * Remove our window from the window list. This way our @@ -556,10 +623,29 @@ DrawBufferedControl( } /* + * Now swap in the passed in GWorld for the portBits of our fake + * window. We also adjust various fields in the WindowRecord to make + * the system think this is a normal window. + * Note, we can use DrawControlInCurrentPort under Appearance, so we don't + * need to swap pixmaps. + */ + + if (!TkMacHaveAppearance()) { + ((CWindowPeek) windowRef)->port.portPixMap = destPort->portPixMap; + } + + ((CWindowPeek) windowRef)->port.portRect = destPort->portRect; + RectRgn(((CWindowPeek) windowRef)->port.visRgn, &destPort->portRect); + RectRgn(((CWindowPeek) windowRef)->strucRgn, &destPort->portRect); + RectRgn(((CWindowPeek) windowRef)->updateRgn, &destPort->portRect); + RectRgn(((CWindowPeek) windowRef)->contRgn, &destPort->portRect); + PortChanged(windowRef); + + /* * Set up control in hidden window to match what we need - * to draw in the buffered window. + * to draw in the buffered window. */ - + switch (butPtr->type) { case TYPE_BUTTON: controlHandle = buttonHandle; @@ -574,21 +660,38 @@ DrawBufferedControl( ccTabHandle = checkTabHandle; break; } + (**controlHandle).contrlRect.left = butPtr->inset; (**controlHandle).contrlRect.top = butPtr->inset; (**controlHandle).contrlRect.right = Tk_Width(butPtr->tkwin) - butPtr->inset; (**controlHandle).contrlRect.bottom = Tk_Height(butPtr->tkwin) - butPtr->inset; - if ((**controlHandle).contrlVis != 255) { - (**controlHandle).contrlVis = 255; - } + + /* + * Setting the control visibility by hand does not + * seem to work under Appearance. + */ + + if (TkMacHaveAppearance()) { + SetControlVisibility(controlHandle, true, false); + (**userPaneHandle).contrlRect.left = 0; + (**userPaneHandle).contrlRect.top = 0; + (**userPaneHandle).contrlRect.right = Tk_Width(butPtr->tkwin); + (**userPaneHandle).contrlRect.bottom = Tk_Height(butPtr->tkwin); + } else { + (**controlHandle).contrlVis = 255; + } + + + if (butPtr->flags & SELECTED) { (**controlHandle).contrlValue = 1; } else { (**controlHandle).contrlValue = 0; } - if (butPtr->state == tkActiveUid) { + + if (butPtr->state == STATE_ACTIVE) { switch (butPtr->type) { case TYPE_BUTTON: (**controlHandle).contrlHilite = kControlButtonPart; @@ -600,27 +703,13 @@ DrawBufferedControl( (**controlHandle).contrlHilite = kControlCheckBoxPart; break; } - } else if (butPtr->state == tkDisabledUid) { + } else if (butPtr->state == STATE_DISABLED) { (**controlHandle).contrlHilite = kControlInactivePart; } else { (**controlHandle).contrlHilite = kControlNoPart; } /* - * Now swap in the passed in GWorld for the portBits of our fake - * window. We also adjust various fields in the WindowRecord to make - * the system think this is a normal window. - */ - - ((CWindowPeek) windowRef)->port.portPixMap = destPort->portPixMap; - ((CWindowPeek) windowRef)->port.portRect = destPort->portRect; - RectRgn(((CWindowPeek) windowRef)->port.visRgn, &destPort->portRect); - RectRgn(((CWindowPeek) windowRef)->strucRgn, &destPort->portRect); - RectRgn(((CWindowPeek) windowRef)->updateRgn, &destPort->portRect); - RectRgn(((CWindowPeek) windowRef)->contRgn, &destPort->portRect); - PortChanged(windowRef); - - /* * Before we draw the control we must add the hidden window back to the * main window list. Otherwise, radiobuttons and checkbuttons will draw * incorrectly. I don't really know why - but clearly the control draw @@ -635,14 +724,41 @@ DrawBufferedControl( * to muck with the colors for the port & window to draw the control * with the proper Tk colors. If we need to we also draw a default * ring for buttons. + * Under Appearance, we draw the control directly into destPort, and + * just set the default control data. */ - SetPort(windowRef); + if (TkMacHaveAppearance()) { + SetPort((GrafPort *) destPort); + } else { + SetPort(windowRef); + } + windowColorChanged = UpdateControlColors(butPtr, controlHandle, ccTabHandle, &saveBackColor); - Draw1Control(controlHandle); - if ((butPtr->type == TYPE_BUTTON) && - (butPtr->defaultState == tkActiveUid)) { + + if ((butPtr->type == TYPE_BUTTON) && TkMacHaveAppearance()) { + Boolean isDefault; + + if (butPtr->defaultState == DEFAULT_ACTIVE) { + isDefault = true; + } else { + isDefault = false; + } + SetControlData(controlHandle, kControlNoPart, + kControlPushButtonDefaultTag, + sizeof(isDefault), (Ptr) &isDefault); + } + + if (TkMacHaveAppearance()) { + DrawControlInCurrentPort(userPaneHandle); + } else { + Draw1Control(controlHandle); + } + + if (!TkMacHaveAppearance() && + (butPtr->type == TYPE_BUTTON) && + (butPtr->defaultState == DEFAULT_ACTIVE)) { Rect box = (**controlHandle).contrlRect; RGBColor rgbColor; @@ -652,21 +768,139 @@ DrawBufferedControl( InsetRect(&box, -butPtr->highlightWidth, -butPtr->highlightWidth); FrameRoundRect(&box, 16, 16); } + if (windowColorChanged) { RGBColor dummyColor; ChangeBackgroundWindowColor(windowRef, saveBackColor, &dummyColor); } /* - * Clean up: remove the hidden window from the main window list. + * Clean up: remove the hidden window from the main window list, and + * hide the control we drew. */ + if (TkMacHaveAppearance()) { + SetControlVisibility(controlHandle, false, false); + } else { + (**controlHandle).contrlVis = 0; + } LMSetWindowList((WindowRef) ((CWindowPeek) windowRef)->nextWindow); } /* *-------------------------------------------------------------- * + * SetUserPaneDrawProc -- + * + * Utility function to add a UserPaneDrawProc + * to a userPane control. From MoreControls code + * from Apple DTS. + * + * Results: + * MacOS system error. + * + * Side effects: + * The user pane gets a new UserPaneDrawProc. + * + *-------------------------------------------------------------- + */ +pascal OSErr SetUserPaneDrawProc ( + ControlRef control, + ControlUserPaneDrawProcPtr upp) +{ + ControlUserPaneDrawUPP myControlUserPaneDrawUPP; + myControlUserPaneDrawUPP = NewControlUserPaneDrawProc(upp); + return SetControlData (control, + kControlNoPart, kControlUserPaneDrawProcTag, + sizeof(myControlUserPaneDrawUPP), + (Ptr) &myControlUserPaneDrawUPP); +} + +/* + *-------------------------------------------------------------- + * + * SetUserPaneSetUpSpecialBackgroundProc -- + * + * Utility function to add a UserPaneBackgroundProc + * to a userPane control + * + * Results: + * MacOS system error. + * + * Side effects: + * The user pane gets a new UserPaneBackgroundProc. + * + *-------------------------------------------------------------- + */ +pascal OSErr +SetUserPaneSetUpSpecialBackgroundProc( + ControlRef control, + ControlUserPaneBackgroundProcPtr upp) +{ + ControlUserPaneBackgroundUPP myControlUserPaneBackgroundUPP; + myControlUserPaneBackgroundUPP = NewControlUserPaneBackgroundProc(upp); + return SetControlData (control, kControlNoPart, + kControlUserPaneBackgroundProcTag, + sizeof(myControlUserPaneBackgroundUPP), + (Ptr) &myControlUserPaneBackgroundUPP); +} + +/* + *-------------------------------------------------------------- + * + * UserPaneDraw -- + * + * This function draws the background of the user pane that will + * lie under checkboxes and radiobuttons. + * + * Results: + * None. + * + * Side effects: + * The user pane gets updated to the current color. + * + *-------------------------------------------------------------- + */ +pascal void +UserPaneDraw( + ControlRef control, + ControlPartCode cpc) +{ + Rect contrlRect = (**control).contrlRect; + RGBBackColor (&gUserPaneBackground); + EraseRect (&contrlRect); +} + +/* + *-------------------------------------------------------------- + * + * UserPaneBackgroundProc -- + * + * This function sets up the background of the user pane that will + * lie under checkboxes and radiobuttons. + * + * Results: + * None. + * + * Side effects: + * The user pane background gets set to the current color. + * + *-------------------------------------------------------------- + */ + +pascal void +UserPaneBackgroundProc( + ControlHandle, + ControlBackgroundPtr info) +{ + if (info->colorDevice) { + RGBBackColor (&gUserPaneBackground); + } +} + +/* + *-------------------------------------------------------------- + * * UpdateControlColors -- * * This function will review the colors used to display @@ -674,6 +908,9 @@ DrawBufferedControl( * used we create a custom palette for the button, populate * with the colors for the button and install the palette. * + * Under Appearance, we just set the pointer that will be + * used by the UserPaneDrawProc. + * * Results: * None. * @@ -692,33 +929,50 @@ UpdateControlColors( { XColor *xcolor; - xcolor = Tk_3DBorderColor(butPtr->normalBorder); - - (**ccTabHandle).ccSeed = 0; - (**ccTabHandle).ccRider = 0; - (**ccTabHandle).ctSize = 3; - (**ccTabHandle).ctTable[0].value = cBodyColor; - TkSetMacColor(xcolor->pixel, - &(**ccTabHandle).ctTable[0].rgb); - (**ccTabHandle).ctTable[1].value = cTextColor; - TkSetMacColor(butPtr->normalFg->pixel, - &(**ccTabHandle).ctTable[1].rgb); - (**ccTabHandle).ctTable[2].value = cFrameColor; - TkSetMacColor(butPtr->highlightColorPtr->pixel, - &(**ccTabHandle).ctTable[2].rgb); - SetControlColor(controlHandle, ccTabHandle); - - if (((xcolor->pixel >> 24) != CONTROL_BODY_PIXEL) && - ((butPtr->type == TYPE_CHECK_BUTTON) || - (butPtr->type == TYPE_RADIO_BUTTON))) { - RGBColor newColor; + /* + * Under Appearance we cannot change the background of the + * button itself. However, the color we are setting is the color + * of the containing userPane. This will be the color that peeks + * around the rounded corners of the button. + * We make this the highlightbackground rather than the background, + * because if you color the background of a frame containing a + * button, you usually also color the highlightbackground as well, + * or you will get a thin grey ring around the button. + */ + + if (TkMacHaveAppearance() && (butPtr->type == TYPE_BUTTON)) { + xcolor = Tk_3DBorderColor(butPtr->highlightBorder); + } else { + xcolor = Tk_3DBorderColor(butPtr->normalBorder); + } + if (TkMacHaveAppearance()) { + TkSetMacColor(xcolor->pixel, &gUserPaneBackground); + } else { + (**ccTabHandle).ccSeed = 0; + (**ccTabHandle).ccRider = 0; + (**ccTabHandle).ctSize = 3; + (**ccTabHandle).ctTable[0].value = cBodyColor; + TkSetMacColor(xcolor->pixel, + &(**ccTabHandle).ctTable[0].rgb); + (**ccTabHandle).ctTable[1].value = cTextColor; + TkSetMacColor(butPtr->normalFg->pixel, + &(**ccTabHandle).ctTable[1].rgb); + (**ccTabHandle).ctTable[2].value = cFrameColor; + TkSetMacColor(butPtr->highlightColorPtr->pixel, + &(**ccTabHandle).ctTable[2].rgb); + SetControlColor(controlHandle, ccTabHandle); + if (((xcolor->pixel >> 24) != CONTROL_BODY_PIXEL) && + ((butPtr->type == TYPE_CHECK_BUTTON) || + (butPtr->type == TYPE_RADIO_BUTTON))) { + RGBColor newColor; - TkSetMacColor(xcolor->pixel, &newColor); - ChangeBackgroundWindowColor((**controlHandle).contrlOwner, - newColor, saveColorPtr); - return true; + TkSetMacColor(xcolor->pixel, &newColor); + ChangeBackgroundWindowColor((**controlHandle).contrlOwner, + newColor, saveColorPtr); + return true; + } } - + return false; } diff --git a/mac/tkMacClipboard.c b/mac/tkMacClipboard.c index 0c06f1d..1ae497c 100644 --- a/mac/tkMacClipboard.c +++ b/mac/tkMacClipboard.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacClipboard.c 1.18 97/05/01 15:41:17 + * SCCS: @(#) tkMacClipboard.c 1.19 97/11/07 21:21:42 */ #include "tkInt.h" @@ -32,7 +32,7 @@ * 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: * None. diff --git a/mac/tkMacConfig.c b/mac/tkMacConfig.c new file mode 100644 index 0000000..83da6cf --- /dev/null +++ b/mac/tkMacConfig.c @@ -0,0 +1,45 @@ +/* + * tkMacConfig.c -- + * + * This module implements the Macintosh system defaults for + * the configuration package. + * + * Copyright (c) 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. + * + * SCCS: @(#) tkMacConfig.c 1.3 97/10/08 10:07:55 + */ + +#include "tk.h" +#include "tkInt.h" + + +/* + *---------------------------------------------------------------------- + * + * TkpGetSystemDefault -- + * + * Given a dbName and className for a configuration option, + * return a string representation of the option. + * + * Results: + * Returns a Tk_Uid that is the string identifier that identifies + * this option. Returns NULL if there are no system defaults + * that match this pair. + * + * Side effects: + * None, once the package is initialized. + * + *---------------------------------------------------------------------- + */ + +Tcl_Obj * +TkpGetSystemDefault( + Tk_Window tkwin, /* A window to use. */ + char *dbName, /* The option database name. */ + char *className) /* The name of the option class. */ +{ + return NULL; +} diff --git a/mac/tkMacCursor.c b/mac/tkMacCursor.c index f221189..3f34434 100644 --- a/mac/tkMacCursor.c +++ b/mac/tkMacCursor.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacCursor.c 1.20 97/09/17 19:33:13 + * SCCS: @(#) tkMacCursor.c 1.24 98/01/22 17:00:29 */ #include "tkPort.h" @@ -64,9 +64,16 @@ static struct CursorName { static TkMacCursor * gCurrentCursor = NULL; /* A pointer to the current * cursor. */ -static int gResizeOverride = false; /* A boolean indicating wether +static int gResizeOverride = false; /* A boolean indicating whether * we should use the resize * cursor during installations. */ +static int gTkOwnsCursor = true; /* A boolean indicating whether + Tk owns the cursor. If not (for + instance, in the case where a Tk + window is embedded in another app's + window, and the cursor is out of + the tk window, we will not attempt + to adjust the cursor */ /* * Declarations of procedures local to this file @@ -102,13 +109,23 @@ FindCursorByName( { Handle resource; Str255 curName; + int destWrote, inCurLen; - curName[0] = strlen(string); - if (curName[0] > 255) { + inCurLen = strlen(string); + if (inCurLen > 255) { return; } - - strcpy((char *) curName + 1, string); + + /* + * macRoman is the encoding that the resource fork uses. + */ + + Tcl_UtfToExternal(NULL, Tcl_GetEncoding(NULL, "macRoman"), string, + inCurLen, 0, NULL, + (char *) &curName[1], + 255, NULL, &destWrote, NULL); /* Internalize native */ + curName[0] = destWrote; + resource = GetNamedResource('crsr', curName); if (resource != NULL) { @@ -245,7 +262,7 @@ TkCreateCursorFromData( /* *---------------------------------------------------------------------- * - * TkFreeCursor -- + * TkpFreeCursor -- * * This procedure is called to release a cursor allocated by * TkGetCursorByName. @@ -260,7 +277,7 @@ TkCreateCursorFromData( */ void -TkFreeCursor( +TkpFreeCursor( TkCursor *cursorPtr) { TkMacCursor *macCursorPtr = (TkMacCursor *) cursorPtr; @@ -277,8 +294,6 @@ TkFreeCursor( if (macCursorPtr == gCurrentCursor) { gCurrentCursor = NULL; } - - ckfree((char *) macCursorPtr); } /* @@ -348,6 +363,9 @@ void TkpSetCursor( TkpCursor cursor) { + if (!gTkOwnsCursor) { + return; + } if (cursor == None) { gCurrentCursor = NULL; } else { @@ -358,3 +376,25 @@ TkpSetCursor( TkMacInstallCursor(gResizeOverride); } } + +/* + *---------------------------------------------------------------------- + * + * Tk_MacTkOwnsCursor -- + * + * Sets whether Tk has the right to adjust the cursor. + * + * Results: + * None. + * + * Side effects: + * May keep Tk from changing the cursor. + * + *---------------------------------------------------------------------- + */ + +void Tk_MacTkOwnsCursor( + int tkOwnsIt) +{ + gTkOwnsCursor = tkOwnsIt; +} diff --git a/mac/tkMacDefault.h b/mac/tkMacDefault.h index 372d89b..da574fd 100644 --- a/mac/tkMacDefault.h +++ b/mac/tkMacDefault.h @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacDefault.h 1.48 97/10/09 17:45:04 + * SCCS: @(#) tkMacDefault.h 1.49 98/01/08 13:18:41 */ #ifndef _TKMACDEFAULT @@ -61,7 +61,8 @@ #define DEF_CHKRAD_FG DEF_BUTTON_FG #define DEF_BUTTON_FONT "system" #define DEF_BUTTON_HEIGHT "0" -#define DEF_BUTTON_HIGHLIGHT_BG NORMAL_BG +#define DEF_BUTTON_HIGHLIGHT_BG_COLOR DEF_BUTTON_BG_COLOR +#define DEF_BUTTON_HIGHLIGHT_BG_MONO DEF_BUTTON_BG_MONO #define DEF_BUTTON_HIGHLIGHT "systemButtonFrame" #define DEF_LABEL_HIGHLIGHT_WIDTH "0" #define DEF_BUTTON_HIGHLIGHT_WIDTH "4" diff --git a/mac/tkMacDialog.c b/mac/tkMacDialog.c index 43d11a5..e1031d9 100644 --- a/mac/tkMacDialog.c +++ b/mac/tkMacDialog.c @@ -3,13 +3,12 @@ * * Contains the Mac implementation of the common dialog boxes. * - * 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. * - * SCCS: @(#) tkMacDialog.c 1.12 96/12/03 11:15:12 - * + * SCCS: @(#) tkMacDialog.c 1.20 97/11/07 21:23:36 */ #include <Gestalt.h> @@ -26,6 +25,13 @@ #include "tclMacInt.h" #include "tkFileFilter.h" +#ifndef StrLength +#define StrLength(s) (*((unsigned char *) (s))) +#endif +#ifndef StrBody +#define StrBody(s) ((char *) (s) + 1) +#endif + /* * The following are ID's for resources that are defined in tkMacResource.r */ @@ -45,38 +51,27 @@ * information about the file dialog and the file filters. */ typedef struct _OpenFileData { - Tcl_Interp * interp; - char * initialFile; /* default file to appear in the - * save dialog */ - char * defExt; /* default extension (not used on the - * Mac) */ FileFilterList fl; /* List of file filters. */ SInt16 curType; /* The filetype currently being - * listed */ - int isOpen; /* True if this is an Open dialog, - * false if it is a Save dialog. */ - MenuHandle menu; /* Handle of the menu in the popup*/ - short dialogId; /* resource ID of the dialog */ - int popupId; /* resource ID of the popup */ - short popupItem; /* item number of the popup in the - * dialog */ + * listed. */ + short popupItem; /* Item number of the popup in the + * dialog. */ int usePopup; /* True if we show the popup menu (this * is an open operation and the - * -filetypes option is set) - */ + * -filetypes option is set). */ } OpenFileData; static pascal Boolean FileFilterProc _ANSI_ARGS_((CInfoPBPtr pb, void *myData)); -static int GetFileName _ANSI_ARGS_ (( - ClientData clientData, Tcl_Interp *interp, - int argc, char **argv, int isOpen )); +static int GetFileName _ANSI_ARGS_ ((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[], int isOpen)); static Boolean MatchOneType _ANSI_ARGS_((CInfoPBPtr pb, - OpenFileData * myDataPtr, FileFilter * filterPtr)); + OpenFileData *myofdPtr, FileFilter *filterPtr)); static pascal short OpenHookProc _ANSI_ARGS_((short item, - DialogPtr theDialog, OpenFileData * myDataPtr)); + DialogPtr theDialog, OpenFileData * myofdPtr)); static int ParseFileDlgArgs _ANSI_ARGS_ ((Tcl_Interp * interp, - OpenFileData * myDataPtr, int argc, char ** argv, + OpenFileData * myofdPtr, int argc, char ** argv, int isOpen)); /* @@ -92,68 +87,7 @@ static DlgHookYDUPP saveHook = NULL; /* *---------------------------------------------------------------------- * - * EvalArgv -- - * - * Invokes the Tcl procedure with the arguments. argv[0] is set by - * the caller of this function. It may be different than cmdName. - * The TCL command will see argv[0], not cmdName, as its name if it - * invokes [lindex [info level 0] 0] - * - * Results: - * TCL_ERROR if the command does not exist and cannot be autoloaded. - * Otherwise, return the result of the evaluation of the command. - * - * Side effects: - * The command may be autoloaded. - * - *---------------------------------------------------------------------- - */ - -static int -EvalArgv( - Tcl_Interp *interp, /* Current interpreter. */ - char * cmdName, /* Name of the TCL command to call */ - int argc, /* Number of arguments. */ - char **argv) /* Argument strings. */ -{ - Tcl_CmdInfo cmdInfo; - - if (!Tcl_GetCommandInfo(interp, cmdName, &cmdInfo)) { - char * cmdArgv[2]; - - /* - * This comand is not in the interpreter yet -- looks like we - * have to auto-load it - */ - if (!Tcl_GetCommandInfo(interp, "auto_load", &cmdInfo)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "cannot execute command \"auto_load\"", - NULL); - return TCL_ERROR; - } - - cmdArgv[0] = "auto_load"; - cmdArgv[1] = cmdName; - - if ((*cmdInfo.proc)(cmdInfo.clientData, interp, 2, cmdArgv)!= TCL_OK){ - return TCL_ERROR; - } - - if (!Tcl_GetCommandInfo(interp, cmdName, &cmdInfo)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "cannot auto-load command \"", - cmdName, "\"",NULL); - return TCL_ERROR; - } - } - - return (*cmdInfo.proc)(cmdInfo.clientData, interp, argc, argv); -} - -/* - *---------------------------------------------------------------------- - * - * Tk_ChooseColorCmd -- + * Tk_ChooseColorObjCmd -- * * This procedure implements the color dialog box for the Mac * platform. See the user documentation for details on what it @@ -169,23 +103,86 @@ EvalArgv( */ int -Tk_ChooseColorCmd( +Tk_ChooseColorObjCmd( 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 parent = Tk_MainWindow(interp); - char * colorStr = NULL; - XColor * colorPtr = NULL; - char * title = "Choose a color:"; - int i, version; - long response = 0; - OSErr err = noErr; - char buff[40]; - static RGBColor in; + Tk_Window parent; + char *title; + int i, picked, srcRead, dstWrote; + long response; + OSErr err; static inited = 0; - + static RGBColor in; + static char *optionStrings[] = { + "-initialcolor", "-parent", "-title", NULL + }; + enum options { + COLOR_INITIAL, COLOR_PARENT, COLOR_TITLE + }; + + if (inited == 0) { + /* + * 'in' stores the last color picked. The next time the color dialog + * pops up, the last color will remain in the dialog. + */ + + in.red = 0xffff; + in.green = 0xffff; + in.blue = 0xffff; + inited = 1; + } + + parent = (Tk_Window) clientData; + title = "Choose a color:"; + picked = 0; + + for (i = 1; i < objc; i += 2) { + int index; + char *option, *value; + + if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, "option", + TCL_EXACT, &index) != TCL_OK) { + return TCL_ERROR; + } + if (i + 1 == objc) { + option = Tcl_GetStringFromObj(objv[i], NULL); + Tcl_AppendResult(interp, "value for \"", option, "\" missing", + (char *) NULL); + return TCL_ERROR; + } + value = Tcl_GetStringFromObj(objv[i + 1], NULL); + + switch ((enum options) index) { + case COLOR_INITIAL: { + XColor *colorPtr; + + colorPtr = Tk_GetColor(interp, parent, value); + if (colorPtr == NULL) { + return TCL_ERROR; + } + in.red = colorPtr->red; + in.green = colorPtr->green; + in.blue = colorPtr->blue; + Tk_FreeColor(colorPtr); + break; + } + case COLOR_PARENT: { + parent = Tk_NameToWindow(interp, value, parent); + if (parent == NULL) { + return TCL_ERROR; + } + break; + } + case COLOR_TITLE: { + title = value; + break; + } + } + } + /* * Use the gestalt manager to determine how to bring * up the color picker. If versin 2.0 isn't available @@ -194,92 +191,12 @@ Tk_ChooseColorCmd( */ err = Gestalt(gestaltColorPicker, &response); - if ((err == noErr) || (response == 0x0200L)) { - version = 2; - } else { - version = 1; - } - - for (i=1; i<argc; i+=2) { - int v = i+1; - int len = strlen(argv[i]); - - if (strncmp(argv[i], "-initialcolor", len)==0) { - if (v==argc) {goto arg_missing;} - - colorStr = argv[v]; - } else if (strncmp(argv[i], "-parent", len)==0) { - if (v==argc) {goto arg_missing;} - - parent=Tk_NameToWindow(interp, argv[v], Tk_MainWindow(interp)); - if (parent == NULL) { - return TCL_ERROR; - } - } else if (strncmp(argv[i], "-title", len)==0) { - if (v==argc) {goto arg_missing;} - - title = argv[v]; - } else { - Tcl_AppendResult(interp, "unknown option \"", - argv[i], "\", must be -initialcolor, -parent or -title", - NULL); - return TCL_ERROR; - } - } - - if (colorStr) { - colorPtr = Tk_GetColor(interp, parent, colorStr); - if (colorPtr == NULL) { - return TCL_ERROR; - } - } - - if (!inited) { - inited = 1; - in.red = 0xffff; - in.green = 0xffff; - in.blue = 0xffff; - } - if (colorPtr) { - in.red = colorPtr->red; - in.green = colorPtr->green; - in.blue = colorPtr->blue; - } - - if (version == 1) { - /* - * Use version 1.0 of the color picker - */ - - RGBColor out; - Str255 prompt; - Point point = {-1, -1}; - - prompt[0] = strlen(title); - strncpy((char*) prompt+1, title, 255); - - if (GetColor(point, prompt, &in, &out)) { - /* - * user selected a color - */ - sprintf(buff, "#%02x%02x%02x", out.red >> 8, out.green >> 8, - out.blue >> 8); - Tcl_SetResult(interp, buff, TCL_VOLATILE); + if ((err == noErr) && (response == 0x0200L)) { + ColorPickerInfo cpinfo; - /* - * Save it for the next time - */ - in.red = out.red; - in.green = out.green; - in.blue = out.blue; - } else { - Tcl_ResetResult(interp); - } - } else { /* * Version 2.0 of the color picker is available. Let's use it */ - ColorPickerInfo cpinfo; cpinfo.theColor.profile = 0L; cpinfo.theColor.color.rgb.red = in.red; @@ -292,41 +209,50 @@ Tk_ChooseColorCmd( cpinfo.eventProc = NULL; cpinfo.colorProc = NULL; cpinfo.colorProcData = NULL; + + Tcl_UtfToExternal(NULL, NULL, title, -1, 0, NULL, + StrBody(cpinfo.prompt), 255, &srcRead, &dstWrote, NULL); + StrLength(cpinfo.prompt) = (unsigned char) dstWrote; + + if ((PickColor(&cpinfo) == noErr) && (cpinfo.newColorChosen != 0)) { + in.red = cpinfo.theColor.color.rgb.red; + in.green = cpinfo.theColor.color.rgb.green; + in.blue = cpinfo.theColor.color.rgb.blue; + picked = 1; + } + } else { + RGBColor out; + Str255 prompt; + Point point = {-1, -1}; + + /* + * Use version 1.0 of the color picker + */ + + Tcl_UtfToExternal(NULL, NULL, title, -1, 0, NULL, StrBody(prompt), + 255, &srcRead, &dstWrote, NULL); + StrLength(prompt) = (unsigned char) dstWrote; - cpinfo.prompt[0] = strlen(title); - strncpy((char*)cpinfo.prompt+1, title, 255); - - if ((PickColor(&cpinfo) == noErr) && cpinfo.newColorChosen) { - sprintf(buff, "#%02x%02x%02x", - cpinfo.theColor.color.rgb.red >> 8, - cpinfo.theColor.color.rgb.green >> 8, - cpinfo.theColor.color.rgb.blue >> 8); - Tcl_SetResult(interp, buff, TCL_VOLATILE); - - in.blue = cpinfo.theColor.color.rgb.red; - in.green = cpinfo.theColor.color.rgb.green; - in.blue = cpinfo.theColor.color.rgb.blue; - } else { - Tcl_ResetResult(interp); + if (GetColor(point, prompt, &in, &out)) { + in = out; + picked = 1; } - } + } + + if (picked != 0) { + char result[32]; - if (colorPtr) { - Tk_FreeColor(colorPtr); + sprintf(result, "#%02x%02x%02x", in.red >> 8, in.green >> 8, + in.blue >> 8); + Tcl_AppendResult(interp, result, NULL); } - return TCL_OK; - - arg_missing: - Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing", - NULL); - return TCL_ERROR; } /* *---------------------------------------------------------------------- * - * Tk_GetOpenFileCmd -- + * Tk_GetOpenFileObjCmd -- * * This procedure implements the "open file" dialog box for the * Mac platform. See the user documentation for details on what @@ -341,19 +267,19 @@ Tk_ChooseColorCmd( */ int -Tk_GetOpenFileCmd( +Tk_GetOpenFileObjCmd( 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 GetFileName(clientData, interp, argc, argv, OPEN_FILE); + return GetFileName(clientData, interp, objc, objv, OPEN_FILE); } /* *---------------------------------------------------------------------- * - * Tk_GetSaveFileCmd -- + * Tk_GetSaveFileObjCmd -- * * Same as Tk_GetOpenFileCmd but opens a "save file" dialog box * instead @@ -367,13 +293,13 @@ Tk_GetOpenFileCmd( */ int -Tk_GetSaveFileCmd( +Tk_GetSaveFileObjCmd( 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 GetFileName(clientData, interp, argc, argv, SAVE_FILE); + return GetFileName(clientData, interp, objc, objv, SAVE_FILE); } /* @@ -389,8 +315,8 @@ Tk_GetSaveFileCmd( * * Side effects: * If the user selects a file, the native pathname of the file - * is returned in interp->result. Otherwise an empty string - * is returned in interp->result. + * is returned in the interp's result. Otherwise an empty string + * is returned in the interp's result. * *---------------------------------------------------------------------- */ @@ -399,32 +325,124 @@ static int GetFileName( 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 isOpen) /* true if we should call GetOpenFileName(), * false if we should call GetSaveFileName() */ { - int code = TCL_OK; - int i; - OpenFileData myData, *myDataPtr; + int i, result; + OpenFileData ofd; StandardFileReply reply; Point mypoint; - Str255 str; - - myDataPtr = &myData; + MenuHandle menu; + Str255 initialFile; + char *choice[6]; + Tk_Window parent; + static char *optionStrings[] = { + "-defaultextension", "-filetypes", "-initialdir", "-initialfile", + "-parent", "-title", NULL + }; + enum options { + FILE_DEFAULT, FILE_TYPES, FILE_INITDIR, FILE_INITFILE, + FILE_PARENT, FILE_TITLE + }; if (openFilter == NULL) { openFilter = NewFileFilterYDProc(FileFilterProc); openHook = NewDlgHookYDProc(OpenHookProc); saveHook = NewDlgHookYDProc(OpenHookProc); } + + result = TCL_ERROR; + parent = (Tk_Window) clientData; + memset(choice, 0, sizeof(choice)); - /* - * 1. Parse the arguments. - */ - if (ParseFileDlgArgs(interp, myDataPtr, argc, argv, isOpen) - != TCL_OK) { - return TCL_ERROR; + for (i = 1; i < objc; i += 2) { + int index; + char *string; + + if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, "option", + TCL_EXACT, &index) != TCL_OK) { + return TCL_ERROR; + } + if (i + 1 == objc) { + string = Tcl_GetStringFromObj(objv[i], NULL); + Tcl_AppendResult(interp, "value for \"", string, "\" missing", + (char *) NULL); + return TCL_ERROR; + } + choice[index] = Tcl_GetStringFromObj(objv[i + 1], NULL); + } + + StrLength(initialFile) = 0; + menu = NULL; + + TkInitFileFilters(&ofd.fl); + ofd.curType = 0; + ofd.popupItem = OPEN_POPUP_ITEM; + ofd.usePopup = isOpen; + + if (choice[FILE_TYPES] != NULL) { + if (TkGetFileFilters(interp, &ofd.fl, choice[FILE_TYPES], 0) != TCL_OK) { + goto end; + } + } + if (choice[FILE_INITDIR] != NULL) { + FSSpec dirSpec; + Tcl_DString ds; + long dirID; + OSErr err; + Boolean isDirectory; + char *string; + Str255 dir; + int srcRead, dstWrote; + + string = choice[FILE_INITDIR]; + if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { + goto end; + } + Tcl_UtfToExternal(NULL, NULL, Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds), 0, NULL, StrBody(dir), 255, + &srcRead, &dstWrote, NULL); + StrLength(dir) = (unsigned char) dstWrote; + Tcl_DStringFree(&ds); + + err = FSpLocationFromPath(StrLength(dir), StrBody(dir), &dirSpec); + if (err != noErr) { + Tcl_AppendResult(interp, "bad directory \"", string, "\"", NULL); + goto end; + } + err = FSpGetDirectoryID(&dirSpec, &dirID, &isDirectory); + if ((err != noErr) || !isDirectory) { + Tcl_AppendResult(interp, "bad directory \"", string, "\"", NULL); + goto end; + } + /* + * Make sure you negate -dirSpec.vRefNum because the + * standard file package wants it that way ! + */ + + LMSetSFSaveDisk(-dirSpec.vRefNum); + LMSetCurDirStore(dirID); + } + if (choice[FILE_INITFILE] != NULL) { + Tcl_DString ds; + int srcRead, dstWrote; + + if (Tcl_TranslateFileName(interp, choice[FILE_INITFILE], &ds) == NULL) { + goto end; + } + Tcl_UtfToExternal(NULL, NULL, Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds), 0, NULL, + StrBody(initialFile), 255, &srcRead, &dstWrote, NULL); + StrLength(initialFile) = (unsigned char) dstWrote; + Tcl_DStringFree(&ds); + } + if (choice[FILE_PARENT] != NULL) { + parent = Tk_NameToWindow(interp, choice[FILE_PARENT], parent); + if (parent == NULL) { + return TCL_ERROR; + } } /* @@ -436,237 +454,89 @@ GetFileName( * left overs from previous invocation of this command */ - if (myDataPtr->usePopup) { - FileFilter * filterPtr; - - for (i=CountMItems(myDataPtr->menu); i>0; i--) { + if (ofd.usePopup) { + FileFilter *filterPtr; + + menu = GetMenu(OPEN_MENU); + for (i = CountMItems(menu); i > 0; i--) { /* * The item indices are one based. Also, if we delete from * the beginning, the items may be re-numbered. So we * delete from the end */ - DeleteMenuItem(myDataPtr->menu, i); + + DeleteMenuItem(menu, i); } - if (myDataPtr->fl.filters) { - for (filterPtr=myDataPtr->fl.filters; filterPtr; - filterPtr=filterPtr->next) { - strncpy((char*)str+1, filterPtr->name, 254); - str[0] = strlen(filterPtr->name); - AppendMenu(myDataPtr->menu, (ConstStr255Param) str); - } + filterPtr = ofd.fl.filters; + if (filterPtr == NULL) { + ofd.usePopup = 0; } else { - myDataPtr->usePopup = 0; + for ( ; filterPtr != NULL; filterPtr = filterPtr->next) { + Str255 str; + + StrLength(str) = (unsigned char) strlen(filterPtr->name); + strcpy(StrBody(str), filterPtr->name); + AppendMenu(menu, str); + } } } /* * 3. Call the toolbox file dialog function. */ + SetPt(&mypoint, -1, -1); TkpSetCursor(NULL); - - if (myDataPtr->isOpen) { - if (myDataPtr->usePopup) { - CustomGetFile(openFilter, (short) -1, NULL, &reply, - myDataPtr->dialogId, - mypoint, openHook, NULL, NULL, NULL, (void*)myDataPtr); + if (isOpen) { + if (ofd.usePopup) { + CustomGetFile(openFilter, (short) -1, NULL, &reply, OPEN_BOX, + mypoint, openHook, NULL, NULL, NULL, (void*) &ofd); } else { StandardGetFile(NULL, -1, NULL, &reply); } } else { - Str255 prompt, def; - - strcpy((char*)prompt+1, "Save as"); - prompt[0] = strlen("Save as"); - if (myDataPtr->initialFile) { - strncpy((char*)def+1, myDataPtr->initialFile, 254); - def[0] = strlen(myDataPtr->initialFile); - } else { - def[0] = 0; - } - if (myDataPtr->usePopup) { + static Str255 prompt = "\pSave as"; + + if (ofd.usePopup) { /* * Currently this never gets called because we don't use * popup for the save dialog. */ - CustomPutFile(prompt, def, &reply, myDataPtr->dialogId, mypoint, - saveHook, NULL, NULL, NULL, myDataPtr); + CustomPutFile(prompt, initialFile, &reply, OPEN_BOX, + mypoint, saveHook, NULL, NULL, NULL, (void *) &ofd); } else { - StandardPutFile(prompt, def, &reply); + StandardPutFile(prompt, initialFile, &reply); } } - Tcl_ResetResult(interp); if (reply.sfGood) { int length; - Handle pathHandle = NULL; - char * pathName = NULL; + Handle pathHandle; + pathHandle = NULL; FSpPathFromLocation(&reply.sfFile, &length, &pathHandle); - if (pathHandle != NULL) { + Tcl_DString ds; + HLock(pathHandle); - pathName = (char *) ckalloc((unsigned) (length + 1)); - strcpy(pathName, *pathHandle); + Tcl_ExternalToUtfDString(NULL, (char *) *pathHandle, -1, &ds); + Tcl_AppendResult(interp, Tcl_DStringValue(&ds), NULL); + Tcl_DStringFree(&ds); HUnlock(pathHandle); DisposeHandle(pathHandle); - - /* - * Return the full pathname of the selected file - */ - - Tcl_SetResult(interp, pathName, TCL_DYNAMIC); } } - - done: - TkFreeFileFilters(&myDataPtr->fl); - return code; -} - -/* - *---------------------------------------------------------------------- - * - * ParseFileDlgArgs -- - * - * Parses the arguments passed to tk_getOpenFile and tk_getSaveFile. - * - * Results: - * A standard TCL return value. - * - * Side effects: - * The OpenFileData structure is initialized and modified according - * to the arguments. - * - *---------------------------------------------------------------------- - */ - -static int -ParseFileDlgArgs( - Tcl_Interp * interp, /* Current interpreter. */ - OpenFileData * myDataPtr, /* Information about the file dialog */ - int argc, /* Number of arguments */ - char ** argv, /* Argument strings */ - int isOpen) /* TRUE if this is an "open" dialog */ -{ - int i; - - myDataPtr->interp = interp; - myDataPtr->initialFile = NULL; - myDataPtr->curType = 0; - - TkInitFileFilters(&myDataPtr->fl); - if (isOpen) { - myDataPtr->isOpen = 1; - myDataPtr->usePopup = 1; - myDataPtr->menu = GetMenu(OPEN_MENU); - myDataPtr->dialogId = OPEN_BOX; - myDataPtr->popupId = OPEN_POPUP; - myDataPtr->popupItem = OPEN_POPUP_ITEM; - if (myDataPtr->menu == NULL) { - Debugger(); - } - } else { - myDataPtr->isOpen = 0; - myDataPtr->usePopup = 0; - } - - for (i=1; i<argc; i+=2) { - int v = i+1; - int len = strlen(argv[i]); - - if (strncmp(argv[i], "-defaultextension", len)==0) { - if (v==argc) {goto arg_missing;} + result = TCL_OK; - myDataPtr->defExt = argv[v]; - } - else if (strncmp(argv[i], "-filetypes", len)==0) { - if (v==argc) {goto arg_missing;} - - if (TkGetFileFilters(interp, &myDataPtr->fl,argv[v],0) != TCL_OK) { - return TCL_ERROR; - } - } - else if (strncmp(argv[i], "-initialdir", len)==0) { - FSSpec dirSpec; - char * dirName; - Tcl_DString dstring; - long dirID; - OSErr err; - Boolean isDirectory; - - if (v==argc) {goto arg_missing;} - - if (Tcl_TranslateFileName(interp, argv[v], &dstring) == NULL) { - return TCL_ERROR; - } - dirName = dstring.string; - if (FSpLocationFromPath(strlen(dirName), dirName, &dirSpec) != - noErr) { - Tcl_AppendResult(interp, "bad directory \"", argv[v], - "\"", NULL); - return TCL_ERROR; - } - err = FSpGetDirectoryID(&dirSpec, &dirID, &isDirectory); - if ((err != noErr) || !isDirectory) { - Tcl_AppendResult(interp, "bad directory \"", argv[v], - "\"", NULL); - return TCL_ERROR; - } - /* - * Make sure you negate -dirSpec.vRefNum because the standard file - * package wants it that way ! - */ - LMSetSFSaveDisk(-dirSpec.vRefNum); - LMSetCurDirStore(dirID); - Tcl_DStringFree(&dstring); - } - else if (strncmp(argv[i], "-initialfile", len)==0) { - if (v==argc) {goto arg_missing;} - - myDataPtr->initialFile = argv[v]; - } - else if (strncmp(argv[i], "-parent", len)==0) { - /* - * Ignored on the Mac, but make sure that it's a valid window - * pathname - */ - Tk_Window parent; - - if (v==argc) {goto arg_missing;} - - parent=Tk_NameToWindow(interp, argv[v], Tk_MainWindow(interp)); - if (parent == NULL) { - return TCL_ERROR; - } - } - else if (strncmp(argv[i], "-title", len)==0) { - if (v==argc) {goto arg_missing;} - - /* - * This option is ignored on the Mac because the Mac file - * dialog do not support titles. - */ - } - else { - Tcl_AppendResult(interp, "unknown option \"", - argv[i], "\", must be -defaultextension, ", - "-filetypes, -initialdir, -initialfile, -parent or -title", - NULL); - return TCL_ERROR; - } + end: + TkFreeFileFilters(&ofd.fl); + if (menu != NULL) { + DisposeMenu(menu); } - - return TCL_OK; - - arg_missing: - Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing", - NULL); - return TCL_ERROR; + return result; } - /* *---------------------------------------------------------------------- * @@ -689,7 +559,7 @@ static pascal short OpenHookProc( short item, /* Event description. */ DialogPtr theDialog, /* The dialog where the event occurs. */ - OpenFileData * myDataPtr) /* Information about the file dialog. */ + OpenFileData *ofdPtr) /* Information about the file dialog. */ { short ignore; Rect rect; @@ -698,29 +568,29 @@ OpenHookProc( switch (item) { case sfHookFirstCall: - if (myDataPtr->usePopup) { + if (ofdPtr->usePopup) { /* * Set the popup list to display the selected type. */ - GetDialogItem(theDialog, myDataPtr->popupItem, - &ignore, &handle, &rect); - SetControlValue((ControlRef) handle, myDataPtr->curType + 1); + GetDialogItem(theDialog, ofdPtr->popupItem, &ignore, &handle, + &rect); + SetControlValue((ControlRef) handle, ofdPtr->curType + 1); } return sfHookNullEvent; case OPEN_POPUP_ITEM: - if (myDataPtr->usePopup) { - GetDialogItem(theDialog, myDataPtr->popupItem, + if (ofdPtr->usePopup) { + GetDialogItem(theDialog, ofdPtr->popupItem, &ignore, &handle, &rect); newType = GetCtlValue((ControlRef) handle) - 1; - if (myDataPtr->curType != newType) { - if (newType<0 || newType>myDataPtr->fl.numFilters) { + if (ofdPtr->curType != newType) { + if (newType<0 || newType>ofdPtr->fl.numFilters) { /* * Sanity check. Looks like the user selected an * non-existent menu item?? Don't do anything. */ } else { - myDataPtr->curType = newType; + ofdPtr->curType = newType; } return sfHookRebuildList; } @@ -755,10 +625,10 @@ FileFilterProc( void *myData) /* Client data for this file dialog */ { int i; - OpenFileData * myDataPtr = (OpenFileData*)myData; + OpenFileData * ofdPtr = (OpenFileData*)myData; FileFilter * filterPtr; - if (myDataPtr->fl.numFilters == 0) { + if (ofdPtr->fl.numFilters == 0) { /* * No types have been specified. List all files by default */ @@ -772,13 +642,13 @@ FileFilterProc( return MATCHED; } - if (myDataPtr->usePopup) { - i = myDataPtr->curType; - for (filterPtr=myDataPtr->fl.filters; filterPtr && i>0; i--) { + if (ofdPtr->usePopup) { + i = ofdPtr->curType; + for (filterPtr=ofdPtr->fl.filters; filterPtr && i>0; i--) { filterPtr = filterPtr->next; } if (filterPtr) { - return MatchOneType(pb, myDataPtr, filterPtr); + return MatchOneType(pb, ofdPtr, filterPtr); } else { return UNMATCHED; } @@ -788,9 +658,9 @@ FileFilterProc( * considered matched if it matches any of the file filters. */ - for (filterPtr=myDataPtr->fl.filters; filterPtr; + for (filterPtr=ofdPtr->fl.filters; filterPtr; filterPtr=filterPtr->next) { - if (MatchOneType(pb, myDataPtr, filterPtr) == MATCHED) { + if (MatchOneType(pb, ofdPtr, filterPtr) == MATCHED) { return MATCHED; } } @@ -818,7 +688,7 @@ FileFilterProc( static Boolean MatchOneType( CInfoPBPtr pb, /* Information about the file */ - OpenFileData * myDataPtr, /* Information about this file dialog */ + OpenFileData * ofdPtr, /* Information about this file dialog */ FileFilter * filterPtr) /* Match the file described by pb against * this filter */ { @@ -909,31 +779,33 @@ MatchOneType( return UNMATCHED; } - /* *---------------------------------------------------------------------- * - * Tk_MessageBoxCmd -- + * Tk_ChooseDirectoryObjCmd -- * - * This procedure implements the MessageBox window for the - * Mac platform. See the user documentation for details on what - * it does. + * This procedure implements the "tk_chooseDirectory" dialog box + * for the Windows platform. See the user documentation for details + * on what it does. * * Results: - * A standard Tcl result. + * See user documentation. * * Side effects: - * See user documentation. + * A modal dialog window is created. Tcl_SetServiceMode() is + * called to allow background events to be processed * *---------------------------------------------------------------------- */ int -Tk_MessageBoxCmd( - ClientData clientData, /* Main window associated with interpreter. */ - Tcl_Interp *interp, /* Current interpreter. */ - int argc, /* Number of arguments. */ - char **argv) /* Argument strings. */ +Tk_ChooseDirectoryObjCmd(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. */ { - return EvalArgv(interp, "tkMessageBox", argc, argv); + return TCL_ERROR; } + + diff --git a/mac/tkMacEmbed.c b/mac/tkMacEmbed.c index 7a73b54..21e4803 100644 --- a/mac/tkMacEmbed.c +++ b/mac/tkMacEmbed.c @@ -8,12 +8,12 @@ * Currently only Toplevel embedding within the same Tk application is * allowed on the Macintosh. * - * Copyright (c) 1996-97 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. * - * SCCS: @(#) tkMacEmbed.c 1.6 97/10/31 17:20:22 + * SCCS: @(#) tkMacEmbed.c 1.8 97/12/03 18:56:10 */ #include "tkInt.h" @@ -53,6 +53,11 @@ typedef struct Container { static Container *firstContainerPtr = NULL; /* First in list of all containers * managed by this process. */ +/* + * Globals defined in this file + */ + +TkMacEmbedHandler *gMacEmbedHandler = NULL; /* * Prototypes for static procedures defined in this file: @@ -74,9 +79,41 @@ static void EmbedStructureProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); static void EmbedWindowDeleted _ANSI_ARGS_((TkWindow *winPtr)); -/* WARNING - HACK */ -static void GenerateFocusEvents _ANSI_ARGS_((TkWindow *sourcePtr, - TkWindow *destPtr)); + +/* + *---------------------------------------------------------------------- + * + * Tk_MacSetEmbedHandler -- + * + * Registers a handler for an in process form of embedding, like + * Netscape plugins, where Tk is loaded into the process, but does + * not control the main window + * + * Results: + * None + * + * Side effects: + * The embed handler is set. + * + *---------------------------------------------------------------------- + */ +void +Tk_MacSetEmbedHandler( + Tk_MacEmbedRegisterWinProc *registerWinProc, + Tk_MacEmbedGetGrafPortProc *getPortProc, + Tk_MacEmbedMakeContainerExistProc *containerExistProc, + Tk_MacEmbedGetClipProc *getClipProc, + Tk_MacEmbedGetOffsetInParentProc *getOffsetProc) +{ + if (gMacEmbedHandler == NULL) { + gMacEmbedHandler = (TkMacEmbedHandler *) ckalloc(sizeof(TkMacEmbedHandler)); + } + gMacEmbedHandler->registerWinProc = registerWinProc; + gMacEmbedHandler->getPortProc = getPortProc; + gMacEmbedHandler->containerExistProc = containerExistProc; + gMacEmbedHandler->getClipProc = getClipProc; + gMacEmbedHandler->getOffsetProc = getOffsetProc; +} /* @@ -180,7 +217,7 @@ TkpMakeWindow( * Results: * The return value is normally TCL_OK. If an error occurs (such * as string not being a valid window spec), then the return value - * is TCL_ERROR and an error message is left in interp->result if + * is TCL_ERROR and an error message is left in the interp's result if * interp is non-NULL. * * Side effects: @@ -240,18 +277,6 @@ TkpUseWindow( } } - /* - * We should not get to this code until we start to allow - * embedding in other applications. - */ - - if (containerPtr == NULL) { - Tcl_AppendResult(interp, "The window ID ", string, - " does not correspond to a valid Tk Window.", - (char *) NULL); - return TCL_ERROR; - } - /* * Make the embedded window. */ @@ -264,13 +289,27 @@ TkpUseWindow( macWin->winPtr = winPtr; winPtr->privatePtr = macWin; + + /* + * The portPtr will be NULL for a Tk in Tk embedded window. + * It is none of our business what it is for a Tk not in Tk embedded window, + * but we will initialize it to NULL, and let the registerWinProc + * set it. In any case, you must always use TkMacGetDrawablePort + * to get the portPtr. It will correctly find the container's port. + */ + + macWin->portPtr = (GWorldPtr) NULL; + macWin->clipRgn = NewRgn(); macWin->aboveClipRgn = NewRgn(); macWin->referenceCount = 0; macWin->flags = TK_CLIP_INVALID; - + macWin->toplevel = macWin; + macWin->toplevel->referenceCount++; + winPtr->flags |= TK_EMBEDDED; + /* * Make a copy of the TK_EMBEDDED flag, since sometimes * we need this to get the port after the TkWindow structure @@ -279,33 +318,67 @@ TkpUseWindow( macWin->flags |= TK_EMBEDDED; - /* - * The portPtr will be NULL for an embedded window. - * Always use TkMacGetDrawablePort to get the portPtr. - * It will correctly find the container's port. + /* + * Now check whether it is embedded in another Tk widget. If not (the first + * case below) we see if there is an in-process embedding handler registered, + * and if so, let that fill in the rest of the macWin. */ - - macWin->portPtr = (GWorldPtr) NULL; - - macWin->toplevel = macWin; - macWin->xOff = parent->winPtr->privatePtr->xOff + - parent->winPtr->changes.border_width + - winPtr->changes.x; - macWin->yOff = parent->winPtr->privatePtr->yOff + - parent->winPtr->changes.border_width + - winPtr->changes.y; - macWin->toplevel->referenceCount++; + if (containerPtr == NULL) { + /* + * If someone has registered an in process embedding handler, then + * see if it can handle this window... + */ + + if (gMacEmbedHandler == NULL || + gMacEmbedHandler->registerWinProc(result, (Tk_Window) winPtr) != TCL_OK) { + Tcl_AppendResult(interp, "The window ID ", string, + " does not correspond to a valid Tk Window.", + (char *) NULL); + return TCL_ERROR; + } else { + containerPtr = (Container *) ckalloc(sizeof(Container)); + + containerPtr->parentPtr = NULL; + containerPtr->embedded = (Window) macWin; + containerPtr->embeddedPtr = macWin->winPtr; + containerPtr->nextPtr = firstContainerPtr; + firstContainerPtr = containerPtr; + + } + } else { + + /* + * The window is embedded in another Tk window. + */ + + macWin->xOff = parent->winPtr->privatePtr->xOff + + parent->winPtr->changes.border_width + + winPtr->changes.x; + macWin->yOff = parent->winPtr->privatePtr->yOff + + parent->winPtr->changes.border_width + + winPtr->changes.y; - /* - * Finish filling up the container structure with the embedded window's - * information. - */ + + /* + * Finish filling up the container structure with the embedded window's + * information. + */ - containerPtr->embedded = (Window) macWin; - containerPtr->embeddedPtr = macWin->winPtr; + containerPtr->embedded = (Window) macWin; + containerPtr->embeddedPtr = macWin->winPtr; - /* + /* + * Create an event handler to clean up the Container structure when + * tkwin is eventually deleted. + */ + + Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc, + (ClientData) winPtr); + + } + + /* * TODO: need general solution for visibility events. */ @@ -318,15 +391,19 @@ TkpUseWindow( event.xvisibility.state = VisibilityUnobscured; Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); - /* - * Create an event handler to clean up the Container structure when - * tkwin is eventually deleted. + + /* + * TODO: need general solution for visibility events. */ - - Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc, - (ClientData) winPtr); - + event.xany.serial = Tk_Display(winPtr)->request; + event.xany.send_event = False; + event.xany.display = Tk_Display(winPtr); + + event.xvisibility.type = VisibilityNotify; + event.xvisibility.window = (Window) macWin;; + event.xvisibility.state = VisibilityUnobscured; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); return TCL_OK; } @@ -884,11 +961,10 @@ EmbedActivateProc(clientData, eventPtr) Container *containerPtr = (Container *) clientData; if (containerPtr->embeddedPtr != NULL) { - - if (eventPtr->type == ActivateNotify) { - TkGenerateActivateEvents(containerPtr->embeddedPtr, 1); + if (eventPtr->type == ActivateNotify) { + TkGenerateActivateEvents(containerPtr->embeddedPtr,1); } else if (eventPtr->type == DeactivateNotify) { - TkGenerateActivateEvents(containerPtr->embeddedPtr, 0); + TkGenerateActivateEvents(containerPtr->embeddedPtr,0); } } } @@ -923,14 +999,14 @@ EmbedFocusProc(clientData, eventPtr) XEvent event; if (containerPtr->embeddedPtr != NULL) { - display = Tk_Display(containerPtr->parentPtr); + display = Tk_Display(containerPtr->parentPtr); event.xfocus.serial = LastKnownRequestProcessed(display); event.xfocus.send_event = false; event.xfocus.display = display; event.xfocus.mode = NotifyNormal; event.xfocus.window = containerPtr->embedded; - if (eventPtr->type == FocusIn) { + if (eventPtr->type == FocusIn) { /* * The focus just arrived at the container. Change the X focus * to move it to the embedded application, if there is one. @@ -951,7 +1027,7 @@ EmbedFocusProc(clientData, eventPtr) } Tk_QueueWindowEvent(&event, TCL_QUEUE_MARK); - } + } } /* diff --git a/mac/tkMacFont.c b/mac/tkMacFont.c index 8619880..616034e 100644 --- a/mac/tkMacFont.c +++ b/mac/tkMacFont.c @@ -10,36 +10,389 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS:@(#) tkMacFont.c 1.52 97/11/20 18:29:51 + * SCCS: @(#) tkMacFont.c 1.54 97/11/26 10:51:12 */ #include <Windows.h> #include <Strings.h> #include <Fonts.h> +#include <Script.h> #include <Resources.h> +#include <TextUtils.h> #include "tkMacInt.h" #include "tkFont.h" -#include "tkPort.h" /* - * The following structure represents the Macintosh's' implementation of a - * font. + * For doing things with Mac strings and Fixed numbers. This probably should move + * the mac header file. */ +#ifndef StrLength +#define StrLength(s) (*((unsigned char *) (s))) +#endif +#ifndef StrBody +#define StrBody(s) ((char *) (s) + 1) +#endif +#define pstrcmp(s1, s2) RelString((s1), (s2), 1, 1) +#define pstrcasecmp(s1, s2) RelString((s1), (s2), 0, 1) + +#ifndef Fixed2Int +#define Fixed2Int(f) ((f) >> 16) +#define Int2Fixed(i) ((i) << 16) +#endif + +/* + * The preferred font encodings. + */ + +static CONST char *encodingList[] = { + "macRoman", "macJapan", NULL +}; + +/* + * The following structures are used to map the script/language codes of a + * font to the name that should be passed to Tcl_GetTextEncoding() to obtain + * the encoding for that font. The set of numeric constants is fixed and + * defined by Apple. + */ + +static TkStateMap scriptMap[] = { + {smRoman, "macRoman"}, + {smJapanese, "macJapan"}, + {smTradChinese, "macChinese"}, + {smKorean, "macKorean"}, + {smArabic, "macArabic"}, + {smHebrew, "macHebrew"}, + {smGreek, "macGreek"}, + {smCyrillic, "macCyrillic"}, + {smRSymbol, "macRSymbol"}, + {smDevanagari, "macDevanagari"}, + {smGurmukhi, "macGurmukhi"}, + {smGujarati, "macGujarati"}, + {smOriya, "macOriya"}, + {smBengali, "macBengali"}, + {smTamil, "macTamil"}, + {smTelugu, "macTelugu"}, + {smKannada, "macKannada"}, + {smMalayalam, "macMalayalam"}, + {smSinhalese, "macSinhalese"}, + {smBurmese, "macBurmese"}, + {smKhmer, "macKhmer"}, + {smThai, "macThailand"}, + {smLaotian, "macLaos"}, + {smGeorgian, "macGeorgia"}, + {smArmenian, "macArmenia"}, + {smSimpChinese, "macSimpChinese"}, + {smTibetan, "macTIbet"}, + {smMongolian, "macMongolia"}, + {smGeez, "macEthiopia"}, + {smEastEurRoman, "macCentEuro"}, + {smVietnamese, "macVietnam"}, + {smExtArabic, "macSindhi"}, + {NULL, NULL} +}; + +static TkStateMap romanMap[] = { + {langCroatian, "macCroatian"}, + {langSlovenian, "macCroatian"}, + {langIcelandic, "macIceland"}, + {langRomanian, "macRomania"}, + {langTurkish, "macTurkish"}, + {langGreek, "macGreek"}, + {NULL, NULL} +}; + +static TkStateMap cyrillicMap[] = { + {langUkrainian, "macUkraine"}, + {langBulgarian, "macBulgaria"}, + {NULL, NULL} +}; + +/* + * The following structure represents a font family. It is assumed that + * all screen fonts constructed from the same "font family" share certain + * properties; all screen fonts with the same "font family" point to a + * shared instance of this structure. The most important shared property + * is the character existence metrics, used to determine if a screen font + * can display a given Unicode character. + * + * Under Macintosh, a "font family" is uniquely identified by its face number. + */ + + +#define FONTMAP_SHIFT 10 + +#define FONTMAP_PAGES (1 << (sizeof(Tcl_UniChar) * 8 - FONTMAP_SHIFT)) +#define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT) + +typedef struct FontFamily { + struct FontFamily *nextPtr; /* Next in list of all known font families. */ + int refCount; /* How many SubFonts are referring to this + * FontFamily. When the refCount drops to + * zero, this FontFamily may be freed. */ + /* + * Key. + */ + + short faceNum; /* Unique face number key for this FontFamily. */ + + /* + * Derived properties. + */ + + Tcl_Encoding encoding; /* Encoding for this font family. */ + int isSymbolFont; /* Non-zero if this is a symbol family. */ + int isMultiByteFont; /* Non-zero if this is a multi-byte family. */ + char typeTable[256]; /* Table that identfies all lead bytes for a + * multi-byte family, used when measuring chars. + * If a byte is a lead byte, the value at the + * corresponding position in the typeTable is 1, + * otherwise 0. If this is a single-byte font, + * all entries are 0. */ + char *fontMap[FONTMAP_PAGES]; + /* Two-level sparse table used to determine + * quickly if the specified character exists. + * As characters are encountered, more pages + * in this table are dynamically added. The + * contents of each page is a bitmask + * consisting of FONTMAP_BITSPERPAGE bits, + * representing whether this font can be used + * to display the given character at the + * corresponding bit position. The high bits + * of the character are used to pick which + * page of the table is used. */ +} FontFamily; + +/* + * The following structure encapsulates an individual screen font. A font + * object is made up of however many SubFonts are necessary to display a + * stream of multilingual characters. + */ + +typedef struct SubFont { + char **fontMap; /* Pointer to font map from the FontFamily, + * cached here to save a dereference. */ + FontFamily *familyPtr; /* The FontFamily for this SubFont. */ +} SubFont; + +/* + * The following structure represents Macintosh's implementation of a font + * object. + */ + +#define SUBFONT_SPACE 3 + typedef struct MacFont { TkFont font; /* Stuff used by generic font package. Must * be first in structure. */ - short family; - short size; - short style; + SubFont staticSubFonts[SUBFONT_SPACE]; + /* Builtin space for a limited number of + * SubFonts. */ + int numSubFonts; /* Length of following array. */ + SubFont *subFontArray; /* Array of SubFonts that have been loaded + * in order to draw/measure all the characters + * encountered by this font so far. All fonts + * start off with one SubFont initialized by + * AllocFont() from the original set of font + * attributes. Usually points to + * staticSubFonts, but may point to malloced + * space if there are lots of SubFonts. */ + + short size; /* Font size in pixels, constructed from + * font attributes. */ + short style; /* Style bits, constructed from font + * attributes. */ } MacFont; +/* + * The following structure is used to map between the UTF-8 name for a font and + * the name that the Macintosh uses to refer to the font, in order to determine + * if a font exists. The Macintosh names for fonts are stored in the encoding + * of the font itself. + */ + +typedef struct FontNameMap { + Tk_Uid utfName; /* The name of the font in UTF-8. */ + StringPtr nativeName; /* The name of the font in the font's encoding. */ + short faceNum; /* Unique face number for this font. */ +} FontNameMap; + +/* + * The list of font families that are currently loaded. As screen fonts + * are loaded, this list grows to hold information about what characters + * exist in each font family. + */ + +static FontFamily *fontFamilyList = NULL; + +/* + * Information cached about the system at startup time. + */ + +static FontNameMap *gFontNameMap = NULL; static GWorldPtr gWorld = NULL; -static TkFont * AllocMacFont _ANSI_ARGS_((TkFont *tkfont, - Tk_Window tkwin, int family, int size, int style)); +/* + * Procedures used only in this file. + */ + +static FontFamily * AllocFontFamily(CONST MacFont *fontPtr, int family); +static SubFont * CanUseFallback(MacFont *fontPtr, + CONST char *fallbackName, int ch); +static SubFont * CanUseFallbackWithAliases(MacFont *fontPtr, + char *faceName, int ch, Tcl_DString *nameTriedPtr); +static SubFont * FindSubFontForChar(MacFont *fontPtr, int ch); +static void FontMapInsert(SubFont *subFontPtr, int ch); +static void FontMapLoadPage(SubFont *subFontPtr, int row); +static int FontMapLookup(SubFont *subFontPtr, int ch); +static void FreeFontFamily(FontFamily *familyPtr); +static void InitFont(Tk_Window tkwin, int family, int size, + int style, MacFont *fontPtr); +static void InitSubFont(CONST MacFont *fontPtr, int family, + SubFont *subFontPtr); +static void MultiFontDrawText(MacFont *fontPtr, + CONST char *source, int numBytes, int x, int y); +static void ReleaseFont(MacFont *fontPtr); +static void ReleaseSubFont(SubFont *subFontPtr); +static int SeenName(CONST char *name, Tcl_DString *dsPtr); + +static char * BreakLine(FontFamily *familyPtr, int flags, + CONST char *source, int numBytes, int *widthPtr); +static int GetFamilyNum(CONST char *faceName, short *familyPtr); +static int GetFamilyOrAliasNum(CONST char *faceName, + short *familyPtr); +static Tcl_Encoding GetFontEncoding(int faceNum, int allowSymbol, + int *isSymbolPtr); +static Tk_Uid GetUtfFaceName(StringPtr faceNameStr); + + +/* + *------------------------------------------------------------------------- + * + * TkpFontPkgInit -- + * + * This procedure is called when an application is created. It + * initializes all the structures that are used by the + * platform-dependant code on a per application basis. + * + * Results: + * None. + * + * Side effects: + * See comments below. + * + *------------------------------------------------------------------------- + */ +void +TkpFontPkgInit(mainPtr) + TkMainInfo *mainPtr; /* The application being created. */ +{ + MenuHandle fontMenu; + FontNameMap *tmpFontNameMap, *newFontNameMap, *mapPtr; + int i, j, numFonts, fontMapOffset, isSymbol; + Str255 nativeName; + Tcl_DString ds; + Tcl_Encoding encoding; + Tcl_Encoding *encodings; + + if (gWorld == NULL) { + /* + * Do the following one time only. + */ + + Rect rect = {0, 0, 1, 1}; + + SetFractEnable(0); + + /* + * Used for saving and restoring state while drawing and measuring. + */ + + if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) { + panic("TkpFontPkgInit: NewGWorld failed"); + } + + /* + * The name of each font is stored in the encoding of that font. + * How would we translate a name from UTF-8 into the native encoding + * of the font unless we knew the encoding of that font? We can't. + * So, precompute the UTF-8 and native names of all fonts on the + * system. The when the user asks for font by its UTF-8 name, we + * lookup the name in that table and really ask for the font by its + * native name. Any unknown UTF-8 names will be mapped to the system + * font. + */ + + fontMenu = NewMenu('FT', "\px"); + AddResMenu(fontMenu, 'FONT'); + + numFonts = CountMItems(fontMenu); + tmpFontNameMap = (FontNameMap *) ckalloc(sizeof(FontNameMap) * numFonts); + encodings = (Tcl_Encoding *) ckalloc(sizeof(Tcl_Encoding) * numFonts); + + mapPtr = tmpFontNameMap; + for (i = 0; i < numFonts; i++) { + GetMenuItemText(fontMenu, i + 1, nativeName); + GetFNum(nativeName, &mapPtr->faceNum); + encodings[i] = GetFontEncoding(mapPtr->faceNum, 0, &isSymbol); + Tcl_ExternalToUtfDString(encodings[i], StrBody(nativeName), + StrLength(nativeName), &ds); + mapPtr->utfName = Tk_GetUid(Tcl_DStringValue(&ds)); + mapPtr->nativeName = (StringPtr) ckalloc(StrLength(nativeName) + 1); + memcpy(mapPtr->nativeName, nativeName, StrLength(nativeName) + 1); + Tcl_DStringFree(&ds); + mapPtr++; + } + DisposeMenu(fontMenu); + + /* + * Reorder FontNameMap so fonts with the preferred encodings are at + * the front of the list. The relative order of fonts that all have + * the same encoding is preserved. Fonts with unknown encodings get + * stuck at the end. + */ + + newFontNameMap = (FontNameMap *) ckalloc(sizeof(FontNameMap) * (numFonts + 1)); + fontMapOffset = 0; + for (i = 0; encodingList[i] != NULL; i++) { + encoding = Tcl_GetEncoding(NULL, encodingList[i]); + if (encoding == NULL) { + continue; + } + for (j = 0; j < numFonts; j++) { + if (encodings[j] == encoding) { + newFontNameMap[fontMapOffset] = tmpFontNameMap[j]; + fontMapOffset++; + Tcl_FreeEncoding(encodings[j]); + tmpFontNameMap[j].utfName = NULL; + } + } + Tcl_FreeEncoding(encoding); + } + for (i = 0; i < numFonts; i++) { + if (tmpFontNameMap[i].utfName != NULL) { + newFontNameMap[fontMapOffset] = tmpFontNameMap[i]; + fontMapOffset++; + Tcl_FreeEncoding(encodings[i]); + } + } + if (fontMapOffset != numFonts) { + panic("TkpFontPkgInit: unexpected number of fonts"); + } + + mapPtr = &newFontNameMap[numFonts]; + mapPtr->utfName = NULL; + mapPtr->nativeName = NULL; + mapPtr->faceNum = 0; + + ckfree((char *) tmpFontNameMap); + ckfree((char *) encodings); + + gFontNameMap = newFontNameMap; + } +} /* *--------------------------------------------------------------------------- @@ -73,6 +426,7 @@ TkpGetNativeFont( CONST char *name) /* Platform-specific font name. */ { short family; + MacFont *fontPtr; if (strcmp(name, "system") == 0) { family = GetSysFont(); @@ -81,8 +435,11 @@ TkpGetNativeFont( } else { return NULL; } - - return AllocMacFont(NULL, tkwin, family, 0, 0); + + fontPtr = (MacFont *) ckalloc(sizeof(MacFont)); + InitFont(tkwin, family, 0, 0, fontPtr); + + return (TkFont *) fontPtr; } /* @@ -122,41 +479,47 @@ TkpGetFontFromAttributes( * will be released. If NULL, a new TkFont * structure is allocated. */ Tk_Window tkwin, /* For display where font will be used. */ - CONST TkFontAttributes *faPtr) /* Set of attributes to match. */ + CONST TkFontAttributes *faPtr) + /* Set of attributes to match. */ { - char buf[257]; - size_t len; - short family, size, style; - - if (faPtr->family == NULL) { - family = 0; - } else { - CONST char *familyName; - - familyName = faPtr->family; - if (strcasecmp(familyName, "Times New Roman") == 0) { - familyName = "Times"; - } else if (strcasecmp(familyName, "Courier New") == 0) { - familyName = "Courier"; - } else if (strcasecmp(familyName, "Arial") == 0) { - familyName = "Helvetica"; - } - - len = strlen(familyName); - if (len > 255) { - len = 255; + short faceNum, style; + int i, j; + char *faceName, *fallback; + char ***fallbacks; + MacFont *fontPtr; + + /* + * Algorithm to get the closest font to the one requested. + * + * try fontname + * try all aliases for fontname + * foreach fallback for fontname + * try the fallback + * try all aliases for the fallback + */ + + faceNum = 0; + faceName = faPtr->family; + if (faceName != NULL) { + if (GetFamilyOrAliasNum(faceName, &faceNum) != 0) { + goto found; + } + fallbacks = TkFontGetFallbacks(); + for (i = 0; fallbacks[i] != NULL; i++) { + for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) { + if (strcasecmp(faceName, fallback) == 0) { + for (j = 0; (fallback = fallbacks[i][j]) != NULL; j++) { + if (GetFamilyOrAliasNum(fallback, &faceNum)) { + goto found; + } + } + } + break; + } } - buf[0] = (char) len; - memcpy(buf + 1, familyName, len); - buf[len + 1] = '\0'; - GetFNum((StringPtr) buf, &family); } - - size = faPtr->pointsize; - if (size <= 0) { - size = GetDefFontSize(); - } - + + found: style = 0; if (faPtr->weight != TK_FW_NORMAL) { style |= bold; @@ -167,8 +530,15 @@ TkpGetFontFromAttributes( if (faPtr->underline) { style |= underline; } - - return AllocMacFont(tkFontPtr, tkwin, family, size, style); + if (tkFontPtr == NULL) { + fontPtr = (MacFont *) ckalloc(sizeof(MacFont)); + } else { + fontPtr = (MacFont *) tkFontPtr; + ReleaseFont(fontPtr); + } + InitFont(tkwin, faceNum, faPtr->size, style, fontPtr); + + return (TkFont *) fontPtr; } /* @@ -194,7 +564,10 @@ void TkpDeleteFont( TkFont *tkFontPtr) /* Token of font to be deleted. */ { - ckfree((char *) tkFontPtr); + MacFont *fontPtr; + + fontPtr = (MacFont *) tkFontPtr; + ReleaseFont(fontPtr); } /* @@ -206,7 +579,7 @@ TkpDeleteFont( * on the display of the given window. * * Results: - * interp->result is modified to hold a list of all the available + * Modifies interp's result object to hold a list of all the available * font families. * * Side effects: @@ -220,76 +593,54 @@ TkpGetFontFamilies( Tcl_Interp *interp, /* Interp to hold result. */ Tk_Window tkwin) /* For display to query. */ { - MenuHandle fontMenu; - int i; - char itemText[257]; - - fontMenu = NewMenu(1, "\px"); - AddResMenu(fontMenu, 'FONT'); - - for (i = 1; i < CountMItems(fontMenu); i++) { - /* - * Each item is a pascal string. Convert it to C and append. - */ - GetMenuItemText(fontMenu, i, (unsigned char *) itemText); - itemText[itemText[0] + 1] = '\0'; - Tcl_AppendElement(interp, &itemText[1]); + FontNameMap *mapPtr; + Tcl_Obj *resultPtr, *strPtr; + + resultPtr = Tcl_GetObjResult(interp); + for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) { + strPtr = Tcl_NewStringObj(mapPtr->utfName, -1); + Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); } - DisposeMenu(fontMenu); } - /* - *--------------------------------------------------------------------------- + *------------------------------------------------------------------------- * - * TkMacIsCharacterMissing -- + * TkpGetSubFonts -- * - * Given a tkFont and a character determines whether the character has - * a glyph defined in the font or not. Note that this is potentially - * not compatible with Mac OS 8 as it looks at the font handle - * structure directly. Looks into the character array of the font - * handle to determine whether the glyph is defined or not. + * A function used by the testing package for querying the actual + * screen fonts that make up a font object. * * Results: - * Returns a 1 if the character is missing, a 0 if it is not. + * Modifies interp's result object to hold a list containing the + * names of the screen fonts that make up the given font object. * * Side effects: * None. * - *--------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ - -int -TkMacIsCharacterMissing( - Tk_Font tkfont, /* The font we are looking in. */ - unsigned int searchChar) /* The character we are looking for. */ + +void +TkpGetSubFonts(interp, tkfont) + Tcl_Interp *interp; /* Interp to hold result. */ + Tk_Font tkfont; /* Font object to query. */ { - MacFont *fontPtr = (MacFont *) tkfont; - FMInput fm; - FontRec **fontRecHandle; - - fm.family = fontPtr->family; - fm.size = fontPtr->size; - fm.face = fontPtr->style; - fm.needBits = 0; - fm.device = 0; - fm.numer.h = fm.numer.v = fm.denom.h = fm.denom.v = 1; + int i; + Tcl_Obj *resultPtr, *strPtr; + MacFont *fontPtr; + FontFamily *familyPtr; + Str255 nativeName; - /* - * This element of the FMOutput structure was changed between the 2.0 & 3.0 - * versions of the Universal Headers. - */ - -#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300) - fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontResult; -#else - fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontHandle; -#endif - return *(short *) ((long) &(*fontRecHandle)->owTLoc - + ((long)((*fontRecHandle)->owTLoc + searchChar - - (*fontRecHandle)->firstChar) * sizeof(short))) == -1; + resultPtr = Tcl_GetObjResult(interp); + fontPtr = (MacFont *) tkfont; + for (i = 0; i < fontPtr->numSubFonts; i++) { + familyPtr = fontPtr->subFontArray[i].familyPtr; + GetFontName(familyPtr->faceNum, nativeName); + strPtr = Tcl_NewStringObj(GetUtfFaceName(nativeName), -1); + Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); + } } - /* *--------------------------------------------------------------------------- @@ -316,14 +667,14 @@ TkMacIsCharacterMissing( int Tk_MeasureChars( Tk_Font tkfont, /* Font in which characters will be drawn. */ - CONST char *source, /* Characters to be displayed. Need not be + CONST char *source, /* UTF-8 string to be displayed. Need not be * '\0' terminated. */ - int numChars, /* Maximum number of characters to consider + int numBytes, /* Maximum number of bytes to consider * from source string. */ - int maxLength, /* If > 0, maxLength specifies the longest + int maxLength, /* If >= 0, maxLength specifies the longest * permissible line length; don't consider any * character that would cross this - * x-position. If <= 0, then line length is + * x-position. If < 0, then line length is * unbounded and the flags argument is * ignored. */ int flags, /* Various flag bits OR-ed together: @@ -336,134 +687,270 @@ Tk_MeasureChars( int *lengthPtr) /* Filled with x-location just after the * terminating character. */ { - short staticWidths[128]; - short *widths; - CONST char *p, *term; - int curX, termX, curIdx, sawNonSpace; MacFont *fontPtr; + FontFamily *lastFamilyPtr; CGrafPtr saveWorld; GDHandle saveDevice; + int curX, curByte; - if (numChars == 0) { - *lengthPtr = 0; - return 0; - } - - if (gWorld == NULL) { - Rect rect = {0, 0, 1, 1}; + /* + * According to "Inside Macintosh: Text", the Macintosh may + * automatically substitute + * ligatures or context-sensitive presentation forms when + * measuring/displaying text within a font run. We cannot safely + * measure individual characters and add up the widths w/o errors. + * However, if we convert a range of text from UTF-8 to, say, + * Shift-JIS, and get the offset into the Shift-JIS string as to + * where a word or line break would occur, then can we map that + * number back to UTF-8? + */ + + fontPtr = (MacFont *) tkfont; - if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) { - panic("NewGWorld failed in Tk_MeasureChars"); - } - } GetGWorld(&saveWorld, &saveDevice); SetGWorld(gWorld, NULL); - - fontPtr = (MacFont *) tkfont; - TextFont(fontPtr->family); + TextSize(fontPtr->size); TextFace(fontPtr->style); - if (maxLength <= 0) { - *lengthPtr = TextWidth(source, 0, numChars); - SetGWorld(saveWorld, saveDevice); - return numChars; - } - - if (numChars > maxLength) { - /* - * Assume that all chars are at least 1 pixel wide, so there's no - * need to measure more characters than there are pixels. This - * assumption could be refined to an iterative approach that would - * use that as a starting point and try more chars if necessary (if - * there actually were some zero-width chars). - */ - - numChars = maxLength; - } - if (numChars > SHRT_MAX) { - /* - * If they are trying to measure more than 32767 chars at one time, - * it would require several separate measurements. - */ - - numChars = SHRT_MAX; - } - - widths = staticWidths; - if (numChars >= sizeof(staticWidths) / sizeof(staticWidths[0])) { - widths = (short *) ckalloc((numChars + 1) * sizeof(short)); - } + lastFamilyPtr = fontPtr->subFontArray[0].familyPtr; - MeasureText((short) numChars, source, widths); - - if (widths[numChars] <= maxLength) { - curX = widths[numChars]; - curIdx = numChars; + if (numBytes == 0) { + curX = 0; + curByte = 0; + } else if (maxLength < 0) { + CONST char *p, *end, *next; + Tcl_UniChar ch; + FontFamily *thisFamilyPtr; + Tcl_DString runString; + + /* + * A three step process: + * 1. Find a contiguous range of characters that can all be + * represented by a single screen font. + * 2. Convert those chars to the encoding of that font. + * 3. Measure converted chars. + */ + + curX = 0; + end = source + numBytes; + for (p = source; p < end; ) { + next = p + Tcl_UtfToUniChar(p, &ch); + thisFamilyPtr = FindSubFontForChar(fontPtr, ch)->familyPtr; + if (thisFamilyPtr != lastFamilyPtr) { + TextFont(lastFamilyPtr->faceNum); + Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source, + p - source, &runString); + curX += TextWidth(Tcl_DStringValue(&runString), 0, + Tcl_DStringLength(&runString)); + Tcl_DStringFree(&runString); + lastFamilyPtr = thisFamilyPtr; + source = p; + } + p = next; + } + TextFont(lastFamilyPtr->faceNum); + Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source, p - source, + &runString); + curX += TextWidth(Tcl_DStringValue(&runString), 0, + Tcl_DStringLength(&runString)); + Tcl_DStringFree(&runString); + curByte = numBytes; } else { - p = term = source; - curX = termX = 0; - - sawNonSpace = !isspace(UCHAR(*p)); - for (curIdx = 1; ; curIdx++) { - if (isspace(UCHAR(*p))) { - if (sawNonSpace) { - term = p; - termX = widths[curIdx - 1]; - sawNonSpace = 0; - } - } else { - sawNonSpace = 1; - } - if (widths[curIdx] > maxLength) { - curIdx--; - curX = widths[curIdx]; - break; + CONST char *p, *end, *next, *sourceOrig; + int widthLeft; + FontFamily *thisFamilyPtr; + Tcl_UniChar ch; + char *rest; + + /* + * How many chars will fit in the space allotted? + */ + + if (maxLength > 32767) { + maxLength = 32767; + } + + widthLeft = maxLength; + sourceOrig = source; + end = source + numBytes; + for (p = source; p < end; p = next) { + next = p + Tcl_UtfToUniChar(p, &ch); + thisFamilyPtr = FindSubFontForChar(fontPtr, ch)->familyPtr; + if (thisFamilyPtr != lastFamilyPtr) { + if (p > source) { + rest = BreakLine(lastFamilyPtr, flags, source, + p - source, &widthLeft); + flags &= ~TK_AT_LEAST_ONE; + if (rest != NULL) { + p = source; + break; + } + } + lastFamilyPtr = thisFamilyPtr; + source = p; } - p++; } - if (flags & TK_PARTIAL_OK) { - curIdx++; - curX = widths[curIdx]; + + if (p > source) { + rest = BreakLine(lastFamilyPtr, flags, source, p - source, + &widthLeft); } - if ((curIdx == 0) && (flags & TK_AT_LEAST_ONE)) { - /* - * The space was too small to hold even one character. Since at - * least one character must always fit on a line, return the width - * of the first character. - */ - - curX = TextWidth(source, 0, 1); - curIdx = 1; - } else if (flags & TK_WHOLE_WORDS) { - /* - * Break at last word that fits on the line. - */ - - if ((flags & TK_AT_LEAST_ONE) && (term == source)) { - /* - * The space was too small to hold an entire word. This - * is the only word on the line, so just return the part of th - * word that fit. - */ - - ; - } else { - curIdx = term - source; - curX = termX; - } - } + + if (rest == NULL) { + curByte = numBytes; + } else { + curByte = rest - sourceOrig; + } + curX = maxLength - widthLeft; } - if (widths != staticWidths) { - ckfree((char *) widths); - } + SetGWorld(saveWorld, saveDevice); *lengthPtr = curX; + return curByte; +} + +/* + *--------------------------------------------------------------------------- + * + * BreakLine -- + * + * Determine where the given line of text should be broken so that it + * fits in the specified range. Before calling this function, the + * font values and graphics port must be set. + * + * Results: + * The return value is NULL if the specified range is larger that the + * space the text needs, and *widthLeftPtr is filled with how much + * space is left in the range after measuring the whole text buffer. + * Otherwise, the return value is a pointer into the text buffer that + * indicates where the line should be broken (up to, but not including + * that character), and *widthLeftPtr is filled with how much space is + * left in the range after measuring up to that character. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +static char * +BreakLine( + FontFamily *familyPtr, /* FontFamily that describes the font values + * that are already selected into the graphics + * port. */ + int flags, /* Various flag bits OR-ed together: + * TK_PARTIAL_OK means include the last char + * which only partially fit on this line. + * TK_WHOLE_WORDS means stop on a word + * boundary, if possible. + * TK_AT_LEAST_ONE means return at least one + * character even if no characters fit. */ + CONST char *source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. */ + int numBytes, /* Maximum number of bytes to consider + * from source string. */ + int *widthLeftPtr) /* On input, specifies size of range into + * which characters from source buffer should + * be fit. On output, filled with how much + * space is left after fitting as many + * characters as possible into the range. + * Result may be negative if TK_AT_LEAST_ONE + * was specified in the flags argument. */ +{ + Fixed pixelWidth, widthLeft; + StyledLineBreakCode breakCode; + Tcl_DString runString; + long textOffset; + Boolean leadingEdge; + Point point; + int charOffset, thisCharWasDoubleByte; + char *p, *end, *typeTable; - SetGWorld(saveWorld, saveDevice); + TextFont(familyPtr->faceNum); + Tcl_UtfToExternalDString(familyPtr->encoding, source, numBytes, + &runString); + pixelWidth = Int2Fixed(*widthLeftPtr) + 1; + if (flags & TK_WHOLE_WORDS) { + textOffset = (flags & TK_AT_LEAST_ONE); + widthLeft = pixelWidth; + breakCode = StyledLineBreak(Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString), 0, Tcl_DStringLength(&runString), + 0, &widthLeft, &textOffset); + if (breakCode != smBreakOverflow) { + /* + * StyledLineBreak includes all the space characters at the end of + * line that we want to suppress. + */ + + textOffset = VisibleLength(Tcl_DStringValue(&runString), textOffset); + goto getoffset; + } + } else { + point.v = 1; + point.h = 1; + textOffset = PixelToChar(Tcl_DStringValue(&runString), + Tcl_DStringLength(&runString), 0, pixelWidth, &leadingEdge, + &widthLeft, smOnlyStyleRun, point, point); + if (Fixed2Int(widthLeft) < 0) { + goto getoffset; + } + } + *widthLeftPtr = Fixed2Int(widthLeft); + Tcl_DStringFree(&runString); + return NULL; + + /* + * The conversion routine that converts UTF-8 to the target encoding + * must map one UTF-8 character to exactly one encoding-specific + * character, so that the following algorithm works: + * + * 1. Get byte offset of where line should be broken. + * 2. Get char offset corresponding to that byte offset. + * 3. Map that char offset to byte offset in UTF-8 string. + */ + + getoffset: + thisCharWasDoubleByte = 0; + if (familyPtr->isMultiByteFont == 0) { + charOffset = textOffset; + } else { + charOffset = 0; + typeTable = familyPtr->typeTable; + + p = Tcl_DStringValue(&runString); + end = p + textOffset; + thisCharWasDoubleByte = typeTable[*((unsigned char *) p)]; + for ( ; p < end; p++) { + thisCharWasDoubleByte = typeTable[*((unsigned char *) p)]; + p += thisCharWasDoubleByte; + charOffset++; + } + } - return curIdx; + if ((flags & TK_WHOLE_WORDS) == 0) { + if ((flags & TK_PARTIAL_OK) && (leadingEdge != 0)) { + textOffset += thisCharWasDoubleByte; + textOffset++; + charOffset++; + } else if (((flags & TK_PARTIAL_OK) == 0) && (leadingEdge == 0)) { + textOffset -= thisCharWasDoubleByte; + textOffset--; + charOffset--; + } + } + if ((textOffset == 0) && (Tcl_DStringLength(&runString) > 0) + && (flags & TK_AT_LEAST_ONE)) { + p = Tcl_DStringValue(&runString); + textOffset += familyPtr->typeTable[*((unsigned char *) p)]; + textOffset++; + charOffset++; + } + *widthLeftPtr = Fixed2Int(pixelWidth) + - TextWidth(Tcl_DStringValue(&runString), 0, textOffset); + Tcl_DStringFree(&runString); + return Tcl_UtfAtIndex(source, charOffset); } /* @@ -489,14 +976,14 @@ Tk_DrawChars( GC gc, /* Graphics context for drawing characters. */ Tk_Font tkfont, /* Font in which characters will be drawn; * must be the same as font used in GC. */ - CONST char *source, /* Characters to be displayed. Need not be + CONST char *source, /* UTF-8 string to be displayed. Need not be * '\0' terminated. All Tk meta-characters * (tabs, control characters, and newlines) * should be stripped out of the string that * is passed to this function. If they are * not stripped out, they will be displayed as * regular printing characters. */ - int numChars, /* Number of characters in string. */ + int numBytes, /* Number of bytes in string. */ int x, int y) /* Coordinates at which to place origin of * string when drawing. */ { @@ -538,19 +1025,12 @@ Tk_DrawChars( bufferPort = TkMacGetDrawablePort(pixmap); SetGWorld(bufferPort, NULL); - TextFont(fontPtr->family); - TextSize(fontPtr->size); - TextFace(fontPtr->style); - if (TkSetMacColor(gc->foreground, &macColor) == true) { RGBForeColor(&macColor); } - ShowPen(); - MoveTo((short) 0, (short) 0); FillRect(&stippleMap->bounds, &tcl_macQdPtr->white); - MoveTo((short) x, (short) y); - DrawText(source, 0, (short) numChars); + MultiFontDrawText(fontPtr, source, numBytes, 0, 0); SetGWorld(destPort, NULL); CopyDeepMask(&((GrafPtr) bufferPort)->portBits, stippleMap, @@ -565,18 +1045,13 @@ Tk_DrawChars( Tk_FreePixmap(display, pixmap); ckfree(stippleMap->baseAddr); ckfree((char *)stippleMap); - } else { - TextFont(fontPtr->family); - TextSize(fontPtr->size); - TextFace(fontPtr->style); - + } else { if (TkSetMacColor(gc->foreground, &macColor) == true) { RGBForeColor(&macColor); } - ShowPen(); - MoveTo((short) (macWin->xOff + x), (short) (macWin->yOff + y)); - DrawText(source, 0, (short) numChars); + MultiFontDrawText(fontPtr, source, numBytes, macWin->xOff + x, + macWin->yOff + y); } TextFont(txFont); @@ -587,92 +1062,1057 @@ Tk_DrawChars( } /* + *------------------------------------------------------------------------- + * + * MultiFontDrawText -- + * + * Helper function for Tk_DrawChars. Draws characters, using the + * various screen fonts in fontPtr to draw multilingual characters. + * Note: No bidirectional support. + * + * Results: + * None. + * + * Side effects: + * Information gets drawn on the screen. + * Contents of fontPtr may be modified if more subfonts were loaded + * in order to draw all the multilingual characters in the given + * string. + * + *------------------------------------------------------------------------- + */ + +static void +MultiFontDrawText( + MacFont *fontPtr, /* Contains set of fonts to use when drawing + * following string. */ + CONST char *source, /* Potentially multilingual UTF-8 string. */ + int numBytes, /* Length of string in bytes. */ + int x, int y) /* Coordinates at which to place origin * + * of string when drawing. */ +{ + FontFamily *lastFamilyPtr, *thisFamilyPtr; + Tcl_DString runString; + CONST char *p, *end, *next; + Tcl_UniChar ch; + + TextSize(fontPtr->size); + TextFace(fontPtr->style); + + lastFamilyPtr = fontPtr->subFontArray[0].familyPtr; + + end = source + numBytes; + for (p = source; p < end; ) { + next = p + Tcl_UtfToUniChar(p, &ch); + thisFamilyPtr = FindSubFontForChar(fontPtr, ch)->familyPtr; + if (thisFamilyPtr != lastFamilyPtr) { + if (p > source) { + TextFont(lastFamilyPtr->faceNum); + Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source, + p - source, &runString); + MoveTo((short) x, (short) y); + DrawText(Tcl_DStringValue(&runString), 0, + Tcl_DStringLength(&runString)); + x += TextWidth(Tcl_DStringValue(&runString), 0, + Tcl_DStringLength(&runString)); + Tcl_DStringFree(&runString); + source = p; + } + lastFamilyPtr = thisFamilyPtr; + } + p = next; + } + if (p > source) { + TextFont(thisFamilyPtr->faceNum); + Tcl_UtfToExternalDString(lastFamilyPtr->encoding, source, + p - source, &runString); + MoveTo((short) x, (short) y); + DrawText(Tcl_DStringValue(&runString), 0, + Tcl_DStringLength(&runString)); + Tcl_DStringFree(&runString); + } +} + +/* *--------------------------------------------------------------------------- * - * AllocMacFont -- + * TkMacIsCharacterMissing -- * - * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). - * Allocates and intializes the memory for a new TkFont that - * wraps the platform-specific data. + * Given a tkFont and a character determines whether the character has + * a glyph defined in the font or not. Note that this is potentially + * not compatible with Mac OS 8 as it looks at the font handle + * structure directly. Looks into the character array of the font + * handle to determine whether the glyph is defined or not. * * Results: - * Returns pointer to newly constructed TkFont. + * Returns a 1 if the character is missing, a 0 if it is not. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int +TkMacIsCharacterMissing( + Tk_Font tkfont, /* The font we are looking in. */ + unsigned int searchChar) /* The character we are looking for. */ +{ + MacFont *fontPtr = (MacFont *) tkfont; + FMInput fm; + FontRec **fontRecHandle; + + fm.family = fontPtr->subFontArray[0].familyPtr->faceNum; + fm.size = fontPtr->size; + fm.face = fontPtr->style; + fm.needBits = 0; + fm.device = 0; + fm.numer.h = fm.numer.v = fm.denom.h = fm.denom.v = 1; + +#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300) + fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontResult; +#else + fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontHandle; +#endif + return *(short *) ((long) &(*fontRecHandle)->owTLoc + + ((long)((*fontRecHandle)->owTLoc + searchChar + - (*fontRecHandle)->firstChar) * sizeof(short))) == -1; +} + +/* + *--------------------------------------------------------------------------- + * + * InitFont -- + * + * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). + * Initializes the memory for a MacFont that wraps the platform-specific + * data. * * The caller is responsible for initializing the fields of the * TkFont that are used exclusively by the generic TkFont code, and * for releasing those fields before calling TkpDeleteFont(). * + * Results: + * Fills the MacFont structure. + * * Side effects: * Memory allocated. * *--------------------------------------------------------------------------- */ -static TkFont * -AllocMacFont( - TkFont *tkFontPtr, /* If non-NULL, store the information in - * this existing TkFont structure, rather than - * allocating a new structure to hold the - * font; the existing contents of the font - * will be released. If NULL, a new TkFont - * structure is allocated. */ +static void +InitFont( Tk_Window tkwin, /* For display where font will be used. */ - int family, /* Macintosh font family. */ + int faceNum, /* Macintosh font number. */ int size, /* Point size for Macintosh font. */ - int style) /* Macintosh style bits. */ + int style, /* Macintosh style bits. */ + MacFont *fontPtr) /* Filled with information constructed from + * the above arguments. */ { - char buf[257]; + Str255 nativeName; FontInfo fi; - MacFont *fontPtr; TkFontAttributes *faPtr; TkFontMetrics *fmPtr; CGrafPtr saveWorld; GDHandle saveDevice; + short pixels; - if (gWorld == NULL) { - Rect rect = {0, 0, 1, 1}; - - if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) { - panic("NewGWorld failed in AllocMacFont"); - } + if (size == 0) { + size = -GetDefFontSize(); } + pixels = (short) TkFontGetPixels(tkwin, size); + GetGWorld(&saveWorld, &saveDevice); SetGWorld(gWorld, NULL); + TextFont(faceNum); + TextSize(pixels); + TextFace(style); - if (tkFontPtr == NULL) { - fontPtr = (MacFont *) ckalloc(sizeof(MacFont)); - } else { - fontPtr = (MacFont *) tkFontPtr; - } + GetFontInfo(&fi); + GetFontName(faceNum, nativeName); fontPtr->font.fid = (Font) fontPtr; - faPtr = &fontPtr->font.fa; - GetFontName(family, (StringPtr) buf); - buf[UCHAR(buf[0]) + 1] = '\0'; - faPtr->family = Tk_GetUid(buf + 1); - faPtr->pointsize = size; + faPtr = &fontPtr->font.fa; + faPtr->family = GetUtfFaceName(nativeName); + faPtr->size = TkFontGetPoints(tkwin, size); faPtr->weight = (style & bold) ? TK_FW_BOLD : TK_FW_NORMAL; faPtr->slant = (style & italic) ? TK_FS_ITALIC : TK_FS_ROMAN; faPtr->underline = ((style & underline) != 0); faPtr->overstrike = 0; - fmPtr = &fontPtr->font.fm; - TextFont(family); - TextSize(size); - TextFace(style); - GetFontInfo(&fi); + fmPtr = &fontPtr->font.fm; fmPtr->ascent = fi.ascent; fmPtr->descent = fi.descent; fmPtr->maxWidth = fi.widMax; fmPtr->fixed = (CharWidth('i') == CharWidth('w')); - - fontPtr->family = (short) family; - fontPtr->size = (short) size; + + fontPtr->size = pixels; fontPtr->style = (short) style; + + fontPtr->numSubFonts = 1; + fontPtr->subFontArray = fontPtr->staticSubFonts; + InitSubFont(fontPtr, faceNum, &fontPtr->subFontArray[0]); SetGWorld(saveWorld, saveDevice); +} + +/* + *------------------------------------------------------------------------- + * + * ReleaseFont -- + * + * Called to release the Macintosh-specific contents of a TkFont. + * The caller is responsible for freeing the memory used by the + * font itself. + * + * Results: + * None. + * + * Side effects: + * Memory is freed. + * + *--------------------------------------------------------------------------- + */ + +static void +ReleaseFont( + MacFont *fontPtr) /* The font to delete. */ +{ + int i; - return (TkFont *) fontPtr; + for (i = 0; i < fontPtr->numSubFonts; i++) { + ReleaseSubFont(&fontPtr->subFontArray[i]); + } + if (fontPtr->subFontArray != fontPtr->staticSubFonts) { + ckfree((char *) fontPtr->subFontArray); + } +} + +/* + *------------------------------------------------------------------------- + * + * InitSubFont -- + * + * Wrap a screen font and load the FontFamily that represents + * it. Used to prepare a SubFont so that characters can be mapped + * from UTF-8 to the charset of the font. + * + * Results: + * The subFontPtr is filled with information about the font. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +static void +InitSubFont( + CONST MacFont *fontPtr, /* Font object in which the SubFont will be + * used. */ + int faceNum, /* The font number. */ + SubFont *subFontPtr) /* Filled with SubFont constructed from + * above attributes. */ +{ + subFontPtr->familyPtr = AllocFontFamily(fontPtr, faceNum); + subFontPtr->fontMap = subFontPtr->familyPtr->fontMap; +} + +/* + *------------------------------------------------------------------------- + * + * ReleaseSubFont -- + * + * Called to release the contents of a SubFont. The caller is + * responsible for freeing the memory used by the SubFont itself. + * + * Results: + * None. + * + * Side effects: + * Memory and resources are freed. + * + *--------------------------------------------------------------------------- + */ + +static void +ReleaseSubFont( + SubFont *subFontPtr) /* The SubFont to delete. */ +{ + FreeFontFamily(subFontPtr->familyPtr); +} + +/* + *------------------------------------------------------------------------- + * + * AllocFontFamily -- + * + * Find the FontFamily structure associated with the given font + * family. The information should be stored by the caller in a + * SubFont and used when determining if that SubFont supports a + * character. + * + * Results: + * A pointer to a FontFamily. The reference count in the FontFamily + * is automatically incremented. When the SubFont is released, the + * reference count is decremented. When no SubFont is using this + * FontFamily, it may be deleted. + * + * Side effects: + * A new FontFamily structure will be allocated if this font family + * has not been seen. + * + *------------------------------------------------------------------------- + */ + +static FontFamily * +AllocFontFamily( + CONST MacFont *fontPtr, /* Font object in which the FontFamily will + * be used. */ + int faceNum) /* The font number. */ +{ + FontFamily *familyPtr; + int i; + + familyPtr = fontFamilyList; + for (; familyPtr != NULL; familyPtr = familyPtr->nextPtr) { + if (familyPtr->faceNum == faceNum) { + familyPtr->refCount++; + return familyPtr; + } + } + + familyPtr = (FontFamily *) ckalloc(sizeof(FontFamily)); + memset(familyPtr, 0, sizeof(FontFamily)); + familyPtr->nextPtr = fontFamilyList; + fontFamilyList = familyPtr; + + /* + * Set key for this FontFamily. + */ + + familyPtr->faceNum = faceNum; + + /* + * An initial refCount of 2 means that FontFamily information will + * persist even when the SubFont that loaded the FontFamily is released. + * Change it to 1 to cause FontFamilies to be unloaded when not in use. + */ + + familyPtr->refCount = 2; + familyPtr->encoding = GetFontEncoding(faceNum, 1, &familyPtr->isSymbolFont); + familyPtr->isMultiByteFont = 0; + FillParseTable(familyPtr->typeTable, FontToScript(faceNum)); + for (i = 0; i < 256; i++) { + if (familyPtr->typeTable[i] != 0) { + familyPtr->isMultiByteFont = 1; + break; + } + } + return familyPtr; +} + +/* + *------------------------------------------------------------------------- + * + * FreeFontFamily -- + * + * Called to free a FontFamily when the SubFont is finished using it. + * Frees the contents of the FontFamily and the memory used by the + * FontFamily itself. + * + * Results: + * None. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +static void +FreeFontFamily( + FontFamily *familyPtr) /* The FontFamily to delete. */ +{ + FontFamily **familyPtrPtr; + int i; + + if (familyPtr == NULL) { + return; + } + familyPtr->refCount--; + if (familyPtr->refCount > 0) { + return; + } + Tcl_FreeEncoding(familyPtr->encoding); + for (i = 0; i < FONTMAP_PAGES; i++) { + if (familyPtr->fontMap[i] != NULL) { + ckfree((char *) familyPtr->fontMap[i]); + } + } + + /* + * Delete from list. + */ + + for (familyPtrPtr = &fontFamilyList; ; ) { + if (*familyPtrPtr == familyPtr) { + *familyPtrPtr = familyPtr->nextPtr; + break; + } + familyPtrPtr = &(*familyPtrPtr)->nextPtr; + } + + ckfree((char *) familyPtr); } + +/* + *------------------------------------------------------------------------- + * + * FindSubFontForChar -- + * + * Determine which physical screen font is necessary to use to + * display the given character. If the font object does not have + * a screen font that can display the character, another screen font + * may be loaded into the font object, following a set of preferred + * fallback rules. + * + * Results: + * The return value is the SubFont to use to display the given + * character. + * + * Side effects: + * The contents of fontPtr are modified to cache the results + * of the lookup and remember any SubFonts that were dynamically + * loaded. + * + *------------------------------------------------------------------------- + */ + +static SubFont * +FindSubFontForChar( + MacFont *fontPtr, /* The font object with which the character + * will be displayed. */ + int ch) /* The Unicode character to be displayed. */ +{ + int i, j, k; + char *fallbackName; + char **aliases; + SubFont *subFontPtr; + FontNameMap *mapPtr; + Tcl_DString faceNames; + char ***fontFallbacks; + char **anyFallbacks; + + if (FontMapLookup(&fontPtr->subFontArray[0], ch)) { + return &fontPtr->subFontArray[0]; + } + + for (i = 1; i < fontPtr->numSubFonts; i++) { + if (FontMapLookup(&fontPtr->subFontArray[i], ch)) { + return &fontPtr->subFontArray[i]; + } + } + /* + * Keep track of all face names that we check, so we don't check some + * name multiple times if it can be reached by multiple paths. + */ + + Tcl_DStringInit(&faceNames); + + aliases = TkFontGetAliasList(fontPtr->font.fa.family); + + subFontPtr = NULL; + fontFallbacks = TkFontGetFallbacks(); + for (i = 0; fontFallbacks[i] != NULL; i++) { + for (j = 0; fontFallbacks[i][j] != NULL; j++) { + fallbackName = fontFallbacks[i][j]; + if (strcasecmp(fallbackName, fontPtr->font.fa.family) == 0) { + /* + * If the base font has a fallback... + */ + + goto tryfallbacks; + } else if (aliases != NULL) { + /* + * Or if an alias for the base font has a fallback... + */ + + for (k = 0; aliases[k] != NULL; k++) { + if (strcasecmp(aliases[k], fallbackName) == 0) { + goto tryfallbacks; + } + } + } + } + continue; + + /* + * ...then see if we can use one of the fallbacks, or an + * alias for one of the fallbacks. + */ + + tryfallbacks: + for (j = 0; fontFallbacks[i][j] != NULL; j++) { + fallbackName = fontFallbacks[i][j]; + subFontPtr = CanUseFallbackWithAliases(fontPtr, fallbackName, + ch, &faceNames); + if (subFontPtr != NULL) { + goto end; + } + } + } + + /* + * See if we can use something from the global fallback list. + */ + + anyFallbacks = TkFontGetGlobalClass(); + for (i = 0; anyFallbacks[i] != NULL; i++) { + fallbackName = anyFallbacks[i]; + subFontPtr = CanUseFallbackWithAliases(fontPtr, fallbackName, ch, + &faceNames); + if (subFontPtr != NULL) { + goto end; + } + } + + /* + * Try all face names available in the whole system until we + * find one that can be used. + */ + + for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) { + fallbackName = mapPtr->utfName; + if (SeenName(fallbackName, &faceNames) == 0) { + subFontPtr = CanUseFallback(fontPtr, fallbackName, ch); + if (subFontPtr != NULL) { + goto end; + } + } + } + + end: + Tcl_DStringFree(&faceNames); + + if (subFontPtr == NULL) { + /* + * No font can display this character. We will use the base font + * and have it display the "unknown" character. + */ + + subFontPtr = &fontPtr->subFontArray[0]; + FontMapInsert(subFontPtr, ch); + } + return subFontPtr; +} + +/* + *------------------------------------------------------------------------- + * + * FontMapLookup -- + * + * See if the screen font can display the given character. + * + * Results: + * The return value is 0 if the screen font cannot display the + * character, non-zero otherwise. + * + * Side effects: + * New pages are added to the font mapping cache whenever the + * character belongs to a page that hasn't been seen before. + * When a page is loaded, information about all the characters on + * that page is stored, not just for the single character in + * question. + * + *------------------------------------------------------------------------- + */ + +static int +FontMapLookup( + SubFont *subFontPtr, /* Contains font mapping cache to be queried + * and possibly updated. */ + int ch) /* Character to be tested. */ +{ + int row, bitOffset; + + row = ch >> FONTMAP_SHIFT; + if (subFontPtr->fontMap[row] == NULL) { + FontMapLoadPage(subFontPtr, row); + } + bitOffset = ch & (FONTMAP_BITSPERPAGE - 1); + return (subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1; +} + +/* + *------------------------------------------------------------------------- + * + * FontMapInsert -- + * + * Tell the font mapping cache that the given screen font should be + * used to display the specified character. This is called when no + * font on the system can be be found that can display that + * character; we lie to the font and tell it that it can display + * the character, otherwise we would end up re-searching the entire + * fallback hierarchy every time that character was seen. + * + * Results: + * None. + * + * Side effects: + * New pages are added to the font mapping cache whenever the + * character belongs to a page that hasn't been seen before. + * When a page is loaded, information about all the characters on + * that page is stored, not just for the single character in + * question. + * + *------------------------------------------------------------------------- + */ + +static void +FontMapInsert( + SubFont *subFontPtr, /* Contains font mapping cache to be + * updated. */ + int ch) /* Character to be added to cache. */ +{ + int row, bitOffset; + + row = ch >> FONTMAP_SHIFT; + if (subFontPtr->fontMap[row] == NULL) { + FontMapLoadPage(subFontPtr, row); + } + bitOffset = ch & (FONTMAP_BITSPERPAGE - 1); + subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); +} + +/* + *------------------------------------------------------------------------- + * + * FontMapLoadPage -- + * + * Load information about all the characters on a given page. + * This information consists of one bit per character that indicates + * whether the associated HFONT can (1) or cannot (0) display the + * characters on the page. + * + * Results: + * None. + * + * Side effects: + * Mempry allocated. + * + *------------------------------------------------------------------------- + */ +static void +FontMapLoadPage( + SubFont *subFontPtr, /* Contains font mapping cache to be + * updated. */ + int row) /* Index of the page to be loaded into + * the cache. */ +{ + FMInput fm; + FontRec *fontRecPtr; + short *widths; + int i, end, bitOffset, isMultiByteFont; + char src[TCL_UTF_MAX]; + unsigned char buf[16]; + int srcRead, dstWrote; + Tcl_Encoding encoding; + + subFontPtr->fontMap[row] = (char *) ckalloc(FONTMAP_BITSPERPAGE / 8); + memset(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8); + + encoding = subFontPtr->familyPtr->encoding; + + fm.family = subFontPtr->familyPtr->faceNum; + fm.size = 12; + fm.face = 0; + fm.needBits = 0; + fm.device = 0; + fm.numer.h = 1; + fm.numer.v = 1; + fm.denom.h = 1; + fm.denom.v = 1; + +#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300) + fontRecPtr = *((FontRec **) FMSwapFont(&fm)->fontResult); +#else + fontRecPtr = *((FontRec **) FMSwapFont(&fm)->fontHandle); +#endif + widths = (short *) ((long) &fontRecPtr->owTLoc + + ((long) (fontRecPtr->owTLoc - fontRecPtr->firstChar) + * sizeof(short))); + isMultiByteFont = subFontPtr->familyPtr->isMultiByteFont; + + end = (row + 1) << FONTMAP_SHIFT; + for (i = row << FONTMAP_SHIFT; i < end; i++) { + if (Tcl_UtfToExternal(NULL, encoding, src, Tcl_UniCharToUtf(i, src), + TCL_ENCODING_STOPONERROR, NULL, (char *) buf, sizeof(buf), + &srcRead, &dstWrote, NULL) == TCL_OK) { + + if (((isMultiByteFont != 0) && (buf[0] > 31)) + || (widths[buf[0]] != -1)) { + if ((buf[0] == 0x11) && (widths[0x12] == -1)) { + continue; + } + + /* + * Mac's char existence metrics are only for one-byte + * characters. If we have a double-byte char, just + * assume that the font supports that char if the font's + * encoding supports that char. + */ + + bitOffset = i & (FONTMAP_BITSPERPAGE - 1); + subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); + } + } + } +} + +/* + *--------------------------------------------------------------------------- + * + * CanUseFallbackWithAliases -- + * + * Helper function for FindSubFontForChar. Determine if the + * specified face name (or an alias of the specified face name) + * can be used to construct a screen font that can display the + * given character. + * + * Results: + * See CanUseFallback(). + * + * Side effects: + * If the name and/or one of its aliases was rejected, the + * rejected string is recorded in nameTriedPtr so that it won't + * be tried again. + * + *--------------------------------------------------------------------------- + */ + +static SubFont * +CanUseFallbackWithAliases( + MacFont *fontPtr, /* The font object that will own the new + * screen font. */ + char *faceName, /* Desired face name for new screen font. */ + int ch, /* The Unicode character that the new + * screen font must be able to display. */ + Tcl_DString *nameTriedPtr) /* Records face names that have already + * been tried. It is possible for the same + * face name to be queried multiple times when + * trying to find a suitable screen font. */ +{ + SubFont *subFontPtr; + char **aliases; + int i; + + if (SeenName(faceName, nameTriedPtr) == 0) { + subFontPtr = CanUseFallback(fontPtr, faceName, ch); + if (subFontPtr != NULL) { + return subFontPtr; + } + } + aliases = TkFontGetAliasList(faceName); + if (aliases != NULL) { + for (i = 0; aliases[i] != NULL; i++) { + if (SeenName(aliases[i], nameTriedPtr) == 0) { + subFontPtr = CanUseFallback(fontPtr, aliases[i], ch); + if (subFontPtr != NULL) { + return subFontPtr; + } + } + } + } + return NULL; +} + +/* + *--------------------------------------------------------------------------- + * + * SeenName -- + * + * Used to determine we have already tried and rejected the given + * face name when looking for a screen font that can support some + * Unicode character. + * + * Results: + * The return value is 0 if this face name has not already been seen, + * non-zero otherwise. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +static int +SeenName( + CONST char *name, /* The name to check. */ + Tcl_DString *dsPtr) /* Contains names that have already been + * seen. */ +{ + CONST char *seen, *end; + + seen = Tcl_DStringValue(dsPtr); + end = seen + Tcl_DStringLength(dsPtr); + while (seen < end) { + if (strcasecmp(seen, name) == 0) { + return 1; + } + seen += strlen(seen) + 1; + } + Tcl_DStringAppend(dsPtr, (char *) name, (int) (strlen(name) + 1)); + return 0; +} + +/* + *------------------------------------------------------------------------- + * + * CanUseFallback -- + * + * If the specified physical screen font has not already been loaded + * into the font object, determine if the specified physical screen + * font can display the given character. + * + * Results: + * The return value is a pointer to a newly allocated SubFont, owned + * by the font object. This SubFont can be used to display the given + * character. The SubFont represents the screen font with the base set + * of font attributes from the font object, but using the specified + * font name. NULL is returned if the font object already holds + * a reference to the specified physical font or if the specified + * physical font cannot display the given character. + * + * Side effects: + * The font object's subFontArray is updated to contain a reference + * to the newly allocated SubFont. + * + *------------------------------------------------------------------------- + */ + +static SubFont * +CanUseFallback( + MacFont *fontPtr, /* The font object that will own the new + * screen font. */ + CONST char *faceName, /* Desired face name for new screen font. */ + int ch) /* The Unicode character that the new + * screen font must be able to display. */ +{ + int i; + SubFont subFont; + short faceNum; + + if (GetFamilyNum(faceName, &faceNum) == 0) { + return NULL; + } + + /* + * Skip all fonts we've already used. + */ + + for (i = 0; i < fontPtr->numSubFonts; i++) { + if (faceNum == fontPtr->subFontArray[i].familyPtr->faceNum) { + return NULL; + } + } + + /* + * Load this font and see if it has the desired character. + */ + + InitSubFont(fontPtr, faceNum, &subFont); + if (((ch < 256) && (subFont.familyPtr->isSymbolFont)) + || (FontMapLookup(&subFont, ch) == 0)) { + ReleaseSubFont(&subFont); + return NULL; + } + + if (fontPtr->numSubFonts >= SUBFONT_SPACE) { + SubFont *newPtr; + + newPtr = (SubFont *) ckalloc(sizeof(SubFont) + * (fontPtr->numSubFonts + 1)); + memcpy((char *) newPtr, fontPtr->subFontArray, + fontPtr->numSubFonts * sizeof(SubFont)); + if (fontPtr->subFontArray != fontPtr->staticSubFonts) { + ckfree((char *) fontPtr->subFontArray); + } + fontPtr->subFontArray = newPtr; + } + fontPtr->subFontArray[fontPtr->numSubFonts] = subFont; + fontPtr->numSubFonts++; + return &fontPtr->subFontArray[fontPtr->numSubFonts - 1]; +} + +/* + *------------------------------------------------------------------------- + * + * GetFamilyNum -- + * + * Determines if any physical screen font exists on the system with + * the given family name. If the family exists, then it should be + * possible to construct some physical screen font with that family + * name. + * + * Results: + * The return value is 0 if the specified font family does not exist, + * non-zero otherwise. *faceNumPtr is filled with the unique face + * number that identifies the screen font, or 0 if the font family + * did not exist. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +static int +GetFamilyNum( + CONST char *faceName, /* UTF-8 name of font family to query. */ + short *faceNumPtr) /* Filled with font number for above family. */ +{ + FontNameMap *mapPtr; + + if (faceName != NULL) { + for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) { + if (strcasecmp(faceName, mapPtr->utfName) == 0) { + *faceNumPtr = mapPtr->faceNum; + return 1; + } + } + } + *faceNumPtr = 0; + return 0; +} + +static int +GetFamilyOrAliasNum( + CONST char *faceName, /* UTF-8 name of font family to query. */ + short *faceNumPtr) /* Filled with font number for above family. */ +{ + char **aliases; + int i; + + if (GetFamilyNum(faceName, faceNumPtr) != 0) { + return 1; + } + aliases = TkFontGetAliasList(faceName); + if (aliases != NULL) { + for (i = 0; aliases[i] != NULL; i++) { + if (GetFamilyNum(aliases[i], faceNumPtr) != 0) { + return 1; + } + } + } + return 0; +} + +/* + *------------------------------------------------------------------------- + * + * GetUtfFaceName -- + * + * Given the native name for a Macintosh font (in which the name of + * the font is in the encoding of the font itself), return the UTF-8 + * name that corresponds to that font. The specified font name must + * refer to a font that actually exists on the machine. + * + * This function is used to obtain the UTF-8 name when querying the + * properties of a Macintosh font object. + * + * Results: + * The return value is a pointer to the UTF-8 of the specified font. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------ + */ + +static Tk_Uid +GetUtfFaceName( + StringPtr nativeName) /* Pascal name for font in native encoding. */ +{ + FontNameMap *mapPtr; + + for (mapPtr = gFontNameMap; mapPtr->utfName != NULL; mapPtr++) { + if (pstrcmp(nativeName, mapPtr->nativeName) == 0) { + return mapPtr->utfName; + } + } + panic("GetUtfFaceName: unexpected nativeName"); + return NULL; +} + +/* + *------------------------------------------------------------------------ + * + * GetFontEncoding -- + * + * Return a string that can be passed to Tcl_GetTextEncoding() and + * used to convert bytes from UTF-8 into the encoding of the + * specified font. + * + * The desired encoding to use to convert the name of a symbolic + * font into UTF-8 is macRoman, while the desired encoding to use + * to convert bytes in a symbolic font to UTF-8 is the corresponding + * symbolic encoding. Due to this dual interpretatation of symbolic + * fonts, the caller can specify what type of encoding to return + * should the specified font be symbolic. + * + * Results: + * The return value is a string that specifies the font's encoding. + * If the font's encoding could not be identified, NULL is returned. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------ + */ + +static Tcl_Encoding +GetFontEncoding( + int faceNum, /* Macintosh font number. */ + int allowSymbol, /* If non-zero, then the encoding string + * for symbol fonts will be the corresponding + * symbol encoding. Otherwise, the encoding + * string for symbol fonts will be + * "macRoman". */ + int *isSymbolPtr) /* Filled with non-zero if this font is a + * symbol font, 0 otherwise. */ +{ + Str255 faceName; + int script, lang; + char *name; + + if (allowSymbol != 0) { + GetFontName(faceNum, faceName); + if (pstrcasecmp(faceName, "\psymbol") == 0) { + *isSymbolPtr = 1; + return Tcl_GetEncoding(NULL, "symbol"); + } + if (pstrcasecmp(faceName, "\pzapf dingbats") == 0) { + *isSymbolPtr = 1; + return Tcl_GetEncoding(NULL, "macDingbats"); + } + } + + *isSymbolPtr = 0; + + script = FontToScript(faceNum); + lang = GetScriptVariable(script, smScriptLang); + name = NULL; + if (script == smRoman) { + name = TkFindStateString(romanMap, lang); + } else if (script == smCyrillic) { + name = TkFindStateString(cyrillicMap, lang); + } + if (name == NULL) { + name = TkFindStateString(scriptMap, script); + } + return Tcl_GetEncoding(NULL, name); +} diff --git a/mac/tkMacHLEvents.c b/mac/tkMacHLEvents.c index 39f7836..bbf56fb 100644 --- a/mac/tkMacHLEvents.c +++ b/mac/tkMacHLEvents.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacHLEvents.c 1.21 97/09/17 17:19:00 + * SCCS: @(#) tkMacHLEvents.c 1.22 97/11/07 21:20:50 */ #include "tcl.h" @@ -361,10 +361,12 @@ ScriptHandler( if (tclErr >= 0) { if (tclErr == TCL_OK) { AEPutParamPtr(reply, keyDirectObject, typeChar, - interp->result, strlen(interp->result)); + Tcl_GetStringResult(interp), + strlen(Tcl_GetStringResult(interp))); } else { AEPutParamPtr(reply, keyErrorString, typeChar, - interp->result, strlen(interp->result)); + Tcl_GetStringResult(interp), + strlen(Tcl_GetStringResult(interp))); AEPutParamPtr(reply, keyErrorNumber, typeInteger, (Ptr) &tclErr, sizeof(int)); } diff --git a/mac/tkMacInit.c b/mac/tkMacInit.c index bb1f8b3..11f730a 100644 --- a/mac/tkMacInit.c +++ b/mac/tkMacInit.c @@ -4,7 +4,7 @@ * This file contains Mac-specific interpreter initialization * functions. * - * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * Copyright (c) 1995-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. @@ -41,7 +41,7 @@ QDGlobalsPtr tcl_macQdPtr = NULL; * * Results: * A standard Tcl completion code (TCL_OK or TCL_ERROR). Also - * leaves information in interp->result. + * leaves information in the interp's result. * * Side effects: * Sets "tk_library" Tcl variable, runs initialization scripts diff --git a/mac/tkMacInt.h b/mac/tkMacInt.h index fcb8174..7cbb21e 100644 --- a/mac/tkMacInt.h +++ b/mac/tkMacInt.h @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacInt.h 1.67 97/11/20 18:30:38 + * SCCS:@(#) tkMacInt.h 1.69 98/02/18 10:50:53 */ #ifndef _TKMACINT @@ -73,6 +73,24 @@ typedef struct TkMacWindowList { */ /* + * This structure is for handling Netscape-type in process + * embedding where Tk does not control the top-level. It contains + * various functions that are needed by Mac specific routines, like + * TkMacGetDrawablePort. The definitions of the function types + * are in tclMac.h. + */ + +typedef struct { + Tk_MacEmbedRegisterWinProc *registerWinProc; + Tk_MacEmbedGetGrafPortProc *getPortProc; + Tk_MacEmbedMakeContainerExistProc *containerExistProc; + Tk_MacEmbedGetClipProc *getClipProc; + Tk_MacEmbedGetOffsetInParentProc *getOffsetProc; +} TkMacEmbedHandler; + +extern TkMacEmbedHandler *gMacEmbedHandler; + +/* * Defines used for TkMacInvalidateWindow */ @@ -233,6 +251,7 @@ extern int TkMacGrowToplevel _ANSI_ARGS_((WindowRef whichWindow, Point start)); extern void TkMacHandleMenuSelect _ANSI_ARGS_((long mResult, int optionKeyPressed)); +extern int TkMacHaveAppearance _ANSI_ARGS_((void)); extern void TkMacInitAppleEvents _ANSI_ARGS_((Tcl_Interp *interp)); extern void TkMacInitMenus _ANSI_ARGS_((Tcl_Interp *interp)); extern void TkMacInvalidateWindow _ANSI_ARGS_((MacDrawable *macWin, int flag)); diff --git a/mac/tkMacKeyboard.c b/mac/tkMacKeyboard.c index a1dfad8..3c10b58 100644 --- a/mac/tkMacKeyboard.c +++ b/mac/tkMacKeyboard.c @@ -3,12 +3,12 @@ * * Routines to support keyboard events on the Macintosh. * - * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * Copyright (c) 1995-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. * - * SCCS: @(#) tkMacKeyboard.c 1.14 96/08/15 15:34:00 + * SCCS: @(#) tkMacKeyboard.c 1.16 98/01/16 10:42:35 */ #include "tkInt.h" @@ -137,7 +137,7 @@ XKeycodeToKeysym( int index) { register Tcl_HashEntry *hPtr; - register char c; + int c; char virtualKey; int newKeycode; unsigned long dummy, newChar; @@ -146,8 +146,11 @@ XKeycodeToKeysym( InitKeyMaps(); } - c = keycode & charCodeMask; - virtualKey = (keycode & keyCodeMask) >> 8; + virtualKey = (char) (keycode >> 16); + c = (keycode) & 0xffff; + if (c > 255) { + return NoSymbol; + } /* * When determining what keysym to produce we firt check to see if @@ -161,8 +164,6 @@ XKeycodeToKeysym( return (KeySym) Tcl_GetHashValue(hPtr); } } - - hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) virtualKey); if (hPtr != NULL) { return (KeySym) Tcl_GetHashValue(hPtr); @@ -190,60 +191,63 @@ XKeycodeToKeysym( /* *---------------------------------------------------------------------- * - * XLookupString -- + * TkpGetString -- * * Retrieve the string equivalent for the given keyboard event. * * Results: - * Returns the number of characters stored in buffer_return. + * Returns the UTF string. * * Side effects: - * Retrieves the characters stored in the event and inserts them - * into buffer_return. + * None. * *---------------------------------------------------------------------- */ -int -XLookupString( - XKeyEvent* event_struct, - char* buffer_return, - int bytes_buffer, - KeySym* keysym_return, - XComposeStatus* status_in_out) +char * +TkpGetString( + TkWindow *winPtr, /* Window where event occurred: needed to + * get input context. */ + XEvent *eventPtr, /* X keyboard event. */ + Tcl_DString *dsPtr) /* Uninitialized or empty string to hold + * result. */ { register Tcl_HashEntry *hPtr; char string[3]; char virtualKey; - char c; + int c, len; if (!initialized) { InitKeyMaps(); } - - c = event_struct->keycode & charCodeMask; - string[0] = c; - string[1] = '\0'; + + Tcl_DStringInit(dsPtr); + + virtualKey = (char) (eventPtr->xkey.keycode >> 16); + c = (eventPtr->xkey.keycode) & 0xffff; + + if (c < 256) { + string[0] = (char) c; + len = 1; + } else { + string[0] = (char) (c >> 8); + string[1] = (char) c; + len = 2; + } /* * Just return NULL if the character is a function key or another * non-printing key. */ if (c == 0x10) { - string[0] = '\0'; + len = 0; } else { - virtualKey = (event_struct->keycode & keyCodeMask) >> 8; hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) virtualKey); if (hPtr != NULL) { - string[0] = '\0'; + len = 0; } } - - if (buffer_return != NULL) { - strncpy(buffer_return, string, bytes_buffer); - } - - return strlen(string); + return Tcl_ExternalToUtfDString(NULL, string, len, dsPtr); } /* @@ -377,7 +381,7 @@ XKeysymToKeycode( virtualKeyCode = 0x24; keysym = '\r'; } - keycode = keysym + ((virtualKeyCode << 8) & keyCodeMask); + keycode = keysym + (virtualKeyCode <<16); } return keycode; diff --git a/mac/tkMacLibrary.r b/mac/tkMacLibrary.r index c86954a..1d9c041 100644 --- a/mac/tkMacLibrary.r +++ b/mac/tkMacLibrary.r @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacLibrary.r 1.9 97/11/20 18:31:20 + * SCCS: @(#) tkMacLibrary.r 1.10 98/02/10 10:37:21 */ /* @@ -118,8 +118,6 @@ read 'TEXT' (TK_LIBRARY_RESOURCES+16, "msgbox", purgeable, preload) "::library:msgbox.tcl"; read 'TEXT' (TK_LIBRARY_RESOURCES+17, "comdlg", purgeable, preload) "::library:comdlg.tcl"; -read 'TEXT' (TK_LIBRARY_RESOURCES+18, "prolog", purgeable, preload) - "::library:prolog.ps"; /* * The following two resources define the default "About Box" for Mac Tk. diff --git a/mac/tkMacMenu.c b/mac/tkMacMenu.c index 33bb82b..a44636c 100644 --- a/mac/tkMacMenu.c +++ b/mac/tkMacMenu.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacMenu.c 1.107 97/11/20 18:33:09 + * SCCS: @(#) tkMacMenu.c 1.111 98/01/21 22:04:59 */ #include <Menus.h> @@ -18,11 +18,11 @@ #include <string.h> #include <ToolUtils.h> #include <Balloons.h> -#undef Status -#include <Devices.h> #include "tkMenu.h" #include "tkMacInt.h" -#include "tkMenuButton.h" +#include "tkMenubutton.h" +#undef Status +#include <Devices.h> typedef struct MacMenu { MenuHandle menuHdl; /* The Menu Manager data structure. */ @@ -46,7 +46,7 @@ typedef struct MacMenu { * The following are constants relating to the SICNs used for drawing the MDEF. */ -#define SICN_RESOURCE_NUMBER 128 +#define SICN_RESOURCE_NUMBER 128 #define SICN_HEIGHT 16 #define SICN_ROWS 2 @@ -139,6 +139,8 @@ typedef struct TopLevelMenubarList { #define MENUBAR_REDRAW_PENDING 1 +static int gNoTkMenus = 0; /* This is used by Tk_MacTurnOffMenus as the + * flag that Tk is not to draw any menus. */ RgnHandle tkMenuCascadeRgn = NULL; /* The region to clip drawing to when the * MDEF is up. */ @@ -166,6 +168,9 @@ static char *currentMenuBarName; * DString. */ static Tk_Window currentMenuBarOwner; /* Which window owns the current menu bar. */ +static char elipsisString[TCL_UTF_MAX + 1]; + /* The UTF representation of the elipsis (ƒ) + * character. */ static int helpItemCount; /* The number of items in the help menu. * -1 means that the help menu is * unavailable. This does not include @@ -182,7 +187,8 @@ static MacDrawable macMDEFDrawable; static MDEFScrollFlag = 0; /* Used so that popups don't scroll too soon. */ static int menuBarFlags; /* Used for whether the menu bar needs * redrawing or not. */ -static TkMenuDefUPP menuDefProc;/* The routine descriptor to the MDEF proc. +static TkMenuDefUPP menuDefProc = NULL ; + /* The routine descriptor to the MDEF proc. * The MDEF is needed to draw menus with * non-standard attributes and to support * tearoff menus. */ @@ -240,6 +246,8 @@ static void DrawTearoffEntry _ANSI_ARGS_((TkMenu *menuPtr, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x, int y, int width, int height)); static void FixMDEF _ANSI_ARGS_((void)); +static void GetEntryText _ANSI_ARGS_((TkMenuEntry *mePtr, + Tcl_DString *dStringPtr)); static void GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr, TkMenuEntry *mePtr, Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int *modWidthPtr, @@ -284,6 +292,8 @@ static void RecursivelyInsertMenu _ANSI_ARGS_(( static void SetDefaultMenubar _ANSI_ARGS_((void)); static int SetMenuCascade _ANSI_ARGS_((TkMenu *menuPtr)); static void SetMenuIndicator _ANSI_ARGS_((TkMenuEntry *mePtr)); +static void SetMenuTitle _ANSI_ARGS_((MenuHandle menuHdl, + Tcl_Obj *titlePtr)); /* @@ -308,7 +318,7 @@ static void SetMenuIndicator _ANSI_ARGS_((TkMenuEntry *mePtr)); int TkMacUseMenuID( - short macID) /* The id to take out of the table */ + short macID) /* The id to take out of the table */ { Tcl_HashEntry *commandEntryPtr; int newEntry; @@ -419,6 +429,7 @@ GetNewID( *menuIDPtr = returnID; return TCL_OK; } else { + Tcl_ResetResult(interp); Tcl_AppendResult(interp, "No more menus can be allocated.", (char *) NULL); return TCL_ERROR; @@ -655,7 +666,8 @@ TkpDestroyMenuEntry( * * Given a menu entry, gives back the text that should go in it. * Separators should be done by the caller, as they have to be - * handled specially. + * handled specially. This is primarily used to do a substitution + * between "..." and "ƒ". * * Results: * itemText points to the new text for the item. @@ -669,36 +681,41 @@ TkpDestroyMenuEntry( static void GetEntryText( TkMenuEntry *mePtr, /* A pointer to the menu entry. */ - Str255 itemText) /* The pascal string containing the text */ + Tcl_DString *dStringPtr) /* The DString to put the text into. This + * will be initialized by this routine. */ { + Tcl_DStringInit(dStringPtr); if (mePtr->type == TEAROFF_ENTRY) { - strcpy((char *)itemText, (const char *)"\p(Tear-off)"); - } else if (mePtr->imageString != NULL) { - strcpy((char *)itemText, (const char *)"\p(Image)"); - } else if (mePtr->bitmap != None) { - strcpy((char *)itemText, (const char *)"\p(Pixmap)"); - } else if (mePtr->label == NULL || mePtr->labelLength == 0) { + Tcl_DStringAppend(dStringPtr, "(Tear-off)", -1); + } else if (mePtr->imagePtr != NULL) { + Tcl_DStringAppend(dStringPtr, "(Image)", -1); + } else if (mePtr->bitmapPtr != NULL) { + Tcl_DStringAppend(dStringPtr, "(Pixmap)", -1); + } else if (mePtr->labelPtr == NULL || mePtr->labelLength == 0) { /* * The Mac menu manager does not like null strings. */ - strcpy((char *)itemText, (const char *)"\p "); + Tcl_DStringAppend(dStringPtr, " ", -1); } else { - char *text = mePtr->label; + int length; + char *text = Tcl_GetStringFromObj(mePtr->labelPtr, &length); + char *dStringText; int i; - itemText[0] = 0; - for (i = 1; (*text != '\0') && (i <= 230); i++, text++) { + for (i = 0; i < length; text++, i++) { if ((*text == '.') && (*(text + 1) != '\0') && (*(text + 1) == '.') && (*(text + 2) != '\0') && (*(text + 2) == '.')) { - itemText[i] = 'É'; - text += 2; - } else { - itemText[i] = *text; + Tcl_DStringAppend(dStringPtr, elipsisString, -1); + i += strlen(elipsisString) - 1; + } else { + Tcl_DStringSetLength(dStringPtr, + Tcl_DStringLength(dStringPtr) + 1); + dStringText = Tcl_DStringValue(dStringPtr); + dStringText[i] = *text; } - itemText[0] += 1; } } } @@ -715,10 +732,10 @@ GetEntryText( * We try the following special mac characters. If none of them * are present, just use the check mark. * '' - Check mark character - * '¥' - Bullet character + * '´' - Bullet character * '' - Filled diamond * '×' - Hollow diamond - * 'Ñ' = Long dash ("em dash") + * '„' = Long dash ("em dash") * '-' = short dash (minus, "en dash"); * * Results: @@ -736,19 +753,22 @@ FindMarkCharacter( * for. */ { char markChar; - Tk_Font tkfont = (mePtr->tkfont == NULL) ? mePtr->menuPtr->tkfont - : mePtr->tkfont; + Tk_Font tkfont; + + tkfont = Tk_GetFontFromObj(mePtr->menuPtr->tkwin, + (mePtr->fontPtr == NULL) ? mePtr->menuPtr->fontPtr + : mePtr->fontPtr); if (!TkMacIsCharacterMissing(tkfont, '')) { markChar = ''; - } else if (!TkMacIsCharacterMissing(tkfont, '¥')) { - markChar = '¥'; + } else if (!TkMacIsCharacterMissing(tkfont, '´')) { + markChar = '´'; } else if (!TkMacIsCharacterMissing(tkfont, '')) { markChar = ''; } else if (!TkMacIsCharacterMissing(tkfont, '×')) { markChar = '×'; - } else if (!TkMacIsCharacterMissing(tkfont, 'Ñ')) { - markChar = 'Ñ'; + } else if (!TkMacIsCharacterMissing(tkfont, '„')) { + markChar = '„'; } else if (!TkMacIsCharacterMissing(tkfont, '-')) { markChar = '-'; } else { @@ -781,6 +801,7 @@ SetMenuIndicator( TkMenu *menuPtr = mePtr->menuPtr; MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl; char markChar; + int indicatorOn; /* * There can be no indicators on menus that are not checkbuttons @@ -795,14 +816,14 @@ SetMenuIndicator( if (mePtr->type == CASCADE_ENTRY) { return; } - - if (((mePtr->type == RADIO_BUTTON_ENTRY) - || (mePtr->type == CHECK_BUTTON_ENTRY)) - && (mePtr->indicatorOn) - && (mePtr->entryFlags & ENTRY_SELECTED)) { - markChar = FindMarkCharacter(mePtr); - } else { - markChar = 0; + + markChar = 0; + if ((mePtr->type == RADIO_BUTTON_ENTRY) + || (mePtr->type == CHECK_BUTTON_ENTRY)) { + Tcl_GetBooleanFromObj(NULL, mePtr->indicatorOnPtr, &indicatorOn); + if (indicatorOn && (mePtr->entryFlags & ENTRY_SELECTED)) { + markChar = FindMarkCharacter(mePtr); + } } SetItemMark(macMenuHdl, mePtr->index + 1, markChar); } @@ -829,10 +850,12 @@ SetMenuIndicator( static void SetMenuTitle( MenuHandle menuHdl, /* The menu we are setting the title of. */ - char *title) /* The C string to set the title to. */ + Tcl_Obj *titlePtr) /* The C string to set the title to. */ { int oldLength, newLength, oldHandleSize, dataLength; Ptr menuDataPtr; + char *title = (titlePtr == NULL) ? "" + : Tcl_GetStringFromObj(titlePtr, NULL); menuDataPtr = (Ptr) (*menuHdl)->menuData; @@ -869,7 +892,7 @@ SetMenuTitle( * * Results: * Returns standard TCL result. If TCL_ERROR is returned, then - * interp->result contains an error message. + * the interp's result contains an error message. * * Side effects: * Configuration information get set for mePtr; old resources @@ -909,7 +932,7 @@ TkpConfigureMenuEntry( } if (menuPtr->menuType == MENUBAR) { - SetMenuTitle(childMenuHdl, mePtr->label); + SetMenuTitle(childMenuHdl, mePtr->labelPtr); } } } @@ -925,7 +948,9 @@ TkpConfigureMenuEntry( if (0 == mePtr->accelLength) { ((EntryGeometry *)mePtr->platformEntryData)->accelTextStart = -1; } else { - char *accelString = mePtr->accel; + char *accelString = (mePtr->accelPtr == NULL) ? "" + : Tcl_GetStringFromObj(mePtr->accelPtr, NULL); + char *accel = accelString; mePtr->entryFlags |= ~ENTRY_ACCEL_MASK; while (1) { @@ -971,7 +996,7 @@ TkpConfigureMenuEntry( } ((EntryGeometry *)mePtr->platformEntryData)->accelTextStart - = ((long) accelString - (long) mePtr->accel); + = ((long) accelString - (long) accel); } if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { @@ -1018,11 +1043,17 @@ ReconfigureIndividualMenu( TkMenuEntry *mePtr; Str255 itemText; int parentDisabled = 0; + int state; for (mePtr = menuPtr->menuRefPtr->parentEntryPtr; mePtr != NULL; mePtr = mePtr->nextCascadePtr) { - if (strcmp(Tk_PathName(menuPtr->tkwin), mePtr->name) == 0) { - if (mePtr->state == tkDisabledUid) { + char *name = (mePtr->namePtr == NULL) ? "" + : Tcl_GetStringFromObj(mePtr->namePtr, NULL); + + if (strcmp(Tk_PathName(menuPtr->tkwin), name) == 0) { + Tcl_GetIndexFromObj(NULL, mePtr->statePtr, tkMenuStateStrings, + NULL, 0, &state); + if (state == ENTRY_DISABLED) { parentDisabled = 1; } break; @@ -1051,15 +1082,27 @@ ReconfigureIndividualMenu( if (mePtr->type == SEPARATOR_ENTRY) { AppendMenu(macMenuHdl, SEPARATOR_TEXT); } else { - GetEntryText(mePtr, itemText); + Tcl_DString itemTextDString; + int destWrote; + + GetEntryText(mePtr, &itemTextDString); + Tcl_UtfToExternal(NULL, NULL, Tcl_DStringValue(&itemTextDString), + Tcl_DStringLength(&itemTextDString), 0, NULL, + (char *) &itemText[1], + 231, NULL, &destWrote, NULL); + itemText[0] = destWrote; + AppendMenu(macMenuHdl, "\px"); SetMenuItemText(macMenuHdl, base + index, itemText); + Tcl_DStringFree(&itemTextDString); /* * Set enabling and disabling correctly. */ - if (parentDisabled || (mePtr->state == tkDisabledUid)) { + Tcl_GetIndexFromObj(NULL, mePtr->statePtr, tkMenuStateStrings, + NULL, 0, &state); + if (parentDisabled || (state == ENTRY_DISABLED)) { DisableItem(macMenuHdl, base + index); } else { EnableItem(macMenuHdl, base + index); @@ -1072,9 +1115,13 @@ ReconfigureIndividualMenu( SetItemMark(macMenuHdl, base + index, 0); if ((mePtr->type == CHECK_BUTTON_ENTRY) || (mePtr->type == RADIO_BUTTON_ENTRY)) { + int indicatorOn; + + Tcl_GetBooleanFromObj(NULL, mePtr->indicatorOnPtr, + &indicatorOn); CheckItem(macMenuHdl, base + index, (mePtr->entryFlags - & ENTRY_SELECTED) && (mePtr->indicatorOn)); - if ((mePtr->indicatorOn) + & ENTRY_SELECTED) && (indicatorOn)); + if ((indicatorOn) && (mePtr->entryFlags & ENTRY_SELECTED)) { SetItemMark(macMenuHdl, base + index, FindMarkCharacter(mePtr)); @@ -1116,9 +1163,9 @@ ReconfigureIndividualMenu( if ((mePtr->type != CASCADE_ENTRY) && (ENTRY_COMMAND_ACCEL == (mePtr->entryFlags & ENTRY_ACCEL_MASK))) { - SetItemCmd(macMenuHdl, index, mePtr - ->accel[((EntryGeometry *)mePtr->platformEntryData) - ->accelTextStart]); + char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL); + SetItemCmd(macMenuHdl, index, accel[((EntryGeometry *) + mePtr->platformEntryData)->accelTextStart]); } } } @@ -1396,6 +1443,31 @@ TkpMenuNewEntry( *---------------------------------------------------------------------- * * + * Tk_MacTurnOffMenus -- + * + * Turns off all the menu drawing code. This is more than just disabling + * the "menu" command, this means that Tk will NEVER touch the menubar. + * It is needed in the Plugin, where Tk does not own the menubar. + * + * Results: + * None. + * + * Side effects: + * A flag is set which will disable all menu drawing. + * + *---------------------------------------------------------------------- + */ + +EXTERN void +Tk_MacTurnOffMenus() +{ + gNoTkMenus = 1; +} + +/* + *---------------------------------------------------------------------- + * + * * DrawMenuBarWhenIdle -- * * Update the menu bar next time there is an idle event. @@ -1419,6 +1491,14 @@ DrawMenuBarWhenIdle( Tcl_HashEntry *hashEntryPtr; /* + * If we have been turned off, exit. + */ + + if (gNoTkMenus) { + return; + } + + /* * We need to clear the apple and help menus of any extra items. */ @@ -1527,9 +1607,14 @@ DrawMenuBarWhenIdle( if (menuBarPtr == NULL) { SetDefaultMenubar(); - } else { - if (menuBarPtr->tearOff != menuPtr->tearOff) { - if (menuBarPtr->tearOff) { + } else { + int menuBarTearoff, menuTearoff; + + Tcl_GetBooleanFromObj(NULL, menuBarPtr->tearoffPtr, + &menuBarTearoff); + Tcl_GetBooleanFromObj(NULL, menuPtr->tearoffPtr, &menuTearoff); + if (menuBarTearoff != menuTearoff) { + if (menuBarTearoff) { appleIndex = (-1 == appleIndex) ? appleIndex : appleIndex + 1; helpIndex = (-1 == helpIndex) ? helpIndex @@ -1577,7 +1662,12 @@ DrawMenuBarWhenIdle( for (i = 0; i < menuBarPtr->numEntries; i++) { if (i == appleIndex) { - if (menuBarPtr->entries[i]->state == tkDisabledUid) { + int state; + + Tcl_GetIndexFromObj(NULL, + menuBarPtr->entries[i]->statePtr, + tkMenuStateStrings, NULL, 0, &state); + if (state == ENTRY_DISABLED) { DisableItem(((MacMenu *) menuBarPtr->entries[i] ->childMenuRefPtr->menuPtr ->platformData)->menuHdl, @@ -1613,6 +1703,8 @@ DrawMenuBarWhenIdle( if ((menuBarPtr->entries[i]->childMenuRefPtr != NULL) && menuBarPtr->entries[i]->childMenuRefPtr ->menuPtr != NULL) { + int state; + cascadeMenuPtr = menuBarPtr->entries[i] ->childMenuRefPtr->menuPtr; macMenuHdl = ((MacMenu *) cascadeMenuPtr @@ -1620,7 +1712,10 @@ DrawMenuBarWhenIdle( DeleteMenu((*macMenuHdl)->menuID); InsertMenu(macMenuHdl, 0); RecursivelyInsertMenu(cascadeMenuPtr); - if (menuBarPtr->entries[i]->state == tkDisabledUid) { + Tcl_GetIndexFromObj(NULL, + menuBarPtr->entries[i]->statePtr, + tkMenuStateStrings, NULL, 0, &state); + if (state == ENTRY_DISABLED) { DisableItem(((MacMenu *) menuBarPtr->entries[i] ->childMenuRefPtr->menuPtr ->platformData)->menuHdl, @@ -1675,7 +1770,8 @@ RecursivelyInsertMenu( && (menuPtr->entries[i]->childMenuRefPtr->menuPtr != NULL)) { cascadeMenuPtr = menuPtr->entries[i]->childMenuRefPtr->menuPtr; - macMenuHdl = ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl; + macMenuHdl = + ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl; InsertMenu(macMenuHdl, -1); RecursivelyInsertMenu(cascadeMenuPtr); } @@ -1716,7 +1812,8 @@ RecursivelyDeleteMenu( && (menuPtr->entries[i]->childMenuRefPtr->menuPtr != NULL)) { cascadeMenuPtr = menuPtr->entries[i]->childMenuRefPtr->menuPtr; - macMenuHdl = ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl; + macMenuHdl = + ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl; DeleteMenu((*macMenuHdl)->menuID); RecursivelyInsertMenu(cascadeMenuPtr); } @@ -1826,7 +1923,8 @@ TkpSetMainMenubar( } } if (listPtr != NULL) { - menuName = Tk_PathName(listPtr->menuPtr->masterMenuPtr->tkwin); + menuName = Tk_PathName(listPtr->menuPtr->masterMenuPtr + ->tkwin); break; } } @@ -2028,15 +2126,15 @@ GetMenuAccelGeometry ( } else if (0 == mePtr->accelLength) { *textWidthPtr = 0; } else { + char *accel = (mePtr->accelPtr == NULL) ? "" + : Tcl_GetStringFromObj(mePtr->accelPtr, NULL); if (NULL == GetResource('SICN', SICN_RESOURCE_NUMBER)) { - *textWidthPtr = Tk_TextWidth(tkfont, mePtr->accel, - mePtr->accelLength); + *textWidthPtr = Tk_TextWidth(tkfont, accel, mePtr->accelLength); } else { int emWidth = Tk_TextWidth(tkfont, "W", 1) + 1; if ((mePtr->entryFlags & ENTRY_ACCEL_MASK) == 0) { - int width = Tk_TextWidth(tkfont, mePtr->accel, - mePtr->accelLength); + int width = Tk_TextWidth(tkfont, accel, mePtr->accelLength); *textWidthPtr = emWidth; if (width < emWidth) { *modWidthPtr = 0; @@ -2061,7 +2159,7 @@ GetMenuAccelGeometry ( if (1 == (mePtr->accelLength - length)) { *textWidthPtr = emWidth; } else { - *textWidthPtr += Tk_TextWidth(tkfont, mePtr->accel + *textWidthPtr += Tk_TextWidth(tkfont, accel + length, mePtr->accelLength - length); } } @@ -2163,21 +2261,31 @@ DrawMenuEntryIndicator( int width, /* width of entry */ int height) /* height of entry */ { - if (((mePtr->type == CHECK_BUTTON_ENTRY) || - (mePtr->type == RADIO_BUTTON_ENTRY)) - && (mePtr->indicatorOn) - && (mePtr->entryFlags & ENTRY_SELECTED)) { - int baseline; - short markShort; - char markChar; + if ((mePtr->type == CHECK_BUTTON_ENTRY) || + (mePtr->type == RADIO_BUTTON_ENTRY)) { + int indicatorOn; + + Tcl_GetBooleanFromObj(NULL, mePtr->indicatorOnPtr, &indicatorOn); + + if ((indicatorOn) + && (mePtr->entryFlags & ENTRY_SELECTED)) { + int baseline; + short markShort; - baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2; - GetItemMark(((MacMenu *) menuPtr->platformData)->menuHdl, - mePtr->index + 1, &markShort); - if (markShort != 0) { - markChar = (char) markShort; - Tk_DrawChars(menuPtr->display, d, gc, tkfont, &markChar, 1, - x + 2, baseline); + baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2; + GetItemMark(((MacMenu *) menuPtr->platformData)->menuHdl, + mePtr->index + 1, &markShort); + if (markShort != 0) { + char markChar; + char markCharUTF[TCL_UTF_MAX + 1]; + int dstWrote; + + markChar = (char) markShort; + Tcl_ExternalToUtf(NULL, NULL, &markChar, 1, 0, NULL, + markCharUTF, TCL_UTF_MAX + 1, NULL, &dstWrote, NULL); + Tk_DrawChars(menuPtr->display, d, gc, tkfont, markCharUTF, + dstWrote, x + 2, baseline); + } } } } @@ -2289,6 +2397,10 @@ DrawMenuEntryAccelerator( int height, /* The height of the entry */ int drawArrow) /* Whether or not to draw cascade arrow */ { + int activeBorderWidth; + + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr, + &activeBorderWidth); if (mePtr->type == CASCADE_ENTRY) { if (0 == DrawSICN(SICN_RESOURCE_NUMBER, CASCADE_ARROW, d, gc, x + width - SICN_HEIGHT, (y + (height / 2)) @@ -2297,7 +2409,7 @@ DrawMenuEntryAccelerator( Tk_Window tkwin = menuPtr->tkwin; if (mePtr->type == CASCADE_ENTRY) { - points[0].x = width - menuPtr->activeBorderWidth + points[0].x = width - activeBorderWidth - MAC_MARGIN_WIDTH - CASCADE_ARROW_WIDTH; points[0].y = y + (height - CASCADE_ARROW_HEIGHT)/2; points[1].x = points[0].x; @@ -2311,11 +2423,14 @@ DrawMenuEntryAccelerator( } else if (mePtr->accelLength != 0) { int leftEdge = x + width; int baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2; + char *accel; + + accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL); if (NULL == GetResource('SICN', SICN_RESOURCE_NUMBER)) { leftEdge -= ((EntryGeometry *) mePtr->platformEntryData) ->accelTextWidth; - Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel, + Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel, mePtr->accelLength, leftEdge, baseline); } else { EntryGeometry *geometryPtr = @@ -2327,7 +2442,7 @@ DrawMenuEntryAccelerator( leftEdge -= geometryPtr->modifierWidth; } - Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel + Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel + geometryPtr->accelTextStart, length, leftEdge, baseline); if (mePtr->entryFlags & ENTRY_COMMAND_ACCEL) { @@ -2403,10 +2518,8 @@ DrawMenuSeparator( TkMacSetUpGraphicsPort(mePtr->disabledGC != None ? mePtr->disabledGC : menuPtr->disabledGC); - MoveTo(x, y + (height / 2)); Line(width, 0); - SetGWorld(saveWorld, saveDevice); } @@ -2447,7 +2560,7 @@ MenuDefProc( TkMenuEntry *parentEntryPtr; Tcl_HashEntry *commandEntryPtr; GrafPtr windowMgrPort; - Tk_Font tkfont; + Tk_Font tkfont, menuFont; Tk_FontMetrics fontMetrics, entryMetrics; Tk_FontMetrics *fmPtr; TkMenuEntry *mePtr; @@ -2562,7 +2675,8 @@ MenuDefProc( * that are lower than the bottom. */ - Tk_GetFontMetrics(menuPtr->tkfont, &fontMetrics); + menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); + Tk_GetFontMetrics(menuFont, &fontMetrics); for (i = 0; i < menuPtr->numEntries; i++) { mePtr = menuPtr->entries[i]; if (globalsPtr->menuTop + mePtr->y + mePtr->height @@ -2573,11 +2687,11 @@ MenuDefProc( continue; } ClipRect(&menuClipRect); - if (mePtr->tkfont == NULL) { + if (mePtr->fontPtr == NULL) { fmPtr = &fontMetrics; - tkfont = menuPtr->tkfont; + tkfont = menuFont; } else { - tkfont = mePtr->tkfont; + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr); Tk_GetFontMetrics(tkfont, &entryMetrics); fmPtr = &entryMetrics; } @@ -2598,7 +2712,7 @@ MenuDefProc( break; case mChooseMsg: { - int hasTopScroll, hasBottomScroll; + int hasTopScroll, hasBottomScroll, tearoff; enum { DONT_SCROLL, DOWN_SCROLL, UP_SCROLL } scrollDirection; @@ -2640,8 +2754,12 @@ MenuDefProc( itemRect.bottom = itemRect.top + menuPtr->entries[i]->height; if (PtInRect(hitPt, &itemRect)) { + int state; + + Tcl_GetIndexFromObj(NULL, mePtr->statePtr, + tkMenuStateStrings, NULL, 0, &state); if ((mePtr->type == SEPARATOR_ENTRY) - || (mePtr->state == tkDisabledUid)) { + || (state == ENTRY_DISABLED)) { newItem = -1; } else { TkMenuEntry *cascadeEntryPtr; @@ -2652,10 +2770,17 @@ MenuDefProc( cascadeEntryPtr != NULL; cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) { - if (strcmp(cascadeEntryPtr->name, - Tk_PathName(menuPtr->tkwin)) == 0) { - if (cascadeEntryPtr->state - == tkDisabledUid) { + char *name; + + name = Tcl_GetStringFromObj( + cascadeEntryPtr->namePtr, NULL); + if (strcmp(name, Tk_PathName(menuPtr->tkwin)) + == 0) { + Tcl_GetIndexFromObj(NULL, + cascadeEntryPtr->statePtr, + tkMenuStateStrings, NULL, 0, + &state); + if (state == ENTRY_DISABLED) { parentDisabled = 1; } break; @@ -2707,9 +2832,17 @@ MenuDefProc( ClipRect(&menuClipRect); if (oldItem != newItem) { + int state; + if (oldItem >= 0) { mePtr = menuPtr->entries[oldItem]; - tkfont = mePtr->tkfont ? mePtr->tkfont : menuPtr->tkfont; + if (mePtr->fontPtr == NULL) { + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, + menuPtr->fontPtr); + } else { + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, + mePtr->fontPtr); + } Tk_GetFontMetrics(tkfont, &fontMetrics); TkpDrawMenuEntry(mePtr, (Drawable) &macMDEFDrawable, tkfont, &fontMetrics, @@ -2723,10 +2856,18 @@ MenuDefProc( int oldActiveItem = menuPtr->active; mePtr = menuPtr->entries[newItem]; - if (mePtr->state != tkDisabledUid) { + Tcl_GetIndexFromObj(NULL, mePtr->statePtr, + tkMenuStateStrings, NULL, 0, &state); + if (state != ENTRY_DISABLED) { TkActivateMenuEntry(menuPtr, newItem); } - tkfont = mePtr->tkfont ? mePtr->tkfont : menuPtr->tkfont; + if (mePtr->fontPtr == NULL) { + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, + menuPtr->fontPtr); + } else { + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, + mePtr->fontPtr); + } Tk_GetFontMetrics(tkfont, &fontMetrics); TkpDrawMenuEntry(mePtr, (Drawable) &macMDEFDrawable, tkfont, &fontMetrics, @@ -2742,7 +2883,9 @@ MenuDefProc( MenuSelectEvent(menuPtr); Tcl_ServiceAll(); tkUseMenuCascadeRgn = 0; - if (mePtr->state != tkDisabledUid) { + Tcl_GetIndexFromObj(NULL, mePtr->statePtr, + tkMenuStateStrings, NULL, 0, &state); + if (state != ENTRY_DISABLED) { TkActivateMenuEntry(menuPtr, -1); } *whichItem = newItem + 1; @@ -2755,7 +2898,8 @@ MenuDefProc( - globalsPtr->menuBottom) { scrollAmt = menuRectPtr->bottom - globalsPtr->menuBottom; } - if (!hasTopScroll && ((globalsPtr->menuTop + scrollAmt) < menuRectPtr->top)) { + if (!hasTopScroll && ((globalsPtr->menuTop + scrollAmt) + < menuRectPtr->top)) { SetRect(&updateRect, menuRectPtr->left, globalsPtr->menuTop, menuRectPtr->right, globalsPtr->menuTop + SICN_HEIGHT); @@ -2787,6 +2931,7 @@ MenuDefProc( } } if (scrollDirection != DONT_SCROLL) { + Tk_Font menuFont; RgnHandle updateRgn = NewRgn(); ScrollRect(&menuClipRect, 0, scrollAmt, updateRgn); updateRect = (*updateRgn)->rgnBBox; @@ -2801,7 +2946,8 @@ MenuDefProc( } ClipRect(&updateRect); EraseRect(&updateRect); - Tk_GetFontMetrics(menuPtr->tkfont, &fontMetrics); + menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); + Tk_GetFontMetrics(menuFont, &fontMetrics); for (i = 0; i < menuPtr->numEntries; i++) { mePtr = menuPtr->entries[i]; if (globalsPtr->menuTop + mePtr->y + mePtr->height @@ -2811,11 +2957,12 @@ MenuDefProc( > updateRect.bottom) { continue; } - if (mePtr->tkfont == NULL) { + if (mePtr->fontPtr == NULL) { fmPtr = &fontMetrics; - tkfont = menuPtr->tkfont; + tkfont = menuFont; } else { - tkfont = mePtr->tkfont; + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, + mePtr->fontPtr); Tk_GetFontMetrics(tkfont, &entryMetrics); fmPtr = &entryMetrics; } @@ -2844,18 +2991,24 @@ MenuDefProc( menuRefPtr = TkFindMenuReferences(menuPtr->interp, Tk_PathName(menuPtr->tkwin)); if ((menuRefPtr != NULL) && (menuRefPtr->parentEntryPtr != NULL)) { + char *name; for (parentEntryPtr = menuRefPtr->parentEntryPtr; - strcmp(parentEntryPtr->name, - Tk_PathName(menuPtr->tkwin)) == 0; - parentEntryPtr = parentEntryPtr->nextCascadePtr) { + parentEntryPtr != NULL + ; parentEntryPtr = parentEntryPtr->nextCascadePtr) { + name = Tcl_GetStringFromObj(parentEntryPtr->namePtr, + NULL); + if (strcmp(name, Tk_PathName(menuPtr->tkwin)) != 0) { + break; + } } if (parentEntryPtr != NULL) { TkActivateMenuEntry(parentEntryPtr->menuPtr, - parentEntryPtr->index); + parentEntryPtr->index); } } - if (menuPtr->tearOff) { + Tcl_GetBooleanFromObj(NULL, menuPtr->tearoffPtr, &tearoff); + if (tearoff) { scratchRect = *menuRectPtr; if (tearoffStruct.menuPtr == NULL) { scratchRect.top -= 10; @@ -2982,7 +3135,7 @@ TkMacHandleTearoffMenu(void) { if (tearoffStruct.menuPtr != NULL) { Tcl_DString tearoffCmdStr; - char intString[20]; + char intString[TCL_INTEGER_SPACE]; short windowPart; WindowRef whichWindow; @@ -3092,8 +3245,10 @@ DrawTearoffEntry( { XPoint points[2]; int margin, segmentWidth, maxX; + Tk_3DBorder border; - if ((menuPtr->menuType != MASTER_MENU) || (GetResource('MDEF', 591) != NULL)) { + if ((menuPtr->menuType != MASTER_MENU) + || (GetResource('MDEF', 591) != NULL)) { return; } @@ -3103,13 +3258,14 @@ DrawTearoffEntry( points[1].y = points[0].y; segmentWidth = 6; maxX = width - 1; + border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr); while (points[0].x < maxX) { points[1].x = points[0].x + segmentWidth; if (points[1].x > maxX) { points[1].x = maxX; } - Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 2, 1, + Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1, TK_RELIEF_RAISED); points[0].x += 2*segmentWidth; } @@ -3228,13 +3384,15 @@ TkpDrawMenuEntry( int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0; int adjustedY = y + padY; int adjustedHeight = height - 2 * padY; + int state; /* * Choose the gc for drawing the foreground part of the entry. */ - if ((mePtr->state == tkActiveUid) - && !strictMotif) { + Tcl_GetIndexFromObj(NULL, mePtr->statePtr, tkMenuStateStrings, NULL, + 0, &state); + if ((state == ENTRY_ACTIVE) && !strictMotif) { gc = mePtr->activeGC; if (gc == NULL) { gc = menuPtr->activeGC; @@ -3246,17 +3404,23 @@ TkpDrawMenuEntry( for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr; cascadeEntryPtr != NULL; cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) { - if (strcmp(cascadeEntryPtr->name, - Tk_PathName(menuPtr->tkwin)) == 0) { - if (cascadeEntryPtr->state == tkDisabledUid) { + char *name = (cascadeEntryPtr->namePtr == NULL) ? "" + : Tcl_GetStringFromObj(cascadeEntryPtr->namePtr, NULL); + + if (strcmp(name, Tk_PathName(menuPtr->tkwin)) == 0) { + int cascadeState; + + Tcl_GetIndexFromObj(NULL, cascadeEntryPtr->statePtr, + tkMenuStateStrings, NULL, 0, &cascadeState); + if (cascadeState == ENTRY_DISABLED) { parentDisabled = 1; } break; } } - if (((parentDisabled || (mePtr->state == tkDisabledUid))) - && (menuPtr->disabledFg != NULL)) { + if (((parentDisabled || (state == ENTRY_DISABLED))) + && (menuPtr->disabledFgPtr != NULL)) { gc = mePtr->disabledGC; if (gc == NULL) { gc = menuPtr->disabledGC; @@ -3272,24 +3436,22 @@ TkpDrawMenuEntry( if (indicatorGC == NULL) { indicatorGC = menuPtr->indicatorGC; } - - bgBorder = mePtr->border; - if (bgBorder == NULL) { - bgBorder = menuPtr->border; - } + + bgBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin, + (mePtr->borderPtr == NULL) + ? menuPtr->borderPtr : mePtr->borderPtr); if (strictMotif) { activeBorder = bgBorder; } else { - activeBorder = mePtr->activeBorder; - if (activeBorder == NULL) { - activeBorder = menuPtr->activeBorder; - } + activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin, + (mePtr->activeBorderPtr == NULL) + ? menuPtr->activeBorderPtr : mePtr->activeBorderPtr); } - if (mePtr->tkfont == NULL) { + if (mePtr->fontPtr == NULL) { fmPtr = menuMetricsPtr; } else { - tkfont = mePtr->tkfont; + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr); Tk_GetFontMetrics(tkfont, &entryMetrics); fmPtr = &entryMetrics; } @@ -3310,11 +3472,14 @@ TkpDrawMenuEntry( DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY, width, adjustedHeight); } else { + int hideMargin; + DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY, width, adjustedHeight); DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, activeBorder, x, adjustedY, width, adjustedHeight, drawArrow); - if (!mePtr->hideMargin) { + Tcl_GetBooleanFromObj(NULL, mePtr->hideMarginPtr, &hideMargin); + if (!hideMargin) { DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr, x, adjustedY, width, adjustedHeight); } @@ -3344,13 +3509,13 @@ void TkpComputeStandardMenuGeometry( TkMenu *menuPtr) /* Structure describing menu. */ { - Tk_Font tkfont; + Tk_Font tkfont, menuFont; Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr; int x, y, height, modifierWidth, labelWidth, indicatorSpace; int windowWidth, windowHeight, accelWidth, maxAccelTextWidth; int i, j, lastColumnBreak, maxModifierWidth, maxWidth, nonAccelMargin; int maxNonAccelMargin, maxEntryWithAccelWidth, maxEntryWithoutAccelWidth; - int entryWidth, maxIndicatorSpace; + int entryWidth, maxIndicatorSpace, borderWidth, activeBorderWidth; TkMenuEntry *mePtr, *columnEntryPtr; EntryGeometry *geometryPtr; @@ -3358,7 +3523,11 @@ TkpComputeStandardMenuGeometry( return; } - x = y = menuPtr->borderWidth; + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr, + &borderWidth); + Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr, + &activeBorderWidth); + x = y = borderWidth; indicatorSpace = labelWidth = accelWidth = maxAccelTextWidth = 0; windowHeight = windowWidth = maxWidth = lastColumnBreak = 0; maxModifierWidth = nonAccelMargin = maxNonAccelMargin = 0; @@ -3376,20 +3545,24 @@ TkpComputeStandardMenuGeometry( * give all of the geometry/drawing the entry's font and metrics. */ - Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics); + menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); + Tk_GetFontMetrics(menuFont, &menuMetrics); for (i = 0; i < menuPtr->numEntries; i++) { + int columnBreak; + mePtr = menuPtr->entries[i]; - tkfont = mePtr->tkfont; - if (tkfont == NULL) { - tkfont = menuPtr->tkfont; - fmPtr = &menuMetrics; + if (mePtr->fontPtr == NULL) { + tkfont = menuFont; + fmPtr = &menuMetrics; } else { + tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr); Tk_GetFontMetrics(tkfont, &entryMetrics); fmPtr = &entryMetrics; } - if ((i > 0) && mePtr->columnBreak) { + Tcl_GetBooleanFromObj(NULL, mePtr->columnBreakPtr, &columnBreak); + if ((i > 0) && columnBreak) { if (maxIndicatorSpace != 0) { maxIndicatorSpace += 2; } @@ -3400,7 +3573,7 @@ TkpComputeStandardMenuGeometry( columnEntryPtr->indicatorSpace = maxIndicatorSpace; columnEntryPtr->width = maxIndicatorSpace + maxWidth - + 2 * menuPtr->activeBorderWidth; + + 2 * activeBorderWidth; geometryPtr->accelTextWidth = maxAccelTextWidth; geometryPtr->modifierWidth = maxModifierWidth; columnEntryPtr->x = x; @@ -3415,13 +3588,13 @@ TkpComputeStandardMenuGeometry( geometryPtr->nonAccelMargin = 0; } } - x += maxIndicatorSpace + maxWidth + 2 * menuPtr->borderWidth; + x += maxIndicatorSpace + maxWidth + 2 * borderWidth; windowWidth = x; maxWidth = maxIndicatorSpace = maxAccelTextWidth = 0; maxModifierWidth = maxNonAccelMargin = maxEntryWithAccelWidth = 0; maxEntryWithoutAccelWidth = 0; lastColumnBreak = i; - y = menuPtr->borderWidth; + y = borderWidth; } if (mePtr->type == SEPARATOR_ENTRY) { @@ -3433,6 +3606,9 @@ TkpComputeStandardMenuGeometry( fmPtr, &entryWidth, &height); mePtr->height = height; } else { + int hideMargin; + + Tcl_GetBooleanFromObj(NULL, mePtr->hideMarginPtr, &hideMargin); /* * For each entry, compute the height required by that @@ -3453,7 +3629,7 @@ TkpComputeStandardMenuGeometry( &modifierWidth, &accelWidth, &height); nonAccelMargin = 0; } else if (mePtr->accelLength == 0) { - nonAccelMargin = mePtr->hideMargin ? 0 + nonAccelMargin = hideMargin ? 0 : Tk_TextWidth(tkfont, "m", 1); accelWidth = modifierWidth = 0; } else { @@ -3466,7 +3642,7 @@ TkpComputeStandardMenuGeometry( nonAccelMargin = 0; } - if (!(mePtr->hideMargin)) { + if (!(hideMargin)) { GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, fmPtr, &indicatorSpace, &height); if (height > mePtr->height) { @@ -3506,10 +3682,10 @@ TkpComputeStandardMenuGeometry( } } - mePtr->height += 2 * menuPtr->activeBorderWidth; + mePtr->height += 2 * activeBorderWidth; } mePtr->y = y; - y += menuPtr->entries[i]->height + menuPtr->borderWidth; + y += menuPtr->entries[i]->height + borderWidth; if (y > windowHeight) { windowHeight = y; } @@ -3521,7 +3697,7 @@ TkpComputeStandardMenuGeometry( columnEntryPtr->indicatorSpace = maxIndicatorSpace; columnEntryPtr->width = maxIndicatorSpace + maxWidth - + 2 * menuPtr->activeBorderWidth; + + 2 * activeBorderWidth; geometryPtr->accelTextWidth = maxAccelTextWidth; geometryPtr->modifierWidth = maxModifierWidth; columnEntryPtr->x = x; @@ -3537,8 +3713,8 @@ TkpComputeStandardMenuGeometry( } } windowWidth = x + maxIndicatorSpace + maxWidth - + 2 * menuPtr->activeBorderWidth + menuPtr->borderWidth; - windowHeight += menuPtr->borderWidth; + + 2 * activeBorderWidth + borderWidth; + windowHeight += borderWidth; /* * The X server doesn't like zero dimensions, so round up to at least @@ -3589,6 +3765,7 @@ DrawMenuEntryLabel( int indicatorSpace = mePtr->indicatorSpace; int leftEdge = x + indicatorSpace; int imageHeight, imageWidth; + int state; /* * Draw label or bitmap or image for entry. @@ -3607,30 +3784,31 @@ DrawMenuEntryLabel( imageHeight, d, leftEdge, (int) (y + (mePtr->height - imageHeight)/2)); } - } else if (mePtr->bitmap != None) { + } else if (mePtr->bitmapPtr != NULL) { int width, height; - + Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); Tk_SizeOfBitmap(menuPtr->display, - mePtr->bitmap, &width, &height); - XCopyPlane(menuPtr->display, - mePtr->bitmap, d, - gc, 0, 0, (unsigned) width, (unsigned) height, leftEdge, + bitmap, &width, &height); + XCopyPlane(menuPtr->display, bitmap, d, gc, 0, 0, + (unsigned) width, (unsigned) height, leftEdge, (int) (y + (mePtr->height - height)/2), 1); } else { if (mePtr->labelLength > 0) { - Str255 itemText; + Tcl_DString itemTextDString; - GetEntryText(mePtr, itemText); + GetEntryText(mePtr, &itemTextDString); Tk_DrawChars(menuPtr->display, d, gc, - tkfont, (char *) itemText + 1, itemText[0], + tkfont, Tcl_DStringValue(&itemTextDString), + Tcl_DStringLength(&itemTextDString), leftEdge, baseline); -/* TkpDrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, - width, height);*/ + Tcl_DStringFree(&itemTextDString); } } - if (mePtr->state == tkDisabledUid) { - if (menuPtr->disabledFg == NULL) { + Tcl_GetIndexFromObj(NULL, mePtr->statePtr, tkMenuStateStrings, NULL, + 0, &state); + if (state == ENTRY_DISABLED) { + if (menuPtr->disabledFgPtr == NULL) { XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y, (unsigned) width, (unsigned) height); } else if ((mePtr->image != NULL) @@ -3672,7 +3850,11 @@ DrawMenuEntryBackground( int width, /* width of rectangle to draw */ int height) /* height of rectangle to draw */ { - if (mePtr->state == tkActiveUid) { + int state; + + Tcl_GetIndexFromObj(NULL, mePtr->statePtr, tkMenuStateStrings, NULL, + 0, &state); + if (state == ENTRY_ACTIVE) { bgBorder = activeBorder; } Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, @@ -3710,17 +3892,20 @@ GetMenuLabelGeometry( if (mePtr->image != NULL) { Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr); - } else if (mePtr->bitmap != (Pixmap) NULL) { - Tk_SizeOfBitmap(menuPtr->display, mePtr->bitmap, widthPtr, heightPtr); + } else if (mePtr->bitmapPtr != NULL) { + Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); + Tk_SizeOfBitmap(menuPtr->display, bitmap, widthPtr, heightPtr); } else { *heightPtr = fmPtr->linespace; - if (mePtr->label != NULL) { - Str255 itemText; + if (mePtr->labelPtr != NULL) { + Tcl_DString itemTextDString; - GetEntryText(mePtr, itemText); - *widthPtr = Tk_TextWidth(tkfont, (char *) itemText + 1, - itemText[0]); + GetEntryText(mePtr, &itemTextDString); + *widthPtr = Tk_TextWidth(tkfont, + Tcl_DStringValue(&itemTextDString), + Tcl_DStringLength(&itemTextDString)); + Tcl_DStringFree(&itemTextDString); } else { *widthPtr = 0; } @@ -3882,7 +4067,8 @@ TkMacClearMenubarActive(void) { if ((menuBarRefPtr != NULL) && (menuBarRefPtr->menuPtr != NULL)) { TkMenu *menuPtr; - for (menuPtr = menuBarRefPtr->menuPtr->masterMenuPtr; menuPtr != NULL; + for (menuPtr = menuBarRefPtr->menuPtr->masterMenuPtr; + menuPtr != NULL; menuPtr = menuPtr->nextInstancePtr) { if (menuPtr->menuType == MENUBAR) { RecursivelyClearActiveMenu(menuPtr); @@ -3957,9 +4143,12 @@ FixMDEF(void) if ((MDEFHandle != NULL) && (SICNHandle != NULL)) { MoveHHi(MDEFHandle); HLock(MDEFHandle); - menuDefProc = TkNewMenuDefProc(MenuDefProc); + if ( menuDefProc == NULL) { + menuDefProc = TkNewMenuDefProc(MenuDefProc); + } memmove((void *) (((long) (*MDEFHandle)) + 0x24), &menuDefProc, 4); } + #endif } @@ -3974,7 +4163,7 @@ FixMDEF(void) * None. * * Side effects: - * Allcates a hash table. + * Allocates a hash table. * *---------------------------------------------------------------------- */ @@ -3991,4 +4180,9 @@ TkpMenuInit(void) currentMenuBarInterp = NULL; currentMenuBarName = NULL; windowListPtr = NULL; + FixMDEF(); + + + Tcl_ExternalToUtf(NULL, NULL, "É", -1, 0, NULL, elipsisString, + TCL_UTF_MAX + 1, NULL, NULL, NULL); } diff --git a/mac/tkMacPort.h b/mac/tkMacPort.h index 733e745..e05b7ba 100644 --- a/mac/tkMacPort.h +++ b/mac/tkMacPort.h @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacPort.h 1.52 97/07/28 11:18:59 + * SCCS: @(#) tkMacPort.h 1.53 98/01/08 14:59:32 */ #ifndef _TKMACPORT @@ -90,11 +90,12 @@ extern int strncasecmp _ANSI_ARGS_((CONST char *s1, #define XVisualIDFromVisual(visual) (visual->visualid) /* - * The following functions are not used on the Mac, so we stub it out. + * The following functions are not used on the Mac, so we stub them out. */ #define TkFreeWindowId(dispPtr,w) #define TkInitXId(dispPtr) +#define TkpButtonSetDefaults(specPtr) {} #define TkpCmapStressed(tkwin,colormap) (0) #define TkpFreeColor(tkColPtr) #define TkSetPixmapColormap(p,c) {} diff --git a/mac/tkMacProjects.sit.hqx b/mac/tkMacProjects.sit.hqx new file mode 100644 index 0000000..97ae8be --- /dev/null +++ b/mac/tkMacProjects.sit.hqx @@ -0,0 +1,800 @@ +(This file must be converted with BinHex 4.0) +:#d&bBfKTGQ8ZFfPd!&0*9%46593K!*!%PA%!N!4%'e0*9#%!!`!!PA&b6'&e!RX +!N!-@EhX!$3P8Dep04%9',VQ(b!4BE$J!20%U!*!$J!#3"!4J125YX`#3&!mM!*! +%rj!%68e3FN0A588"!,$B'6'a%)MK!*!'Fhm!N!B1R3!!h98!N!DCC`i!AFIem[- +jj3lP(TkERCDheq5$M%@jqk4QRbHR$MBGj(%*IhTQ-Xr1YlekmI16E#R[#$r##2m +)Pr!NQp$)2R,E5l)*2r*l32N4IQjMC*00f*E`k`JRYmrB%dEfQ3dBi8H1EBpXbEk +-2q'%E8CBY`*IApGRRAPb+[25)V62c3Kr`Lpb@r,Ef!9!0M$qp1eYi&29)#(%4)K +84%JiJa#eQ"#c"f`XNLc"NiPGEI-hHU24J"T92&'edqr6%lD#&*NNNAMF8-EM%JU +UjV)RbXD0K&`9a`p-**)pbDQ'[6je"*@C&*%XkA'j1r%HP!3i3j%(IjRV#PRQ8VQ +BSQ&5$IqcZ-k,XH1keI#($+Hb!IkCA2GGq%rQZXh`cq+kTq'IcA8[`$q(krE!I`S +25bimm)qk#hKm8,F-([PFGc8mcZDkCRJ8F"h'iabZZ`-H8lRZQr#BaR8rK-GdVRX +#(M1ilRI`Q-Per`q2@8`RBhaRFahDc1%k#mmAe&A"iebZZajcQ1ZLm*Kh)%[44J( +lfhQ+[HdMQC8m@b@b@&j$HNal3'HDdi2fp9h0c[++bT++YS#Z4K2U5M@X*j31l`h +H4)8eM$aHcHF0+RBe&!N%r8R2h!i+FcJ3EYH5GXbr8V&DMhU6C[DBTUXKj@VrQK[ +9D&[5cZEcq690mAMeMU44@5`3E0Z2i2+P9d-8f[c,rH%"Qr+!jY8dIkLe2cTS@"- +)G`fDl!qZ[GLqH2&EX@9QEiE@AZN%%-P)Hqa["J4Y$JB%$3F$JLDHLXTpq[hCjl( +EY"#N4pJI6"M9qYHq&E0kEl6GVbYeIPdI#&SPH&'FhNL%@KRC5DeU!PS5DA@YiSl +SJ9"JE4mSTpIRVP1FIS!f'!0D+fUmiIDBYpfrcmSGdb1aI9@PA2@*@ULE@%+3!*) +Je8++KG3++495&U4L5+Q3!%SKK6)S'e)FT(j)DC!![L"Y3D+"P!@T$G)rj#4)YC! +!BL'e3NU&9!ST&0*!T%q-0L&+AK)XD`-4F8f5VUcf+!lE#K[qmjaq2DVHk)pfD3U +YV(AcDj9&NVAh3FQkUV6"VG4@GC!!"8SG[XS@cPY'*0H2#6R[PrRc(+4GDA!65fm +AXDc+bVq)@19eVh'#EpSUEpc%8rY+S+-P9I+k9hVPkkUrYHK2Q1Q5Jf3l+e`0N!$ +VV8JU`1DfZ[VDmd&rYmHMYS*q8ffJV3EHMh[pZKrH6i-pN!"8mQaPd)[qrPc[p+$ +pbj'SIa@mhlM"(p@)p(C-SB3%D29"FNl-RE4Dh%m$e8fVc'j858Z`!5,4jS"N)88 ++NEj)GCmKRiAAHZk[&(32Fjd$LY`2H&,9Jqi4ERFY&,TbVJZ$$QbTlLD&j(C`(@4 ++(Y0*L([U6kK1TVTAZBq[3C%VP+pcl-L*F%kPViRi*hGLRU,'Y-+TjI3ckKaR32- +TGAS8L9L@[I&cLNCeNi'4"j[48e+684&Z$`DdMV2l!5JZEmJr!-Q-qE82j!#(cbQ +fN!"m,d6YE,1mERGqP`6eZR#44pli#'Q"A#U2UK'-0HDrDc0jfEBRrKFPmpi'd'f +SfAP1KQ[2c09JmjYYH`QjB$keM&@p-)PFieC8NMpI*91A&*1CFh[Q04%*rM,m64I +0d%P,HF(-I%NZ*GhY1GZPI+QUZfV,MZk@SVQhS#GU@GUHBjfaUqVj8QUCDhKI-'2 +AlFprjBm2&C'k@afhKKpVFYIX*#f)1PpC8+SX)C8Nka[G-8Ge25NX@d)FeQ82I[Z +"bZ*-kl,lHZk[I'MRLLhPC&BTF45ELV0FQq2Pa34H,[IrNCa&$P,T!)rYjSKdAdr +06R1Q+fEEmmBHM1f#G4MERphTLLR0mkZf2p2E%j4GfhTl9(KG-V1hCj9jkeEAe[U +U,ci9Ip@ec49cV5!%-L[c+J[*JAmZCYMXap!#0HGfZ+iImR%2@N,HQ#&r-U1N),r +J'DY8Ch18KPp$Mr(G95m3ki9KN[QC)2P#I$HmbZ*lFllH#Sh59C-@G"&cbi80lZ, +XiQ@YUY(iBXfjV!C2Y3@,33$l@X-L`3HX$CZ&K0a-@iTpVdb!)P1'C`CDGaCk+a( +Ad$4KLQ"aLB-!XD,9Sd6i9K#-HJ"2%c!&X4`r3'i*r+"%p`@A@Li@YK8'Saj!rm" +-Hm-5$Lpafm5d%RfM&[l`bS!Ar9(,b861-IV%85hUqeF8d1h(VJm+aN*f8j@C0%J +ET-Rb6F+$4-UQ53*rQ-#SmR[ES(pUB4h*Y*MSG"K,0Q-SDb!ra6r5h+cThUMJBBk +&G[&S!4f`5T68$&CU2mPf'Q@a3kL0B8(4M'"hP[9SMp@*j)!SqXc$i3"l%)I60%Z +R&dF1"`4R6jb0+h%!Pr9h6Z#NI@0J'haQ&bU3!$%Cb[6bA3NrD'K+qMP8S4!2pdA +McDQ3!'NJRJPA2,U5-@*j3'!5+B0cbRGFA!9Lmq$8LJ36%IM(DC+Q,3+%M*B3H5+ ++(YC(%F%3YDN,lHlbLSA+`R*E[3fHRQTlr8,45JV3XMG!mXa8GeE[+jZZM-HrqUc +iT8B)A35j%8j8d[G$qHZI)f6Tli9Zp5!Pf&*P!p``Pre[#!PZM'c%A&kc[-RA&@M +$)F2'1SqGmC4DYjY08KU`PpFfX%B#k$+@4p9B4-%p%A*PG8d&NRRqPPY%$UPKY!5 +-k1KGd'e&#iX2qklZ1NX`d%T+"VV40B&@T6S88D1kJVX!R*l'IR@C0aK8eE"5j3p +'L,04BBX%U+0''+#R'a03#a2m"%Erqef,QJ8R*,$662XUm%FqMIX2N!"Eiki%h*1 +!8qI[GPcIPp2-59`3&9'+I0326qBX#PB))rp`!iCKMeeSBqlQ3Pj98#lMP3A&cUX +15Lh(JS)l%)aP5,JDbeL'Y*CA)T3[`ppBKL4HN94(p+@pYRMmH`m)@r*#$#-$(G( +H[i@ZMmI[Z&RS9Jp5FTTeraf-N!"riEiEf!&$U4lScGEHhrkKqjbqABA)m0MqV,j +PC-*9'4Zk%k')%'k($K@CC1Fc-YLh#(*3CV2jdp1#ic5f5!5lK`)!(%jR69RD6pm +m$%6fN!!2@!Bh6J'1i@LdXmeYCq*D@eFlK2"p(2896I@@eJlLdl3@BYUfRK6-C9[ +Q8!UHh)(2JBNJSaJmkVQA[U1hB4H"i4ME9T%B*KV1$J2(iX@L!"a(![*2(%G@2Cl +#-3VN*!lrDJ(!lNQ+Bf`E4cSH1$*!FBa&)cNhPJSX``'VFJ8"1(bMN8h(&3IR$4` +MPHJNMV'H'8l5(FYAMA5-e'QfD*I33QfBlUr66AEh1)p"(iQj[U(BYUQqf+Fe#2Q +(''$($H,31S+ieA08qUB9K`Z)TXF%!6K3,*!!**r%&AZjR('RfUrL$mBp2$Ik!H0 +1i4!'-'jhQB0@d"%C(+8p+))2jRjib[FpjMk1i`4c(mGaJVNIaA'FZDGaL"HBqe! +m2Q,ZUF#qcpc61%i`pb%B(c,h0!k"!(2hYj2$G4U"d+h("jRlhE41#cmBph$LIm# +i4rF-#!)BGf-JI1NPbZUPP`malUch'"2J'+d-lc+QF4`RQ-j4(-HC6KV(Zj9m#-H +(P6b0BkcS!3l)qk2-r0-+Nm#"DcN15epRih#Q!3keYA-%KlZeFac(C1FliaaF-Te +11ajp)3#3!'19%bk5`)`qLL0iK(-#$Tb,6jiC-93CfZKqIa&!A-p8KJ3R2liMmbL +1G!8Hbl0%IZLMDAC-XYQT&DNDNdZlQ$Hr(JE@Qf,*"k5I*5HkQ%)!(2DJTK%S-9" +!KR%!Cm#iNT&q1qdq#J(L3EZ'3J!F4YG`"-I*VQ'((JU5l4k'Sh',I'h*HRN$k![ +bHZAUja5bBIY@d'q3!+qjSKGF`Ld@mei&IEIXI6&(GTMT,3m8"akF3&,aQ-JchUd +*4!lR+hCV8Pd@KJ2hC4!mlZ*-hY0ZM4!JAfQh4JL!!i@9-fMHr#HZ&!HNadJhD`+ +(5`hMe48TNCa1M`"JeKahrSr2Vmm4[de3M-MEA'Lr#'iR+#+4dDQ&G&`&"C-BCd5 +F0)R4GlR4)5FCiJRQ,UKJTN+!bLP@U&36NPj$)3$Tk3KFpP#-L)#J&b0Hh80aXKG +c#)L3!'#IaDM`I4DM)YlDCj%H"#06a42-hHkqXb[YajKi'4%k85B%`1(SM+kb`2q +6Z#*M%Tad!1KNfZRm5%kQRFjALL-N!"Ja&3J`,cVK0LB6F9dCL)`cV`NFiJRQKF) +RjIiE9iVM`%EZMh%)!1S3a6&fYGi%$Zi$cb%ma10b6M%Q3*(bFBSaMH+BB#MTbLR +mB#LMq5&NB"E$mF#*c92-BM5Z%iaJ)Zp46M##dAK3(-FVm"%Fl$JQ-G!K6!*Q-8% +rhda#F$EN2M[T1r$["VY"8T`"rJMD`Cf6!cMQ`k-)l!,ll"EFNX4RHM&TGa%F3Q[ +JklFV!Rm'[Ril21HA@1RYPhQ"Hp#!fcA"`m(X@[(@6(ir4FCIiB3($lA,hI&c$"# +cQr*jH#aPrLl$Zc$jA48QZ1f56'(qGZ+0Zrc'#Y-em*M+r-Q2JSlI@c%&Hf5cQEp +06b*JEJGh5@8bh(NA[`3'r!k,D6[40l0VY)+1hf3aE4FmCM+l*EM@QppR-Heee$& +m@fi&(Er9BMVLc'AqfR##MGpY-4fZ)j8i[T)e'!KQ0`2[h5aKGUCISfpZei#q'Ek +pZ!Q#(lSl!jSAdV2-Ac2HPm'2hTeeC6)2[*Jcr!$H@AM$'SY6AXFES12(m-l#[(Q +#iA[T0Y$a`hKR`m@RdR6QldXB2hiNEb(@M3HCh3V`B4c-1qG5H0!c*%PH,Gi)b)r +R24I`bcaq2m8Bmd0kVC!!Cj1ihF1[B'iaZmXK&bqpRH&BLGd-IQ"[)4iAV)4d$HY +F(i1Ima3m2#'GcLcdf4@Lhmb3!"l%'Y&[GalQ#[M$12ECcB0BbS8K[Af`cTeh"GJ +Y#88dm0G[Gri[i&(UUB%VD[2Z`KV%MrqerLKCAr[p>B2#,B#qQ2(cDKH"lXqJF +DF(`iZY[+mU!H,ilM&fiY!Ka5!E@EmRhX'['$JZGJ[Eq%fEAp#R6mZ1"1U(rQc3b +I"A18(K(m2`!!$3e8DdaTBR*KFQPPFbkjE$J!20%U!*!$J!#3"!4J125d13#3%4B +!!%kJ!*!%rj!%68e3FN0A588"!,$B"&#a%)MH!*!&!P"2!*!'2`d!!*5m!*!'8,8 +'q)klAkmMI''hf-4m`YH&hd)iECq%VqaDH)36YMY1&TN,cGjEU%`AHV+&Zr"&#GY +iDRK16kC[(*qdcrdGLq`MYeh)2X)AY[!LYr![mb5l)mIc)X[aA2KJ-F+AQC&p,[a ++ZmKQNB@6@ikl#5Il1V,`Uq00b#DF,$bbBSAAGF!kkmNYG*YH!`+`MbcN1GPN1E) +M#aNXj$ECVFZYXlbXXdPqCTlFcXZFTH9(Qq6C)0V,G60lb`Cf$MVGfRPTRA@3!0r +#VIF)h+8(#H6`0[6Ehl@lpX@$qb&Iq+),KrUP!mJA)9QZjh"$#GcNi1ekXZ%QN!" +XH"k"4jE)NZdZXN6i!S!&F1,6p5a1CrLMRmm*jHG[Jr`@IQ3Km!L(YjmZ!*cJ$cM +cFZ"AilJH"-&*3C!!@arNIhThN!"rc9Z#B1f(ZI2jA$l(dAcemAadBCJNY6JTP*0 +i6e40HhFG+9qUA`Za$f'r(33[2K`%2p$eGh`fi'"@b5a3kP[acRd*kVKb5-"VmaE ++TX0L[(bmd'p`6fF1FYkE1j4ERArpBqpL-Z+Fb3@G6[ILRh9bqR$0FNHqRldQ#&l +6dDqZa)29,bc&cE!D(hq[E,!q@*2lmrc"hVRM3H2"&IR6FSqF0"TXi"Pq13JHh"' +FGV4@+hH@*iUY*,UNY[mE9F%TRVeNi920NbH,"EqF2D`p84&aRPb&j!(-8hY@lZ# +Vk,Vec@3@5!FcJA9KHDQDDm9AmI0`I23Fmah'2QC2HH,a1M29j(6S)(QVXI'P#hG +APVC(iAb8R,rTClpCFp)hP$Q3!'rNccVT2B-Q&282mk"qqDZR,hDLJXGf!#G)%h! +*$"i9@IrdZUl,SA(NJT2@9*E1S9FXUGIQrVXS0YMR$LLb8LiGPH-Qq'MQLFGEH[r +hqQMQa6*0d!bFqh)(me@DR0pTE8EUZm`LmDh'UMkX[phGeU+qHl"Tmcf1cCM[&p9 +Ga2I9V!ZB6kd%9,@ElrIdF*)bqH60G`@(+[04Jq2-Gk$rk[&P$YAQqqXF*TM[(h# +BD$l@$T2-pami6$EILacdAN)p,fpmLIQ@FCKU[ZdFTTQ[PF0dmlf2`kAQqaN1-mc +h+eB[q2ijKjRQqmmF,RHqT'TMP[RQF*KY[R8FDXc('r2qq1M[a-(h)3jAQZqA1&a +P[PrR-0Gmri,$222p9`jA1ep+G6AII0braRce("DBldi1#mhh-)G&j[YT$S[0p`b +(*HEl"JI90l521UCfD!AdL'[0ajXZ0ap[A'XqqXF+ml&FZmjmIih$5[2p23kVc2G +&kcrirK@(kmhh"acUR#qM2V,'I,ce@[0YjN$Zq'lMX0jmY%RTljP$(25mT(c8eNE +cICR$*[2p,JIU"GmIFb![@KajEc%IpEr9I,c[0[2YiR#MqHLA$HEl!!Ik$,k2Fj! +!3ERL9JilcIFl("V04je*MmkU4j-A2RT0NrQSQAHCMpbS0A`-9FhQHj6$([2pE3j +lcIIh1H`chpFiY*L2Ypp[[MrLF,2cjG4ck9Iik#1hQ)rDZp9mj%$GiEZI`qhQ8d[ +8f'lc8A0hQ)qmk8AirLd('3CcRq2!kS14JCjqa(cdV+2QScl[-KpjhfdqCS9Mj[Y +E(1MRq06-%pYM2RSRYBR[[h#J,c'5-,IFDclklhhQ)eFCHr0khj2QSkr`c[LSV92 +QHjC$QrPqQi2-l[P2Fq"pe&HPQRl3I-`-Cma(,j'aVNUeqKlcNF0lcIFh1FKm@U8 +CL"k1l`81MjL2@H3Rc-HF6ap3hcM0-$+9Me2rIFamp!lQ(Abmlr[04jqQGq(l*!I +Q2RaIiI#%qIie"fSF(l2)Ah@qmCS92fJqqZ92QSrjJEc`d9YrbRc8&V-22YlJ`qB +MIqBqI"rP3!r(aacf0mc(h2QNqCJlU4&m[mq"2S#21[L)me9VRU4Qm6%M-I[JBaj +JeX0(lp1l+1@M,r`Gmr(Z[!-qlRr-I*rQ3'r(pimir*cjk1XrEllra1([QSrCp"2 +10d&plKI-aic(6)f2qBIj#"rpJ"V%4frkP2QS+rSU2Q)pC6lHJ$I"pdd1p(amp0I +210p%cHHI04qck1I-4eqRYq#M[cjY2RSS[43I2B)j%4re3$hLSrpphRb!*r$MSrm +alkK[NRB0cjQ21INIQSqHp'[QBiEjJ[R)QpN3(hhY5qDMKTQ,mI&'[$Nqm[i0mre +($XahkTZX[1PGq-LE[S'2pfBH`8F[r-IQ)qrRc8FIqNhc8F0I0ar[dJ0lF0Ym&Ed +Grp[I`GhY0-`1TiBe)($8K$1mR@@hZ,&FCXD2-hGKf6rXYalN02MLJkfQ49'ST8d +#Qm5QX#aa+V"6XAPX$MX"@idGMjf"[4`l'mYF3[p6F*p+-Y&V1rc-cHTkl15E2V2 +QQNlRZPQ(lT!!*6`EZX@kVM2`prIH-lNrqTJ6iR-lY-"#'AF"3TV+YNFEr**jka@ +PAX!fk+aENmHDY)d2r-I1A!!0qP-aUbI$[H&B2@bhShCa6fLl'[ml-&%ZP#kmb1h +@D&IU8Ea0D[GlaeDASQ3K+NbI`'EdIiA*3-1D0NpYfe9GUXd,80Jb5pd%MC%pdeN +e6f8ICc-Pq"q*dRVmV3Ti'"1,V6VE$cCkp'ED1&Yh0K"XcGQ@Xd9QSmpQLZl1YSr +*QNdI'`-f08cAE2MBmV$YCV214Te01KYd0ZGXQc`X$"XJYTFH*S%DiaAC9V#PB$[ +"9S)0"YX-YK*X)pK#X!eKfm'%cf61"S,0!aX(TR1f$@`Cf#k`9@#E`"D"l3(61GX +#YJ4X6pMfXFeKJm*@MfdKfd!f6P3CRB&Y)T-r@cbUQkdGfcUfG'cRf-UaM@-,arD +0V4YE#ECX6(KX(GQXX9&M5m,QJ#dlfh@fkQc6fD+bd@3EaKDGl6QE+$D2E,ICqV- +eCA2"aT302pY5*NGk)p-B'hifl@`0fDbc2@%Vc!DGIX#'J`d5Qh-3#'cTfI+!0'" +Mc"DDl60EClE@E+[C1V0YTK1beDD$X`PM8mG@PSQ2M5bEF,DaE%(Ba,)jBi214TS +0#YXE0XpXVGJdXbeRbm)fL3dcQhSfp-bSE16C,V2*BM2)4T!!65#E0MD)E!,C!,, +jB`2*KT(0RlIeBp[(PSm0$KXqYN*Xp0MNXD&MFmH'LNdG'cSfFf`XfFUab@%,*pX +hjm&(0lfcH+"Q1f4hcFFdYRhdjdGPUdY4QX6lSQ5TAG!39c0laNcK&EQ00efIfhM +*jTh6KCRYLm'2&fCefM4bqJ9"EJGpriUlejiq'5`8GMVNK%a6MhD'3IaGErVR1F5 +'3VbMUqDImlB-%Re%-h#F'6EcXYaGffr,AIGUKq,kD$BE-iH`NhZl(m8k'pBX6dj +8J[CL&`dAblGE6"8dZMA-FRAEmqfSN!![If6ajCSBCqBQJe0+icYfmMD(+Q'L#IH +*fFV-QILI,*GM6C62cG6Q03eq,Ba56AB[F*q*m9YEkk(LIEG5dKicpMQ"$pAjaEe +4dQDh8,NPLCAjR&@'[1&,eE+YJXEpT2CN@`'$D6LEE3,q*(Zc4F+JaV-03E`BV#m +%Z3c2&$p(dfcFi8M1DMU-1fc"@8fYHF-Pk1R5`afkCVi%dl["IcTJeUY64XDQYib +2&%DfM&C'16C0M&8-,1P+qG5qEJ4"2[39-3cl[i,TrMrj&*cGH'Z0Nh!,I+"0fMI +-Eh`1#,4*`'c!Gfj(cBied88RGhmT)Jc%6a-KZZqUQEh8A[XPlJTc#TK0p("@T*j +SVhC(6A@prMNLJ$%&bTX#qBDTE3[++S&9A!+8(fP(YD&31#(9KRZ!5Z2lG@'cIJZ +Hid+!hlce*VPJeGV+dUELZ@0E5f)hD9ZXrbHpbCjUIHUr`JkqFF(C6fcL&*Je2"M +Ba!%-c"6%D(5JL3#(G%[c8%%&dK(J34UXl&d!(r3m)@Hr`"SS!#%0V934iP`%!+- +[DN53!,T`1C%F&Jh(riDiV6b'+iRTPP[h5Dq3!$0J2kqa!#ccD(d!RhNE"`"NAN- +&N!$PdIS!"20@2!$r2&SIJ(%HV3q!1!rJ"c",D(dd!%YSI65J6fKp0($2)c-#N!! +RY$kaZl%#C)L*6N*SI@+LX4"DRjMS5$aD(pj)D(hLZL1d2TT15'KpiJ,C#De2A'! +cSI@*#q3QY$ja!4Z&eLFZB+$3qX3&pT2&@9cJ2D(eL3Z)*V3qFEfad2V%"HJ3@Tq +i3)C#ka2AJ#+d2R%"%iA@*blJQY$ka%9()V3qF9&A#+e2r(i1dVVLUJ0Ca-8rbd& +SIH+2@Le6jY5Ud2SN9"0#kj23H`QY6d,hKGBR)D#Jd2SN"1i6@Tq%)"K#kj03h3Z +YMkC'%PUIK1T$D(d5!MJ+V8p#S$bKp8N)G#Hd2JRe!+(e5@K'%eUIK)#C3ZZ6%*! +!8'Kp%U)F%PUIa(dFK0BR)5S(SI9*r$-(Q@i6AqBJY$j*eB(3qL69Di6@*kRD&MK +b8R8SY$j*eBR3qL6eMN,VNe4Z3ZZ6e2!UY$j*J4Q&eLFT3+E3qL3&+*8K0bP`U0$ +k*!9L&&UIT%#-3ZZ6&!K4D(ddcC23qL3&C"9DRk6!VN,VSbQIK0BRUCS3@TrN!ab +%eNG633QY6r)4$N,VNe+r&&UIP2UXd2UNe"Z%eLHPRL+d2LR9[0$kT&4A3ZZ6dMX ++V8p+XB6@4i&p#V3q+I8'SI9*#3!Vfib8hPjSI9)#CJUY6dVJ5k(e5@Qk&eUIP%C +fSI9*#A3Ui+,8acJ)V8rUlf`H`FGm),3q+G%f#De2@V1(d2UN03m)V8pDI9CSIG+ +UHi&NTY8,K0BRV4U6e8"Dlb@d2ZNZ-"JIS&qKp8N,`#Ud2QR0"d,VNaEd5@KpdS) +b#Df2TVX5@TrdA4aN1j2@$#5d2QP4aJLY6rVc()6@*k1j6QKp-TUA"$+488d,V8p +'r9jSI6,UZ8,VNe%r&9UIM2U8d2TNe#1%eLHMfK0DRicH@QKp-XT(D(db1JZY6dE +pAQKp-PVG#+e24U"XSIA*L*C&D(dbUPfKpFNmb%&SI6,Uj8,V8k(j8'Kp+P5l3ZY +6SGS9@Kp0[b@d2K@D(i6@Td)p8@Kp+P6E3ZY6S6F9@Tq+,MJB(h1Ed2T8U2F)V8q +&!1C#ke1K199SI5SdR`QY6iAkVY$kk$&CD(ddACF!Ll1Dpi6@*kXj5QKpXTT$K0B +RUei[Y$kDaNYSIE,U4d,VNe@G#ke29M8QY$jC[DA3qQ59Mp$kC09[K0BR+c#j`1H +bQLH%eLFVqLfKpFQ+DNeSIE+D,iA@*kH(&9UIR2U0d2VN0"X,VBqQ"K0DRjcU8QK +p0%fBd2VN0#m*VBqQ$"0DRjaQ!+(ebDQr#Ue26Me4D(ebkN&#kj06R3ZY6dke**3 +U1H8XY$kj1cN)V8rZEcN)V8p1ml63qZ5qb%&SICa!hrJq#q[rCK&fJp!"[8j3%P( +G[NaY@b*cCDRaFFi$5+q2m5`$5+qIH`B*p[-RN!"JcJ`H*&8ZKl&(X%HaGf([aKl +$YQ,IMEd(Hbrf2Z`*,,6[!,3!DU8GEbl&TdNCFeL)N!$b@!MpaQ((BkZa%l'6X*1 +a8l#AB+GLTf%[apCJVm$1`9k*[3Sl&cX2Hc9f2[BDl!,X3Z`Ll',X%Za5l$,XYGM +Pf&VXGGL9f&ABeGMVXAAB0GLef(ABpGJ0f"Z`'l'EX2ABcGJYf+hBEGJEX3hBlGJ +Gf*hB4Za0f&hB*ZblX,ZacGJpf,hBIGJ@l(lXcGJ$f&Z`Yf*[`pk12BLp!hZRE!% +#CCTELDqRm1PSVm`&P100dcY'5q2&m9ffd@[rcR-PU`HrXcSp@`#f8M09Dbj&Am' +(Z%qrPCZ@IUHb0&@E5m,%YT@ZP8r0*B*-F,apDK5p&j[!+Tkkf#TX'X[f[3+EaEC +LFpK+E"jEK4f((BqYaNl%3RJ+qHJ8l#ABUGKTf0RB'Z`9f$RB+l&ABHGLjf'[aXl +(AS0GJ&f)AB4GM&f#ABTGKVd@Zabl!RXGGL9f&ABepRTX(AB0GLef(ABpGJ2f"Za +'l#CX2ABcGJYf+hBEpNCX!hBlGJGf*lB4Ha0f&lB*qblXEQ`cGJpf,hBIYJ@l(hX +cpJ$f&ZbYf0Z`Yf-2BZr!(X)HaKl"(XAHKEdEH`clEZaa,+!0c6(TRCpCHmAIGcU +I-T!!Krpj5$E(i1H"QYN+'8Kc@h(!GG6rZ4"``iBpda28)9PEU(!aP33E,b"22i" +Ab`8IAUf#Ti5h9QGfCMkm@PeiE`D[,MapLHM4)iS%RdFE"d-+GK6-U%G##9i2I"U +i(`mEkNci(#[69,$GD8ULDYaSeHUeD,jJrBe@9e0C#RB9aZ*')fi'fk*QP05b1aE +D[k49A3c5*B*YUU@0X&@XQ[H"0)fEA@ppA)q6R[1"T$h`(UqejZ)`QHpHf&`,kr& +#chXUh0IeEBfEDGGhip6ihULCYV[qKQDYGhG(G0PM'69'cH@M[N12[3dh#QQSVQU +6hadYe2U"QUY*IDlhEXe4XjGJmr,F[PTc2YlAbk-PFcFZp-+e0,UHrE2TmT`#294 +99@M2%II+$be8G@TYK!Z4(!qNYAS@Y[$bHjZerHHj[(%e9m1k)TeHXNXENi@pcR% +kGKP[iLA%8DK2@jceBA2[D++dMHp1pi5i0RA$i@aSZ+V!TaEL*QQF6A(pXVl6Mli +RfZqH$1IHlN2LT$D-Xe6kpBejLejS&[9amj+DjAfLfBlYV@d$fG*-%jIqPL6ThU% +a50NFYY,H@UY(f0-d,1dq&6CF,Y['h2&Sh)#4dD5b,A,KYbAKR$PDh4Xe@'ALZEY +A(mUhE@*Vep98,[9Faq)dlMS,0E#ceNlRi[h@$eTlr8A9KGqTLJkr"jDEep&fZrX +HZeTTYe8eKG8PjcJH9YhYTVM@l,lpEZ3+lGSEZVI`'iMUELIUpER3"@Q1kS64VN) +KipK855)A$qrQ@YY9!%kr0V6h[[R)26(HaM"a6i*c6qK+'PqK&qa*V0!,CE+[ePk +f9c,G9,P1YUU$XF9iQaIaamEhYq)N"D[4PJECMCSU+SeUcLSN86YH6UT41f"`8I` +U06$K%&eGE9YZ+@M-jG0+L*BSA-V`(ZT`U'h0R@b@42YE39UYijIXJfQQVCKBGbr +l[@MLEY`b[K@I*H946l+kZ0'4a65S51qLD(R4M6YQ*`TM4FA"h4LQf82VjpLph%a +VG$"pXF@m1(A[E+T9!DcJVKX)ED%Q'KTCPDJVX9,j`U2Z6@'p(XG0TVrM,9+U'GX +`G[EC,P",S4bfk42DZcXk%*6(Yai06C,HDpSNe48r%A&+)RL9hGKZ",['TVIfXY( +hr14`Uq3+jG%i1e@`YbEIc906fC@1LP#Ar-,aqS@Ulb8Ib1TB"ffBhVQV&d-phEf +dkTJMULNdPDfeT*d@CU1&"K0&l#FG`Nd+dB5U@IqUfZj0mkrSj9em$"1LF,9BU1D +U&(q4,dMG+"56HI[LE99#IV2DXm4SIL6U6qq&i9hh16m36kTk$jI81qM8JNIF'Kj +p4Zre6ISmKRQCpXF)VJI086p"+ETL0[,,8,GZVihA(Aec&K1PLqU#[ULErH&kpfQ +#l(64PLmARdUZf'$baS@JrU+!lRc3pHQfT0TcIU(VS5lXI4ei5f-ZkQd$l05kDfl +2iejeeXX6$a5V,KfIliABf'T&B4)fh3"J(Uh%*U9,XRa$"bP8JSPJhITkmHjIm&+ +jb$kA%`qjhY-#mpBmcX)!EB$IPYrChQ[rfqqfaqk,eCjIej[f[8(4$ZIApAB$Ec[ +`IPde-2!'IIIlB[5phi9D((fMU"ik-KUS*lG!$aKpleGV9hM)6hr8k&X8$rRTHap +qM)Imp0h[cPpmjm(64GMK@Z-Krk'NZ1m6D6J*2R"4F2Yi*3iI$Ra$3+6!6F'9!aJ ++K"5F-[$3`$N$Ca1m5[!J`5X%p`m)+QJZi+%"*`8R&"`fF$I"E35)LSB&Ya%i+IL +Mi(Z#N`NH*##1P!*9!mm42%0`3-'M",q4*jD#pNS6KPV$NbJ%$a4m4h"-`DF$"JX +1+$LEi"2bq,CSUl3jH)iS3cLHi0J#q3hI%EaDF*A!F`@2%Ka&F"-"*S0VL,B)$aH +F5F$F2+iMH(NmS4T`f8%K!XqB*hkMA44(83a(Rl!06p!'A%r`#X%("jm9R(ZHQ!a +2M!E8+2!V`3B"VaYmER#h`H8'$a(m8h#fHEJd4J"@)r!6J8pM2H,Kdq![mM"URS! +5D#(J+S)2#@kNSSL5SL!5i+ZH+")ie1!FK01*%B44"Niiq0pB%M"k`)-%,a+m4ee +L1M`4(I#i`68&KaYmE(#f`G8'4aXM$jaXF,%a9X&$#1mG('a`Q6&D`G8%Ga0F6R# +NJG@$d`XU'ALGi",cK)1i&,i#rBEDBcTEk6F#T*16jA2'd@qi%$iAKGK3Tm2Hbhe +4U`@j$"iCYG2YDjbG'&qA3@E[Lp)#!'!&IIhc49%$H&$#+PbS8"!lelk-i9FH2-q +B+"Aii-%,@(GDr-U$'qr*m#X36,Y,m#YT`[[`d'k%U(Y!R-6&cc*iSPj1(8qD'Q1 +21l)3+@lNhLU1-V&,I4`J&kGm(+!6E6i1-))(qR%ma38[a3&HF'BP6Q`3"rM"Hh` +q`")HASQ6(X3"Z[#KVqIM1G3Yi!dIpR'!1$cTi`"pH+SITfI*SH)!MAMfkh9QifM +DD6p156q,d*rV1%!BR[0j!h0iAK5[qUf#GbbSd4%9I&pHHHr#)kKE3#db+qrBdH, +8p6rM'fQ&c[Nij8pN0la0[9E8"9L%XJ%cDiHB!@rcB'KGZ[mm[ArY-$*2Ialc%6" +"p`%mX&eRhJ!dd02!ekk0VkL*VdrIAK&baij%T%ii+ck82`8G4a9R1Y8'b((aESk +$6ffiK%T1FG#e(SLJ#6282aHq-Hd"*[mp8G+S0F2d1qRV-RE5S%Iqldl8UkMr0dZ +j''JX(669Eb8`cD0mVmE1aek$AB"GL&f%ABaGJPf+ABDp&VXF@iYGJEd1Za+l#VX +DHcff$VX'ZaDl$VXHZ`&l!hBMGK1f(VXCZ`@l&EX0Hb1f!EXGQmCQX"AB,$D&6@, +[`4kAG5dS(bMaJYD*BeE4!0D8DZhUXDZ+NQrhQ+K"i4dlGHcb3j[1ckM*&'9Sjdd +"G(GFP(6E(m&`a[@Q+VGE`U4CDbk)kkaiHmYm,BfI#!QCC[Q+T[2T69pUB-[q0!Q +Ib+pqZ3h2CJf%SfILC2k*faZVd!kf3AThH['*UjZ@DrAjImX*3VDHiZ'QSPa%XY5 +pFemY"DY9SH0Lcq-DFVlHdM+AHbY,#1c+YD,JqMe2amhqTl-irik,LK'`keC2Y@T +@399bpdAeBeF9Ff(I5i2M84#bjLK0[rE8F)I@P-*@+lYE!QB((6+i@Zk3!-(PBSI +XZ#QPd((4Hr6JTR5ji*,ZFZA(+RI5lYZ&HJpZPcTN6`e)0`XZYhI)i(DT3`CA5ad +bZ&VXN!!G0dYYTZ0kGfd91f6jrB)1fA@jYf+N3jCVaAE)MT[p6fFlC-G&1Q6RVCj +U,AE)i'UT3`CAfcYNZGGdGNK0UpM9(mh&lZjSVREd4[pHU36mDm&65qVGhDjdYeb +jjQkTQjSVYTHD#jhG-(M[8Ymb9hXkSEREf3I0aFiZD#jfp%$rAQFEm5ph9P"(pj- +AkqTpaD[Gp92UHe)9,h8preli@#pe22qDhqrXRDjUl1KejQ*RTc-AHrUFG)&5Pr- +UAGr5Y-2"e0J`8a!RmlfXNG[(6GdpP"b!Nl$*GYlF9cTfbh$K'"8"AAflP'VRf#D +TGYj8U3DhqP)e&G#CU1f(T66Y[8+5jNj(LJ(VlNZ0XRbpe#[,Gp[,Yh`pU1$bj9+ +V,GmYGY[1Uk8HeRPIfPMR6DpVYCG!d(QlEaHDErYYdhr,YdUP@ljEV0kZUlf2j"9 +hqGT)IEF2CMhAqjkh1%YdAKdS46Y4G0jNU1Lke[2iTG'LI,FdAC6[PZIHmZhLk0Y +jYHIaLJ0`A`rYETjpAE1RAAEhbDi''AE'cTEBe3YlQf"[pbZh[HjqepASZMYFHfZ +,HPTI-q[VBPhY+qaER3fV[90eYDMZhY6GP(Ul89FEkZ`rABeRB)!,TlH"d5fDfm+ +KV@pL'acAHQHe[N'YIdVV(p%kjl0`11ZEc-+aV'XQ1cH3!!e-B`1M@0mF0ML%p8j +JAH0Ahq`9$PlKe0@j9YNC0KH@NDM3HAGcA&hCPJD41qi@)jGUX"#cH+XBlD@UYHm +6h1aiRDkSl6H,89rld,@9cR"YS*%QCc4XG3Y1qSHcMBm0!*TJdG&"kS#MjE2p!1i +m04mFbU5PY!f$Q`m8La6pi!'NbEMFTJ6E$c+Z(cb%J!p(A$qSF2fJ$V%SLQM%fEC +Am[U"fLp1H,`Ih"X1CpXafRi`8BVQ"E$3l03CeCNH,CGDBr$kJ5)X5EPqi'Y8D8l +$jMb+X86GN!!#V+,eU!k4@bkcrQ$RJpbrp`0pdV,9kXV,Fh98Uc8dUrAPq@Jif"K +Kqd(&mre!6C91XQB3p)2XirXNC((GQ3jI@bRCIM$*qN%M&2q!L0X+jaCI96a[f&T +(X2fJQRQaDZfcfQ*Q1*h+2rkJJ99kcPl5*rSAH65@TNc%I259PGGeIdTfJ)LE(mZ +MCFc%drriAAI2cUaNq(SHHmCh9BTcLd'ehAiib$hbjZ$8b6lS1AY$jLX*h2-k`lH +[c86[appj@'QB2)CiHdZ5pRSrNmG#%q2rPhQFHj!!lqGa6ZVCDhN-*R)a$j6i,6f +`fGAVddF@1erDR*Gr#YVfUbjlAkBdF"Bmf0PYQ9"mGIFEf*2j$@mSj"ikR"&BkMb +'G*J1[`GdecU2Fq949LrBrkiRBD*`"15KK(AqrhG&XS#Aad!RZTM(N!#b$T8(&6[ +ik6cDJXAMI9Td)HT'l9eYlp1)4MbAUBP48T,Bq4e"(qC`(X-I$k+&!$S"mKK99e( +@apMpYD%`e!f3!!II%SVNKqm+CET-h*'BE[I(a+eHYLI''a0hP)FcB1,Hp616cdQ +j+L[$l2iF(j0lq+T[61iMHCbIh%Ib1$qj[jc(Uj2lF"l$NcZI61la"qlG1!4JFZp +pMlFQpqKKAjrFKr-i2lRhT[(Qj$kFKd0JFMqkm,pelrbBZ"9e9%q-0bEZ-!mq4m$ +%VCMGDRqL-#"Y+hqjEdp-+Sr"cR"KBKV*irbNmh)HVdik`hPFk15pHEcCbBIc''T +k+Jr0k$IF)E5Je[l2EL6k+d6PF@*1S[r#6`PH(FNM9hT'iPff9"U6,Jm(`2G+ae1 +NGP6LbhNFIhT@9(NFK`22Ck6VVHJMQ3)N&m#lMXd-K9Rk99AM,qFah$Q(kUa3(kG +2P0NVApi4j88pCRbfIIa-mmVFN@ZHh%*eIIi@kMZ[kfdIR3"je0IElB!@SaT)Q)I +UpEaVl2LHA'm0R3$[SEGp6S!m['hI3"iAYhh(dNBpZ,cXmRML(Qjr1(FrrUQAEXa +GI98Vq0(FM@pBIrR"h2@RU*NSC6,96HkIcGfBh*+lqPEL54l[9K9&lc&DCl*PD@d +p9DqX@(3MkXm$YE%aLE)GUhZpCA%#e+[HXMJ"mZ!cl5cfhAI9HDMbL(f[2Qk+Qdq +V2BZA5Z8K!*)M%G`a2(V%eJfI3$l86lrYUGf8qE`D'rMd$1-%b'2lRZ55)[D(lmT +8kUl!,!jmAE03qqI23MqZ$hm@qR'pMQkF4pE0kY1cd&MrS!-IU,@H3q#-[UYlBR2 +0*c29Mpj9jc'N!hSdMf')9qbP`pm`AJ2Ia8R(VB6a'[XF5aL[Nkd6dqR`Zel!LSe +1lJ@Xf0MR!-'+p6D3!$HaBQ'RGJ9JaD`qK*iJ&F-R*RG(a@6U"1LFES910IU0L(" +fIqad(#j-131IJf!Ai`CLbKRl(%Y-14Gh-6f*Z!Kf-HGL#121i1IHBY`CK[r(eJk +V`2qIRq$F'c`#&bD[hMcHQVbL"hPpmKV1`cR"Mh"amZT*a#h!Xf$b1(ULcNK#FC+ +DSD!rMKYJ)Y"j1#9i(`46KNbGRK'PkRNNUXSLL[%D%R8`Mp%Gh2"-l[a!IJl@Kj- +"q4Qqaa[)cm&h(GdeM0BphhR%jZ"lk$aH4@`1jU&iF9%,@Y(6U#`1llUR'GT)BSk +Gl12!mC6cFG"3@ZRMS,-dlq1JaE6+ad(AdMJI"dfRihdFG*p@qcKS3jhJik!IGD+ +2JmE856i11P3RqcKS9*hLik!,H+U2JhEJD6i1qS+RqcKS%,l8ad'6m!`I"lh#PrN +iD"UHkH1JFAK1,ij4U0m9KlPQELm1D[CliU#4H*k2JilLUhdFY"E2ph(3Bhb0Mi0 +Qi`8q$VU1&rSiD$pHj11J$hQaMi1'j#8q$MU6PrSil+D@q6MS9El@ad(6mR)I"ph +,Y6i1fTKAq$L`S&cRik!"HD@2J`lR96i1@TeAqcKSHDlcFGJTVI&ad!5peXG"0r3 +k(`GYdHYp(!3'E2"ad#KpJiq$MZQ02JjDTcIj11LKV[Ga8-klfFGKhE,&ad&lp9B +I"`cI0Kq(IGb02JiB[!BI"qQmfhdFpNSlI"`dCHrdFH#hDr4ad+CpNiq$IZeG2Jl +)iLBI"icRZh`FY(,[pR(3dphXik#jHiq2`i*lViq$!ZKp2Jlk[PYm($5!lrGa8"0 +pXiq$P[!$2Jjk`fraFG"RIUZ2JiEcfh`FG+$IlZ1J&IfJMi1Hp$Ym($5RhqRMS%[ +pN!#2JeEc`ci1HXk2q$LXGirk1+cBlr*af0THfBZ$'(JEacT34R#9M`1`rh)I"jD +Y@6i1h!kcI4a!$M8q6L[(+h`F8#GIm((!MAc4a`(eq1Xq$T@C@BP6$(L#ifriI&k +*icF'9ihfIAGb(!85#R"#jAR&QeY9N!!!*a6&#A"#84a`3Mlq*iS$6XM(%d9a!Ta +3&#I!#89a!Ta3&#I!#89a!Ta3&#I!#89a!Ta3&#I!#89a!Ta3&#I!#89a!Ta3&#I +!#89a!Ta3&#I!#89a!Ta3&#I!#89aCR2dm6p4(("#2[iRLJ01b-Ir4((!#IRiRbJ +11#%Ira2&!5INihqL11#%I2a2&!HFN!#2riRLJ"2bm6p4(("#2[iRLJ01b-Ir4(( +!#IRiRbJ11#%Ira2&!5INihqL11#%I2a2&!HFN!#2riRLJ"2bm6p4(("#2[iRLJ0 +1b-Ir4((!#IRiRbM1#SiqrLH+!dl)arp%FF!*qILI+!ii)4rr%m8"*q6MHU)ii)4 +m2'!8"jb3!)rrLH+!%r*a4e'F!#F8a3P`3P'F!#F8a3P`3P'F!#F8a3P`3P'F!#F +8a3P`3P'F!#F8a3P`3P%FF%)qrLH+!dl)ar9%F3+F8"3(R*!!Mrq*iS!6m[%r84a +`3Mlq*iS$6XM(rd4a`!Rjq*mS$MJK(rm6a3%Rj10rSMMJK(cm6a3(R*!!Mrq*iS! +6m[%r84a`3Mlq*iS$6XM(rd4a`!Rjq*mS$MJK(rm6a3%Rj10rSMMJK(cm6a3(R*! +!Mrq*iS!6m[%r84a`3Mlq*iS$6XM(rd4a`!Rjq*mS$MJK(rm6a3%Rj10rSMMJK(c +m6a3(PTB4r)q+!djS"2qMiS!6'X(rU$MJK%E`2bS11+%4r)q+!djS"2qMiS!6'X( +rU$MJK%E`2bS11+%4r)q+!hA+#2j(a3%Re)Ir+FDKJNG`24ILq)hKR4i#rJH85cS +XaQL3!(rlfm"RZ),M"hH*CQhX)jq#FfrZ8'jer[A(AY8*N!"PpiIQlErm%L#P`!5 +j!$lH`SfRfGdPTm(DD$4hZ(@#PrU"D,KhcfPfGmKTqRI2DAEh02@qFel3l2i$MHC +Z0-hZfD&cQYec3qFdZdmB3UIChI!&!P2QE$k$`RhNrGphlF@GcUpH1@5Y136IhFB +R@H`,Mp-AEZpdlKJ#S$A)kI8GJi`8AY"LArM0pkppiiFlRB1(KVVeK9pK@'LI&lj ++ArKQTr-*Tf(DcIE4"I)cdp0LB#YmZ@dc1l[DLI)[,LH4PT0U*A8%A6iDi%6JV40 +6ir56Xi0BL4HbZ+kTL)9qQPe[Y[-H1qqemb0fhQIR&M[[Yr20GRlBcJIXI)ZGElA +cEADqhFi(lAb(R3rCqE#GMpMjU*h[X[2GGMifH-lNbEX-QD'F&4EJT*h[Yr-T1lI +CqE5G(l$cJi1%8QZf145TUC(0&U,5cRNl9pPjR*h(flRDcK2X20(1Nq`mfFj6l(b +*RDIDfD[*kADqe-icl(bCR@IDqA)lcl,cE$[Af2N+1mqaFj1GVl6c9ADHDqGjGVl +Dc[2YI)fG&pKjSCdAfAQaRCIBHDQGPpRj@MX[Yh1YR9IBq6SlVl6cShCqc-kVl,c +DcYIEZFl1DqbmeXlVl,cHcK[XI)1G0pTjNjhVlHc9qaBlElAc0M[ID1F'1fmIY)l +-$mdZ5UE8iAJq+Ta93'$9LH@NQXQXdTe*$Ie*1kIXV-YARAAjUR2DcVVFe6Na5+m +LRh8NhG69eBV"eH`29UVe!L`UB&48kQd1kdKrP'KHAr!5[h332EIDS9YDXkI+@S5 +FRA9R8QIGfG6Ckf`k-h@qamlhfIhm),2+dbk-`U9-4*8k(&*k#3ZM'kBkcch8V+B +ej%5eYJX)cQjY-X'd0J[4rM3*fm9UiCAL"IBN+M%*`II1M+aLD`jfpLK`Tm-a"1F +jh%9`PF0$$XFir1(XDC%6"IFh[0j`GX2($@FNI*!!F$h#i`K()hc&F&2#1`NA0cc +EF'JVPFkaPf"RB#r$cX5LV@F@&ZjXH,(K[)E2'UjUH+MKQ)Br'QjSH*rKG)D['5j +QH*EK-SC(Q6H'VaJZB[6)`$8-Mc!F`I$r`Zd,Ebp!!rKfiFL&6aF1A,LQi+k&PaE +1@IKNiBU&"aD19rKEi@D&Ga919IK5i8+&ja318rK*U9Gi4H%-K3q854-H6lJSiCQ +%3a*p')i!jBj[ISRJe,A2bRfF-Ea,lH2KTr45Ap6El9C5qlMd`'CAVdmI@HamDA0 +HrLRh-@qpjhfCe,"CJ''bfm6U'Z2Z0l!Rma[H8-JpG$MEE$U@e$i1+9j6HBb)AK1 +9MXH1pfP4kDJEYAHe[8qlYe3kbX3GLDCfIdcF$L$0e)k&bGd0T*PkB(,RNmNprX# +p'iF!61lZ(mh8$S(*A@QG(UYl"iM@k9kPPQpURHjAI1N)Q,L(KE(QKPASBR91k&P +e6qJqG3,S0G8GaLQKMc4AHP*eYIQbTG+B-#F1J1q9MPI[+[(P2)ir25ZU2&$!#Ci +3*'AliaBU@X'8(!([1MBc&'ETSCRmBKl$RA1ScJVeFISj5DXMAei+33Gkc2KXqrL +CjT@j)pFmZBAUq[`Ye(GHepXq1J(bd%THMB65-!p42KSl[LIA@d-R`([SECm6)!p +[fcH3!-I&ECp@"2YBfHAaa$hFrR$ZI[a6,pfBZrUU9R"clXBhlEVmB1lk8p4-&1* +Z`KAF2jZlFImYZDY[*9j4%@cd(U0e*PZ@eYC6pFU+46HLrMbd)PJNVil9[Gkb1!( +U9@pCR!"jm*Pf&[[ZZqSm9(R%[PFI0mA0&3RiAX$'8[QCVGR,(d$+iG%MYQli"2, +K06A#Jc&H8b-m''2lRZ55)[D(lmT8kMK4+1pD8%FmQ)Z634eaH2m0GF5$-G`6QfZ +qmbU,4r)jVl,iA!d03EaL,ahqK[%Dq#j11QiPM0IBjeM#H&e8"0q6b!@Xf1MNAX# ++MAd1%+aBE`0j%bX@GQTA!&E-61k08E+`XK5Y'$iaZ6XU*P-R31Gd+h5Ud@qB+-F +"XY0aZ$$P$(`1JPf-'iJTCqac,$(PA0c&p#6L)YM&R)XKM$Z$RhZ,F@FBrKpE1k` +#rhpqJR0[m!KFQ,akmhKVmSSHj2A*DcJ2j`3r`XA*UbF4Y`$2JXP$Xk#'(dNSh3p +Q+1L2i`DB#(3H6JRH"m'8EBkV+b0+eI0)9*9&&1-e*1TJ(U-lZ1'Ch2Q"r"bX$bF +$mM0mMcH3!*q$lcUkDaLYHllcL-h"pp"j[)VB2*G(JX&!D4$4[r2PQc)b0VePI+3 +`XQ@d-XUaD@+X)U*PKmS(%lCMjS19A"erTUGH05&hi5Yd6&(Cm*8A10NQ*i*9Mm9 +jE"!(K['6ckTK9A&J)Eqr(kId,-8i-*@ImR&J-frcF@!lYkUp`cJ`SP[9hQ%F@01 +YDZm`$XcU9V9h'!IfGD[D1i`$3lY9l4h'BILeUVh$1$#p@pAHB4cBi+eUlc!1M2& +@YAFB"eCjUpSlM!1c[&AY(FD"IGkUpJlM`&"[9AZ(F@#aYkUp`cJ`h9[9hQ%Ff2# +YDZm`$Scj9V9h'!G@ID[D1i`$mlj9l4h'JChIU[B1im$JEe9lKh(BFPM9hQ%FP!" +BeGjK(03#@2AFB4`8"9Kehf%F9!GBeGjK(*3*@$AHB4c8#eJehQ%F"QqVaMZ-J`S +#UmBlM)05!U['1ib$QJ+VaMZ-`kEDU[%1ik$+`+Va$Z1JfX#Um3lMS#E"U[%1ik! +!BBH2!bH59HdGaN&0JPAM(FC"FB*9pah'3C@#9HdGaN'jJPAY(FC"hB*9l4h'B40 +Y9AZ(F9$*B&9lKh&3dQ"9HiGa80YJ9AZ(F9$NB&9lKh&3l@"9HiGa829J9AZ(F9! +!B99lKh&3#'&9HiGa8"&K9AZ(F9M5@YAHB4c85&M9hQ%FN!#r9V9h')FY[PAY(FB +"Z@Y9HiGa8%GK9AZ(FGK'@pAHB4a89PM9hQ%F@$'YDZm`$QSYV'V[-!k+,UaUlc! +1F"+VqMk-JrU,#Km(K4KC(`F9'6NI"m8GP6i1UMcb2Jl+2UTm(04rM20a8!JbhXG +"48LeMi25N!!*2Ji+2#Ek1+MdQ16MS14MXSm$q''+M`-fDDU2!kCKQSq$ESMT2Jk +d&jIk1($3cI"aB$kjc-F"!M66a`%&pG0q$`d3k)b2JlbG6r6L**q-Fi,M8rdi24! +"&3FNLUrL2IRNA[YqMVk+pbJ1'#*IaAX8"ab0Vq)pLJ1dcPIa(X8"1qLVH)rL2-M +49r%Ha6R$m9NI"qM3VrEMq++Ge&I%$k$mqMPIM`pcp0A$"hNAicc#d9F2(m9jP+1 +[(Mk+!hc59`mIaH&0I9A`8Cc(1AjjT8m9LN3j2[$01)A#FqDT3AGB[*p43BikS5` +,0&%Tkja63HjUD`0GrF"CThVE1DH5hPQ[JPcY&bF1Pe0"V[V"K+qT)#mSrR1RY3E +E$mB2R92&RKiZTiTGpB2-F$P9l+SIr%!P[300&E[U"pRKFUVB96qS(LkRLPheJdU +a()jSbh'HIUVcIE+bP!P#GV88J"-1dkkr42#Lrc2fD$G$djAcl@ZFR4KI0p&-Sk3 +CTBAarDdkR%P[-"mdX*mQV0T6Rf09F*GpQ3eVPLFR+X'qU8`4[aB1FfBRbU$JB&U +$`U#klIPp%dIb&ppjm!cTVCUCQ`a1+Bh[f!NAak&+Q!JTq-4XCHC-r%q@bl&f&-r +0e1D&,2TD'+AU+Lp`RkR`@e[VSH*pY`*%4jhrX*9%iSCiF5pXX8Vi4Z@@*'BbLTq +aDM"JTfUC2M5djX4@lFQdLIeLG[&XTJ2X6l)h@b6ZmVMdUm9ba@"p)FMpA1CE,'e +3m5XXRKSXicHE6fNGb[qZTBMq)#@l)mlR*1Y`lY2[RCR%j))'Ud5'`8PRZMmGq4U +XA('DHV3qADHFTKkY3pJeTk%Q09a13ifD$h,Id9$M11X(fH&b'QUd$R6AR#B[dI6 +RLY28SrA,&c68p2-"1dqrNkhUm&J0099VRad'(9lFm)IElBH$h#0[$NkGl*15CQr +)I&fmP2%Mem,eTFiI2k`dA%cFm2he#M'P9l!GpIUGIVfkNlMKA3+FlXH1pfRKG1q +YHpZReAjh*1'Kclh&$5q6Hb69CmE`0k8qMS80J"Y)UFr3"N#V%(-(E!$F2dTpKMB +!+Sq4*8""BFpBh6Y!&2EdkJ0i8f&2[mi!4m$%25c()MHX3Sf&Fd*&KAY#EB363#@ +%lM"1#981ZG)cf,jXU63'SlF,i(ZPip@l5R`jMq02ciSU$h3A`'a`%N'JlBpEU1J +M'CHi#q"GafD'`L`p0*0Ic'1iF`l9@D%q6MmRT',NbcmVLA"mYRhm622+h*&V[M( +GGRl&kED`IA3#j+(eBaMK$Q%HRN+kJAflhKSk!Gj$ErZF!(Piflk"2#jZql31MCf +(A"j2S!-JmD,m,[a6,pfBAhIa2F(0qH,&ZkEq0&miI)53!0-KX2TRh2p+[MMcD(l +Gj9Nq[Jk0k$e'kdbf,+fYTqU9&8Zd(6&jD"dD#+dBUhZpCA%#e+[HXMJ"mZ!6(4S +rHPHGKbU2J5h8D"l['([8@#U5pH"c!iRD1VLlRBBRTMN(`SG!XAIZ#"V&P1B(aY" +iT9S(IGE3V+@eX&il%'e0`S9'e2c@A-8%&[ZI#8bRE[,I%b@0@M0-[jfqHX2N9bq +Pdb9NE6KG+M["'P+0TITh[Ra64XDQYib2&%DfM&C'16C0M&9'KUf8`(eB@2dDX%V +9DN`BCj!!T)hBQl#lX+bY8F5k'pZ-4I(UAZ`qE!Yf2rCQl!(X,GKEXHblMQ#"-X- +C"!Tp'jEP*V[[$*BC!a9d15cU@r2B+Lb+AFGMUl%X4LGL*f%RUf59[33l&BZD9m8 +R&RX*GJB@4DmcXCGMCf&RBpPJAS'GJld5Ha9f,RBHPP*(PH`ef!9BN!!2Ll#,X8Z +`5l(`96%Y,-I@BPGJP5VBQ,ETUl#VXGGM%8Ha"VX@Z`kl(VX"b`*d)aBd,&YV8+K +EX'a%%eJQ&2CrDHcYf0ZX,P%Xbl+5pA3VPMdr@hL@c'$%6Q$C20,$hqlM+['(XIG +K6f,[ajl#YQ&2Bar!2SJpJhd[pK(XSpLcf-H`Mf1EXAZ`Hl(lX#hBrGLEX3H`Yf" +[aGk'[4el%(X(pK$f-2B)pLMf,ZcGf'2B*Q`P0SqY`Sl$MXG@BbGJ*f)RB5GMTf! +[`8l&6X01aek+RB'p$$X6HcPf&RBfYJCl"AB1pNVX9GLjf(RBUl(cXGGJ&f!ABKG +K&f1AB*GLPf'[a5l(eQ*AB+r$VX5Z`Ul'ASqY`kl"VX@Z`kl(EX$HJ0f)hB5Yafl +'EX&Za@l$hSKY`'l(SJi`Jkh!CV%TE"*l$eEeJFIS(91#4MXpYZ[2ISEb1FZp-L" +KqJ1%jaiphhjapEEjh+22f'rRJfV(*VrN2rE[,IYJ2lrL[6[Sj9jqaAYT+HkYc06 +k9Vlf!reqPIiEp@0cEjrk)2f3!(Yrh)ZAqa"[i%ha'F9pdX@l@Re@pZDCYfYf-I& +qjpHYPj,1LqV2jYlrZ-pQ$Y+KGipcpclp6cD(F*eFPlRmjQVZ%*A8&CSV6(k9NjT +lQ&FB0G5-NbklHl29Vl@#B"AfhfK1-IPprJDEDmLErMr$a@[42-5XSlk2m,icMVK +lLhr,jKrL-3YNA"lIqi,040aMYTVZl[h"ApUFa,frdUqchCV(H%2Z2DlBjYiHc6V +-8lbVQXhL,Vr+efSfBXDLI*L"kPaqrel[apa&(Y4CPBYh4$-GXaMMQ(U2q(hZAS0 +Q(HBciU'3!0M83H9@jFI-aVf[pH[l'Fe)c('Nb9cc[,[hUHjXarMfHI+Ek[*Se"c +%[%GUc'92ZA[[8`dc!e*rc%P,A"iIHk20KBb![d92-1qAq`2e*fC&4M49caPlebH +[YIP4I8r6,eGeij%c-b@Mip-FcME5Y[UVREfqqbqmbIa'QM%Sf([V2SRlTaTTA61 +E[CHk8M@UiY&hlEhNErIVq0($0XGbli9H[mapp+-ffh,[$r[a&UM@QAHjplrkr9+ +MPjL"'A@Ik2Hch,YX,ZBp8,GXqPrZphl*CQAZIDFIljMQBHCRkZaRHrfemTAD(6" +6%drh-(2[(Xf`XP,C6hreqZ86HJYQErS0G5&pB[*[fMc1[IIhqf@6HJ-cZUU8#EI +hqq9kp84",+CZl2A,bZrA$%!I)ir2pITPj6VP`(c22AURp+&[kmfBq8RKhrAljIZ +e&f%23$PmXpm[PdN90,9!qf,H0rfbFS[kQ@`ATfJ1N!#qFN)c'R-@crj`VerQhV( +ApJVNFDCI"rImXHdDD+HmJGF2[QVl"mV`Gh[pXR,c&fdR3EQTpr,kj9RYEGK68$j +SY*CqZI*qeDlN63m`rE*bKpk-I3CAIUhA,bX[rkcHf0`lc0Ylr6,h'eaJlk&5V[[ +AIVrmR(SB-aUPara6Bre5CMbq2kA(UrR9p%YlEb[c3r`+kjIfhV5h$[UP[4GA(r( +QaCp8`j9ll+0N[Qa5hE16i4kp6H*p6lXBDTCle,6dbmAADc#3!$Q5Z8,khe(9)M- +1pqLT-LqZek`P$#1*GrIMR9)2*8Ieh80rN[kAZehi@%(&*65$HR-52[CNe)hUFi@ +kXC[XqjQR+dkfZV(hTRa+05GeBqpGSTfG9cIq[IMCe'jf[T%Z(*[MYlf60eR8D,@ +*Cqr&ck1qdd&jUTh5cjL9fI@4(r1'l!q+H6cd*q54)Qp`G[jm%pp%(JR92IGX(Hr +3([*CZfIIEpT(qRhd$QBX[9rN(VeUZE[h@jSCC(H@rCL'!A2[SqS0l0@S*qD%3eC +Rc00D&ELkpk&qILpS4K@3!1$#rIhmlYFZ8i#CDHV$bqqh03X*PRHKCQA*lq[DX3M +QEj(QI-RM3Gd4HUH%GRZ5arFdSaTZeIJb14AkSSm062c8AB1kmHr&,Y"1aCY(lEh +TQXqmZVGjV#12q"h@*fbm$HrSpFZU9fYrm$kE9jKG6,qXqM(0$FaPkQ[9c'(kCGA +eQTmqB(QSZTIq9e93$6'6mKl%0Zqpib,Y,$lLlTh9fH5p)e8YdMrTPjrSjEhMGXe +rq*RrU$Q6pijcp@DrB(P3"bE[(Hr9h'q8RXI1%CbmYG%qe[pLNhS2ljkYJbAD@e6 +5cqM[0YjmpA%cMpCHS,di-ijkM`rq%DZ%rqEZrEjf**pdpcl&h#Pc8ZeYQRFrjHj +pPRHDlGkepY1hFH1AV+p3rfDqV2fJCKeQ%1BfpZaQIUepcbhi2ZhZcG2F*RPm8$X +DqJr[4&mcmf[YEXdBc-Ad)6Arb2bkiSFechh@kS1jaFb[Y9ri1$lQCI+QKmRlEA` +)RbKHIbqpAqEA&5r6hS9p#2'!hNUm*YAm,eYq[pIVIl9YeHicVJlqk9rdjU(DGrd +D0ibkpYL2X1q42V(L61d$m&1Ap%M6AfXl$fY@-2I@k2h-(Q*&3EhN9bdH2F$X)@V +r3EXmDSelc)KQhUTpVfU)1BYlp$#TTqqTMYAmUr06mlV-f5YHVPQ@2X0BSHCHQE0 +Vhhi(&llSlUh6r'cQl0U1pNPIXMl02'RQl0Srdda!6*A#+@T)jZcD6fU@9[f%lpe +[iI+Nl&lf&l4cC#HJV[a,DMheKfk1c'Ph3lp9hm2X-b4HEN*lXUqiH0pNIT*ifAG +U9Q1(S,kIS2kmr"l3VN6YGBRh,I,fmUY9$f92`[[4$dcrUlVSVr!C03MaqjQ(Tpc +NlYfNHBXC@Ghllr3BkArj4a@2Q8,GqjpICNq`am@E*Z`)FcTelqp[mQr9[TDG%RN +cPj[qPdqe3a%H[V@D%f3ZfDPpMc#JV98I02d[IkYfVQ"C90l9l"ZNre9YeHi'I!Y +TXYXcr5rrFHhik1h--IIhqPRq1RCi3Yq3!$LARBVd[rc[r`ShY&Tm&Bpq)r'qT"Q +!Q9'&1Nfp5Te9M@VAmh@A4bhcU04C988pk*rBHc#[QckA[qVcq)6"mD$b0(dZrbE +Y'i4KEB2H`25jUPr82NcB%EDV$jSqPrpV+Gd([m-pY3H9ZXPr3Rf)I09lV0,q`25 +jUY@U#A!qkYjUjJhTFeARDer&$Pap*jRMTFp9EGG-b*c#1r%HTXrP$bT[-%)UMqZ +e$j!!q[K6p6PU2rEr!*!$$3T8De0SC@aXFbkjb!4BE$J!20%U!*!$J!#3"!4J124 +[r`#3%!mM!*!)rj!%68e3FN0A588"!,$B&&Qa%)MG!*!&!c0$!*!'4Q%!!0TK!*! +'VGB'!'[F1XTYj4hPbl&&)iXGiH[#-lh)CUh-le0ZYkLHIFUL-Yh8Lp2fNFA@MDI +i!0DALFq,iEm'r,TBNAeNmFK#0Q(E"VhR,DBGiEFF@r6)F[cV*0ZHl(-jAZq4K@F +ZcaFH@F`)Gr&kKr'&PaQ2m"6Sm%V2'T3aXLR[,9PN*3[Cj$RCC,c*FE,*EYeNYFr +XNZXeX%N1E*!!j@9XXbr@kI&EI(CHRpIDj@CHJlb-EMD3!$pYB*GfREIVP"98qcM +NLqFYAPiQh0!AlN&R$MV6jIRLj8[fp4Q('fli[TIC#hFqI)8$ff4jMd!Hh!H-"A$ +L,jqHek6cQRJEXZh&pK@ra50`i)#l$B"#J%j(2S"RqlkVP$T&UF3'GFTCPkP6RKd +UpBYh`cildC@!UcheIPP2@d(Jq%%U(rKlY4dYqcT56VV9#iR2SM[N1K9G-dhXI5F +-H#DV9"`SrAracTiNqVLm3d#eUBAm5kbdhhbmdCp[5QF[HYqBZ$Ta@YH94kTXXV' +h6%)G2VcNq,A$#4j-Xmf9ma0[8HV5`rc%4@-(cXNMk8X$%LbKpXFTK6HR622j9DC +crVVl2(ADdh+qCpRqi`A,UJeUEH)[ZUjD[[G@e&2cLAFR[YVe1E8*CALh8PrBVCj +a"#R,Tr,CG#23&@IKZfh"$3b4'cRCk[PrpF&@ZQ3fRUNiN!!0"Y1adF2-JX!aZYL +baFJr"IpR5Vjc9[+e+)@MG&K8VX$#CCb8DRaZZP5F(G0@@3FA$Pc@KS65Z'4qY31 +%Secq2AQmH-2REpSZE#1Fm[!j$-0qAfKR1"b`jqE%hBRE6cPP"AZq34"-H)1XDRH +Cd)4qE'V1CpTe5(8*#)E0N8I82%Dk(IVrI+ql*ATE#qF-k1dRk!'a2(66m*Q&rf+ +69',pXE`J"8T6fK,rP[Mm+C89c-hM&QH'9)Cc$A&%EHZA5LVR0[a,a%CRCm6f6r! +h(%r13c%+f204r-[%pQRmr@lmlc(#fI6KF"9LZaUA5m6@L)Y5)ipj9iU0[+[%pNC +F*SMY39`QLZeIi6**E&r!CE)d%M@U&YZPZ*!!1lERi$*9E"Y`-6+5f2EJ-PeX,jB +H`IBkA)L2l4GaQ5Qf4k3EXIe(BUP#-[dc4fcie)LY$THjBQ["CClBpZ)bAf`rM-X +#XIdd,TH*lGGa@5LfIi2,j@,l,#k+&UQ(FEP#N!#!fPdTYQYaHDEBAS$,9@)MlfH +*ME`ALHeRF"(F-$EkHl(BrLdZ5m6fAh&CDQ`Pl'ek'4YeTlq`,FGPQGJf#FjJkm5 +&QQ$l4lJ3"pXEF+N9're0[f!6264aXGMq-blA'eZ'Z2-$BU1[RLXfr*mRYYBPR"B +Ep9iK0[*H+ECrLSYbVFclF'N3'hLf5QarM-YUXAdCPcA'9NVFZ8&Xp-aDXH'c6Q` +lF&'GSA34PjcBIK`AF!rE1h"4M#lp5m&KE1"SXpJHaBAq"A,"5V!,'lJ!RQ#MMY3 +FfeCF0SU0RU-(XGf$bfDa8IXYB[X9A'i5fqrJ3RaXr`@AEFCQi2eQXB'cfm8'6Yd +L0RUq6@cdc![&4Jld!VD$Z1`8fcr!CCIBU-eZXB'll@,lH9aZ&GZ(K*YJ!j0Z&p[ +RF1N3ferL!Tj$3q!Ep$ifX"[0(4[BYepXi!)pJSfH8GTEcRT4+fb(F,P$E#r("6X +fkL5k[E'p'4IPM1A%X#0LqbeFlK6E*h'j5fcJU'SrimM(`!GXp0D,a!BZ+k-F4pb +KAl$4Krp3E2MrN!$BAS-,r!AE1h&49MlZ$PcZ&YYRF(Q*f-!9m&"1"I%-,S!0M[& +5XB'$p#BfX10PBU2hk!9Xe2S9B[[(Z2b)f1MGHmAfch("&aZFk6jMZi4Fl8I&"[p +jTGM!lPH*M9kmAfcd`!0LSrpq6'brM-ZVaIClZ0!,f1!0i+fFmH5PVa8Ef%PmE'# +R8G,%"PDpAQcdf%q+$Hi,6m(fIPb`BrYpA1#Rf1#li+UF5[,2Ra)EH!1R``C2J'G +K!pIH*$Ekm*q*$Ar`""[mlbeL)pHhLZd[F(QEX9@4hrkXf1"J2bFfm1cYBJ1Ek%G +Xp!qm!pZlF!%VX2eVA,"MSfp%2q"-B0rmJYMJPR"KE2#FpiJ062mPXB%lla8EI3) +HBS0MdDIBi"R`$QaI`Z9AM@dL16RF%aZFN!#Bf1!`la-EZ%N2BU2Rk4&Xe23$B[Y +YA$iS0Pk+`"hN6++@mE$Bi1&J)cCijSI&"Xl"aE#"qlmK0R$Y0m9'Mi,Yf-JCI-- +'pT!!1cEidlm`YXNN81J'f-#jIbNfq$"m%aYm$dd$'j`%rSZ0[1P0E'!"1J!fkJi +2`[B(Z0"6f,k)bqmD@cAV68f`S8PmA'cNr3QaN6IBJJfq"%r""Vk6&cC`kP0LSkr +q8'c%qL1a`EhJbh+QX0j`@'cNrHr%"NH(Jf#$arb*f1!aD"VB`&Ni(6D`ir0LSdr +q[GLi$li!FXmFkF6+JP0[Z$T9R%eY`0-(eBUqG6CR`l("I"lkaB48AP$eUI-mR-$ +BUjc+'5IFJ1-#N!#)jC3Z[d[jfp0@#L-V[KcUe2!-ErM&aiRh,fT&8lJ5`8Q!hNF +r[C)#Vr`A(RrPBSi)QA2`Ri,r,2c"la&e1S8)Trh6L($D[`34K[frrhM'9-LmQ2# +I,q92mY3%kjhL$5C0VUM3U-qScUK)U09d$5S*hB6bLA+"#S`DLAS$Qd+jJIQ!CM! +Ue!SD$4D')N"q+0#`A"4Re&TI,8GT4UAbRaE4X#M+X%pB*f`6PJPlKCh#-Q'AX%V +B,H`99JQ,JMh"QQ"*X#CB*@`5&JPlK$A#&Q'*X%0B)8`B*3B&"Z8&a3AQL9+$BS$ +5!YY'k8(*3@'"iD'ZS+UJTX$b3#J8&*36Q"`+!!S*bJL+#%S)l"PP#&D*kS(D!E0 +&S8BY3IP#989Y3-&'L8D"4RN'`9!GBHbS1+JdX&"8-*3V&$"B+bS%kMTX'j8DC35 +&%M8DpS[k$1+!ELJ0U-kSf+MfU-US!`!-+JFU,ZSYULd+,bS1ULeU,H`CG3i9#4@ +3!aQe$ED-dSD#KVS$BdCK3h&%J8E44FP&`8@j4De"j8!jK5@M3U$3SR5MF-1B8-9 +3F9!k8'e3De#"8(P3De"T8'G3L9#"8'GJfbJc+$+`D4Jh+J`-#p8&Y3@9"A8&939 +9!88$RSHUK0+(ZSUULMU!DS8+LjU+N!05J9U,5SHkL4+%HSJUJ(+)`SYUL$+!SS" +#M$+-dSV#LX+#SSU5#Up#"8D"4P9%18@43bP!F9DPfA&``"2k@49Cdr[d1Me!VF! +rkNC0`AYU4Th!*HS'6S%YB$pB36q$'q!(@!+1JV(J+aJ&4S!,B!ei!Lk!#H!"r3r +QJXGJ-2e'2i&AB$2m!Ai#"S0ci#IF!a`#8q!8p"QF!b`&2q%am"!i$2e)Mp+[F"* +i$MJ$jS)jp"ki#"l4Jf!A'!3QJEpJ0GK+li2CB#bm"R`'3q%6B$Gi#`l5ih!Um"2 +F"2r!C$!BVJ0qJr[d2Y`+I!B2`"Ii%0J#[i+$`C(!DR!DA!![i3"J,hJ,$`#6`5Y +`#B`"`m!Z-!h1!RD"4A!`q"Pm!A`#Dq!hi$4i$SH$Dm!0i@M`(rJK("#Z#*F"Zq' +#F$f`%Db%1m%CiA4`#hd*FqVilkYF-qI[hNRQMl`F2U0!N!"K$CYAr[)ZFI"eFZ! +P"m)VK$B,JQjHYVe1"F54XZY(c2h0jLjN`9Yk1MD3!(9&("li'mH,r1HX2(m0Uq2 +q1@i(l5jSibHHKAj(mV2hi*Ai031c0aMaYh9@66YK649YGa0di*`c%eL"Sd09@!` +MA9paf+"$[aRBX"bHc9RfB+14pC`SEF2FUN0M%,r!eV+[D38D*NRY@8KiNH[-U1) +X6$I'*SQe[K"E9Z`ZC%HY$9ZF632Pmc0T"T!!Y#A!i4VZBUjCpMD1*XrkCK$k3CJ +1M(R,FEYI,E%IE0LYBNZqqrh)9p2DBV8lMj5F3JPpm![PQc6NSV*[Uk`AkD"LfAU +P3)RFG'Dbk891AFIPSC`eQI45q(VIpB1mBmrUB,PiMF-MSkK-9ke9Q1C!fhkpiEL +1,UF-PHQ+@l-'REE2XDh)mEfP0QfTSE9fVj3Z*%#,'REFcX[6[HQ`jV+8J8P5L5V +91#h@S$"KVP+IS19VcNZKJfXiH#Eab+1"ZNFF**QDE,hK"a'#hUKbqHNMjT@@krU +qKa,[Dk!!0CP0QHFrh`6DR-TES@fjXA@$[N,P4dD2K)ibPHk+-iAf"GQS8E2"+[m +9B9hYb8b-,UGNr2)CBSibl+TG!153!2UD*T3@5Z3+iqMV!)rDP[!)[jEXa05H&R5 +C5##!Ep9'Le`+cGJ$Gh&kBIL'mI%M,Rl+KfFc[KIkVL"Z!!f,EJ-!4&EJd0U2UHe +()!p5%$[kS%e%XEI%B)HR0!0"$D4)rNARqY%Fbf,meF82Y[H'T@U3!'5H$CJFBdq +r,0E6cbq2C6E*(YFSFpqcTf!f8'$@0!)FML$!qPja[&Xe4lme)a#eVKCaJ`alHk+ +[9$@&''N&D2-m5b!X*LIL(&-dJd`4([[ekN1a`lDl3XjfZFFXkfIf`KLe8p$5VE1 +PQ+d!)mC#!eQA3f%!V0Q,LZh69UK63dh(,DY4*`LM9%&AkpU,e(Bc0D(1*06ZZNX +3T!fhbfeeR&6BiRUH&aAFrA,kf4KiXCD3!0-@STUQk'ldI!J6`HmF%YX"$Y3HfS( +6L&Mef#%2Fe%8[me$(j13!+"*RjIIml'RB4p&&aZ*aT8L#GK)2I*'beMST6#!C4* +"#%1E+(XB`P$ZI@kU%)(Rl5+GPrB2f,VPTqeH%r`[ER3*)S2'@TS0XU8mf#mj"[D +#E$dH*NJhqNCQialjjL&56B+ml9CJHBCdYpB#d0`ZQTbq4eiZM-bci6@QIGh*e"A +q[2(BdK(JRHHjikfm!rfE&hlGVaF(hrX9iTip5Ea-XG1c($#Dqq6eQBRKNI@TpF1 +$a8&FQl1CSJbJFD8FH@Xd1JhUh)R3GFXhjf6phh`#im$EDB2JES($fqR("hUG2!k +)Yp24E,6`a86HTL9f"d`rFp@miaTjKI@hllaXCbIf*$k@q!L)RabGIZBbHdJPbNB +dem,Sb6dR2lH#Kk)mcU6lh3!6,%DU%l)dQ)$lJcha$Ud+rb6q@IbVm6H$Q18r(Ip +,mCq*rbcmCq-r"rmDr1IM[a$rbq2*%p+a%lreBQ'`BhPHQq+%&f&AcS@12IGNXr1 +QPa4hhl6rSIf(pYqrrhrf2b5``[YNreQI2db$jk6d2p"M"h!mmIa2iP6ZXZDXM'Z +&)4lel,&NpPMqE-hQm6*PUjN9jdpcp-''ppaqVVclp[ejjq`c)pjXqp-HHI2Y6h[ +NcEV2B[fhc4cr$6D(pqMqr!VHbqZd4r1HADFpQMIJ1Zh4c(R`P6lQ$1Ld4c1h3UF +pQMN*1Zda`5P81Zh46*2dTce58jhfD#C,kV4(Mfr"GGUMalIT1Zh4ihYjRIESm6f +q6R[dq+jITcekI21Ydaip[Yr@r[HSVZLd4ip[rRADSmGhr$VYdH--"Thfk('QJNj +lp$K[3kFpHTb0SG-H2GC9TcekR#USdal0j%UGpTKNI99X5r+ZV$R*YrJ+QNR1&0" +TMdR@6kFp*PNrRICSe#'GpTMNHhqGpTMNqhDGpTMN(!kGpTMNl!LGpTMN[!LGpTM +N$"+GpTMNc"#GpTMN2!QGpTMm6ecdMAZ5GG9TMbRLK8jl6,%2GGTMLMA5DBmTaY9 +TMbRfT8jl62&p[Njl62'p[Njl62'G[b*fLM-5G0TMLV-aG0TMLVa"TcfQ120%PB3 +8Ce(SY-F8Th6TY-F8X9bR2DD*GcVY-8emd@Q2DIDf6RY-XjGdfQ1DYG0TMqQPH5( +BQ1'Jdal0j%fGpTKHQ[H!M4N-1Zdac6N21ZdacANT1ZdacENI1ZdacGNG1ZdacEN +[1Zh461V8DBpTcS$4DBpTiSe1HdbcaMVYd8c`e'Q2*F3qRICB3Pc3DBmPV,Y1Hbc +KE!5G`9&#l0GTMb@FYD$6(NXiUd+R2CC`TSXqhbRK,"+GpPM#Q6BklE'%mfYdfQ- +*qe+R2CC`LTP1HbcKJfHGpTJKPZLda`baAUFpCSLc1Zda3ac8DBmCBT01Hm`34h6 +DBiBpUM*IKVA@DBmCjU26(M0,XdQ`-EY#TceQ@'pPiKR1H0"TMfDLU%jlc,"IGGT +MK[0jp#P$KR0lG,C)KM0iG0TMKR0D9-R0r"FZ1ZfaP0a-Tcf@NVISY-G5mKDGpPM ++HUX+@8T-e'Q2TF3)RICBbTl4DBqPj'FklG&-)p9TMk@F+D26(NXj%dDR2CDbCMV +YXC4cAA6DBbPa4DFpCXNjGGTMPRa2TceQL5Xkl6&,(U26(V2N$cVY-8[me@Q2@H+ +86R[-XKGefQ1@ID,6(V2-AkFpCPNrRIDBj9`KRIDB*3r3DBpCeP+R26S6$LJ&Ji# +pfSRQPQA6'EiU!)Z&!F2+BG'J-D`CKJ`$KK(l%kGF"-G&qmj&F,!XTi1U6NhmZ"1 +#,Z"K5ATiI1FHHpBTFhH2c3@mBbM-RQ2Q(!HQX#0pK5-Fe&ecd$VA$9iqb(pP6NH +"2kq$f6"&LE5QF-jNk[a%lmd(%lf9(9-6UFQaQMSh9H"YjIUc,i(B*mVFh$YlcYk +PUUNTSl`%hEJ5%p6US4E@Jm(AJj8h32&T`25k"NcDDm"mp99339D"`Dr#*,A98+a +@Bh,H'LK@Da$M"Ya[J0*a!pM`@LK$Dm&mef,'m6US11ZJ!+c$P,CeQ,Th)bM&MBL +A3p2R`'acQ0#@JemM9)R'jSQDLN!NUYPke+3CE,mCDNXcTZ8eh`q"51Va!UKc,m$ +-e3e3dcCJ5-`'q,9!Z@N"Hfi&Vfb&DY-+0Yb++B!ES4"Ya&5qMCMmYJRjE`,,hJ5 +9B$2bfJa9Bc-Qq@d"cpb#QQh"j,iYb1XQe1XQU!3h34@i#IjESBaYKC+b&DVD0UL +#fk!)E2XmK#*4VQk'%R%c&-,Yk+(Yi!$E`HDhBaVG,DM$,9#'EN%2Y%'eE)1Ld)C +FASKFASKTKMZJDZk!BV)$YGca$BK&SZ,YK#U`%kVL,UL(Zj!!ebj-SpZ0'Zm'Qpm +0KDXGr,JGDQXle+&f-2jfc,'q&HVEVHM[@a(h0[6!E9!PES2kHYYA)"`*"lmGrGi +"P1e!EhE!E`q8P$fSbaj-4pb,[YU,h2CLQZ)qe'mI&0"pk+Api"rlSIlXac6"6[$ +`6LKCRCLZG`!mrJ"8[!03X!qJrJHKAKa%[3pLHYj"B-!Gi1jhS2IZJ$,("+K$k+P +$8)J223J"5HV3"I@L#e-D$m2[-2$J#(VT#05Y)e$)MU"Ali5LHbG8[$[4VhGLUZ4 +G`++ld#phS9q13R%m#KAY+2$R'*63BqL2Br"l%@+m#1VXXpFfGf@,U[j-8H0NhY$ +qXp#[!0ee`)bkXDjkXY%erI$"FcRhEfCLPcSp0l*l#QV!cU)98'qlTe#FI#lX$q6 +c2V@l"bHG-VA-KbdG8DIl+2c4ZMmjkPU-prPLMU`[m3!Il-VpUh-FD1-PeJi(2[L +-GmiD8HiiD5G@3)aZQ0iEkr0f![Ea@(Y(-diN0R*M#5pq9q#PeBD85X4kU#MkSZ9 +j4SFk6VhA-j1SMe1$04221@KHVTVAGa(l("SX4BLNH61LdD+CCbbRJaKZH+ZCILN +1Q9-P-AqNCI#H",hDD(2LB%)Jk"Pa$`Ia30!dZD#k'lAG$fh'E%U%'8[*SE-EcFr +2"G!aSU%km1i[b-HIc"RNBfSM%B*LRDf041,4Kh%d8bl&B6C$bjeA(rQLL8208Nl +qE0!Jkh0&%j`bdl%Bhf''9,9rmhf2qr6%%qVF,%HBP6k"FVdGPpP,GApc*K9Jr(r +2[N`fQ,`0iMQ3!0%2+*Yj@HDV#6`Y-dr+I!IHP*QhC#@5!)qNc$-*2`+[b-cV-H2 +JUTeY3ejrRi)$BMU$3(YfHAETi(&%c&AilM5$D*jAF@i2RY5q#[mNrY2aRi(rTIM +2a(m@rV2aRi[r22`Ai(mCHdAqeIMcH2M-S)F4IkRR92aRi(mTrM2aVm&r([lcm9m +!J[HYpCpF+XH"m-`ZH'hR$YMP+Y)Skf34[jUF%h+5DZLjfI%Q-jLGc("R%I*Mhk- +$&mC6PGGSle&(9Ik,ITTU6rjff2&JQZSX5`0f1Pie21DmUZa%r['!Uhh-ESdpc'1 +k`FbemUX@SX!kRPYp-icmHZSb[6M["qAMcLYX6,RY`TMQ`lAMRQD5l%"#[)JBD"J +F'jb3!"4Lrm`h'b"m5&(d'bLU(53pf%h@Gl#CG!*`Gi-dXrhlDSEMF-h`lUmCIM+ +hZXpTS$[0j'YTXNjpG%EZhZfBX(fL`$cjDZF-hm24Sa9HMAJe1FbT0Dl4F29Z$)` +pHc!`pSd`X1LS$9$dmf[GRAm2"[Bl"fdE1bX'aMi'!f12'!-(+Uq3!"Al&M!`GSi +a-2D--6$fM$#`k"MM5G'l[jdL$1`ZA$F'p[N10T0LB(H$K"KBG"bZ@BL"46m`X0G +TS$XM$)`pB`b-23XBf!d0-3D'Brbl)6"bl%(!b$8#`)+I&VrJjTFj6Vd(rITmJhk +0I"Al)KF$IC&$M(cpp9DFLP`,Z"IjaV!A1FDS&cP'S&I`Lr'Mi0cA34(La4AV"Va +Hei(q8EL,Zb*%Zi,I8,&#V#Zi!A9&RrjZM)!ZFSaa,R)X`&b-!M(+)59f`j[ak-% +eia-"@Z#JT3hXI[eXAMhB&6N&6@HF&+f-cF#8XF6i&&G+SF6i&"$*1-93C$aL$$) +H%IJ%$R%M"ej4Q51FX3AS"TM3Tl[)#LQfN!!KPJ31[EQ(k"(BJBfm-Hk1##L-4i` +3aU-!$EEPBNc`QmaijCc`Z2D`GM)edF"U""eA2+)`Q(i9RHmJ9,KHadfjBdlf-D` +9"rY)A*aQ,f(A0(XG*FhBU6I0#!hM,)[F5*-XqNQ1N8p[LUDViYcbJ+C*j4dN'f2 +X6D0RMB8Le"AmBp3V1"Fk[q$I$3)&laJq#mi4N[ElaX$@(d!aVYr94lKL,h5MlU" +l!-"&Gi[&"EHiC3[18IF1q*iXPGrP"Eq[0hb"3Ch`(bTc4$2kIFmdCNJqqPhK)30 +q*lSJCLF&jjLS&*alf'M"25+QrEiRDKM4eF+q%d@N,3D)SEESAF$DBS"ZX#fkafK +Ep)lJGX!jEZZ"#0S6!ll$6G%0Z5Im!c$UpIFAkHMaLe'hk"h"lU$c8-&mi#dkpL* +[-83"HNm''#jh",i$cQIE0)6I!9r`Gp$aC$[%#&cdML%iA#@ML)@4E`b$N@-"!52 +IE[#,2'2FLa`Mb#[ia@e8F0B1+VMj24,AZ4[HHPf$9SpG,DK&,M'H4BkpX"0j&a# +RchHJ!K(1&2b'HL0%Pi)E`&,dkHZA'%iLaq%h+!D3!(1@9feD9IfSDi0[Ie[Vlij +EG)hL&X@D)'c"-iUD9f1#F)&,&'H!fJFKqlfMk)-%*3Jri"l&MjUX1h648`P6dHp +N+P'DVTIchCHV,S4CJ[qR*QNLf0rA*(K(2&L6i(LBEH#22!hR'1J,hP0c$03K2mG +!3hE2-A#BcFV34BBRi$m4rdRi6m&r+[l6m*q"rdcmCq%r'rmjCX0PYN"*R)&r*Ij +9q*IM2`lrLNHHC-YIjkXl!3iMMe0QdUm!dZ61F*0mi#&I`j&V*XD$ZUVfG1$B(GZ +!)F3$q,IJ`9&XjH4bB`NK(T3D2+M$CPkb!C@cM5IiH#$k`B4MH,$IkXc''8-mQ-L +GDqY@*S+,00pCYS+PE3#2EBqAckXEFVa1CN!4iN(C$r(!h!l8klkh2GqF`C+(09R +2GTYP(AB%JiN3$mUIa!0jC1BN!i0Z2"KRm-!m*p6PrHTN[8bAQT!!i11"M,9,I`X +2JT8Lh@Q)%1*"b6&pN4e8Gd5Geb6'N!![6K)mD23$cGIhADQqp*EdjNjVL"$L3GA +bpR869VD[de%'jikEiRedIZ%r@qB-GpF`pHeH`XC,b%C3iX9Q4Z1@il$Y@[lF[4+ +(bHd9bh&54q0%qE$$519b(,Bb(Sc$jNG9l6KXKc5K(BFG5kjlV$kKJHf6RYq1`p$ +SPHdiE+e8reLIK3DfBXUfil$p8QNl$LZ*V'V&'Cbk,1k-I,kYR3plUGcHMX-ZBah +Y1+`PdY#ZMpN(2amRlV0JmVQi-j+kE$A[+"p@'(RPDMj4((CDHqeUR1#Y[ELcqFM +V6XE*!e,`eZh-FGM'F6jY"CAHX@9E[dV1QrP+E601&+TN"NX*(pC$6P5h'LSCk(e +0"`YkYf#X8b*Cpm1Si&5(RDS6UH3`eQdqj#m@-+0*I'A$iM8kZY`*QjDVNYQTR&A +0&k)!L8Qk9B'ZBUEQS8@)&`Ge%#fUlZ,XG$hV98l8G,IU,ZY'9-Y(JHU'FVG[NJ0 +kXQR-eYU&GF%6hCGDRZreEGQXILQGU9QHdN1@29X0r+CAaYLmhIjm[+PiBPfk10[ +!-#lV`bE)+a%p[@2cYQdU#9pF'hGEG4e(DX[jFaSV5dZPE8$6(eHV*-B0lG0CEa* +hUE0-%*%k5!5U)h9QjT2@1DdA'LkV,9X[(h$G3C[,Kd[&GkQHp%Kp"M(VDpUHM6f +b@"Hj,@FjRRTfZP5bI3p,*4dZ93+rA[,d[1Yif)VDVr0ciTSYMqZ"EGQfAT9%VGX +$aT'CBP+9[6ZeAdFE(F2LbjlUE[MZBX'DdkSl@QbJH,IkUR[+FrBeGABBRA6BahX +*Q92PClK-VA&e*9*V&LFUP6MEfMKEmC0XPm6p8@pjFhN!J1lr[,q-kZq[jQYB+(e +eS0P$8Z1eG3aQN[PE"ef,[8iYTL%f@kl,M+G$l-'G9X$1N!$D90&aVkD6GP`9))5 +'h,fd1RC3S@[LHR"E4XcUp#1RXMLX)m[K'Rbk&96Rf0h#2"*GhJZa+N5i&96Rb#& +Z"A8C&3ehb9C3qANYQH9j,Hkjq4bZ0KMSai0dalPj,6h[jpcemeUFpZr[api,mjc +Fpr0DJZe4`m8YR+XR@[[$dG)!lVMY8GebUhf+1-#JUeYEJjVLf8c")#RaBN$8LT- +$SL31!k+fYq-`)'VEmPbbEL5+mRB2a'&&rPA,!h91$0KbAm54X`-ePTA)Kmj1M+J +EpSr6NR@Sl3LmX'YN6j*J&pR%Zl#hZJ`5ijhlpdm5da2-C!i(`+%@5CAX15PXc6$ +EM(l[X#6jLJD'dMJ"mQM-M3qGM#-21@UbGEi%T,+$-@4X#QYPZ`$bf*`ClJa3e`f +&bG8-RmLMG@42-6e68hBBhUm5$lj+*AHejMjQhaRE9PUZkrYHDNblbc1[[%2Aa%Z +YHQqpPfRB2'3$pY1RF6TPYR-DkJirMfFq[e0!(QF,mUdmcSlkqRBHCa+jN!#(6'a ++E,TLKqRAGafU(IlDMLlD*hm#XbL2h43(QJdkNGeCTNPm2iEr`Dj0,dXP[RK[c$T +0(Z'XRrpG$mC2QMc1YJGjk&*8`i@eHFJU@Bk!2(Cp[l)MGBA"qRQF4U),HCc6rb8 +2fF2UE!b64jHU2Bl6GXZV4!c8[QX"TlGN*TlJ-F4Br3-QXpZhipf4RMS8j&!Br)! +e2*C(9mhPr+Xc4lEP'Z9RA9'c3d!HR%9SNUIUbP"HCGc$LmLl2aMhd"MM*aRhF"l +1!-DpIQJA*kQG1Bhjk5IUiIKJlUH'6[m[jMkDaq2-I652ajRler0iM,Q2j2&YjZj +pqZ1p(3#BqiPkI*Hj$aIf#HBqNXIMc2e%'YpKlL0jR'2ZSl6Gck0,9rqrljdIM&X +fb"Z-m56M(XU$i`KJh$,9mqVqe-SkNMfRl%H-5I)iJ`cIC%bMH6c1G,kHaf0-Cb5 +2Eb,jL6bqJq3MHC`$2FR$l+ijJK#,-(I`Y(qS5*cU%-RM`-cHar0B2l2hL6c+FMp +iAjc0j6+B)qX#10p!2&PYN8lmHKllrTFV5KlXUj!!hd[a4%I[MLIBZJ$UqM4R#,M +d18jq)Bm4j$cACd&rb&cXljpaCRA&BB`C(kZ2ErF1*!kpj6XU92r*Ue#IHHQbqZJ +%b+2H$8-&L"%!'FT$X*kk*KlAbBeUk!5SKe(lR!"jq'VIk6`ZU(fh4h9A[3)28mR +M(NbIpJiNlS0pbVlHa*[Id&"A*'kmk6@[Z#Tam(5#LFbHV[6JIcaairAV%QrqXhK +DYFPM$lYSZ"lRqda9PSl'prS9PF8!dDNmQ$DIi&$qTr[HU#a1J(ie+SX6)!q1KE2 +%6qTUmT!!pNMmY$qDI)pcaBH2Pm[P1`$-Zf$pqa(UN6Lcmm6,KrU*ecialF$[XG2 +(F"JR3"lVpJD902j2e49@kUjiXhMkp(1K`XPcSHre4ji,IDpIh3'+Xqq-(#,c +9D6ca!ZGmAGd6bM9(1GA&ZTSmcZf"F6k2N5GHLHGdIR[MGITFB$TZT6GH6ar(dKZ +[Jih[Xp14ZMS+hSSpI4`JEm91!-KhhSUG@T(+$I"@,0`5Hc")DHF*jZkSB+C1!14 +d+b$9q6-k!G,pSHNiA#EPR$i1!Lh'$63TjqRM@*U8Fd','8c%4D$&R)fK%hI1(2I +@a*f4jrqb!*5Mi[hri`c1[6&(i*[-kd3Hhf9H``9jJRQ0j1'FQ)p`JAN0*Z)@Q,0 +Jmj!!9F*1(C+3!&RlPK5FLZ-'B!3Q$kI%h!Gp8pEJfkX8TH,*PkL5aA#-Elp%2C2 +(H3eZK*-l2ejqRZN2*m2,ck&k22RbmdaGcfX0jrZHmrL,c62e-(NmpQ,c6"ibdIF +EZfY+((EAR,)kSMRBA92LX,[QT08i86jX(cLeR6IlY%eEc5Ha%SIj`02EHE-*h-c +91#8VFFEMQYq&FlJql,LChm&c1!i`Qpr"FcJ1Zf[q`'0e$2Z@h6@Ifil$D1MRYH1 +`iqESETd5Kp(ISlYe5KbfV"[GV92LX,[Qk'kGiXAZQU1lG8SF0VSEhDe6iV$MjZK +ZR4+(%HElf[9KK2Q2VSj%[hXP$L2(4hIe&#ri6rA*A6dPcMaFlf[AF6kZ*hIkM1) +X`2AN6Tp4R)@iRYcTXf3P$T2a6qld'F6*!q&B#f%(6l0RCk-94Y!Hd`X0(aYiXKR +QLJSFc)k9c8-6$Hd0MaB@29XPXE)QVa4c6KdEH-UQQHbYfD!V@!1c[KQ%f(NcQhI +p+)Yp-X@hH@J-m9CcqdX624dk(RDR2+5MCZ$TFK'EBFSqPFX(6Y3d[D1r$eYQ5RV +09K$U`D!kaeL,ZB9Ql3#fiT3Y0A0B'A-YeY!mLMJ*Yj5(d0`HB+p,'EkjclGR5a8 +[9$eeDb(RPjf+Si0TTac98*GkhkXie@DJKjT4K%Ua)@BEem[F%3i(eV`eiqU-l`G +PE-!Td9FZ4Yb&Xm[&1TYQ)p$kh$Kf#@hh9(F@)IG09Vei2defc,4VG,E1MXaT$pY +X5Qe0[4CcMmdPII'YPKYd,ZhVikff0kiTZfl@$X#[a5PMMdhkVm'Xp#RYNp0H&98 +cAEN+kE+C$K@@ABAUXA!S@5kpL0NX(lJ)G@L*9rr8(6GeqdmU`1DD5r[kicTJ@h) +4Ue%lX"9lP0Te19Gjf0icN@4qM4B@(9f6(9AV#YQ*U6fS`T&'85r))U1*j(J1Hh* ++TTXJh#H5NpM"V3%lQlBkf'5dSP6#HU*Yh2UcSdb%N!#Y6J9K@1kd$5dP+*2&jU! +(XT'ZUfidr'E6CfcrZDU-YpFKSZJ1U0QC'AmKVQ-9Hd#+)FUk*(l%a8kQH*MY2a0 +&fF(c`'pH*m`MdH@r6S"1Gr!mm-UEiadmli5,Xf3(6h3BqD1UC2![a6q,IaRqjIK +IJ[pir#[aVm*r)[k6m*q-IcAq8r#IL[m-r#r&IbEq0IM2`hmqrJ[`AbLD"SHpQUN +@QKfl+G[Y)YMedZiVM,k"ESSQ#Y0$bd3(C-pQZJ'0%Id3,3qG$Jh1AA$)Nhc4fra +D8"IU46G5Zd,GU#depZZ&pNIpU$8epq['9UI8$Sf1ENCEFfFFHS"Dqre,[HN*kKh +eJpmcp!6p3"rirF[GCA$ml!aR,Cr+Cp-%h)k&EdF,P$CR!8Dj#XljR6`FAT-'('- +lHI$-bDQeNmHh*`3i!(Eb-(R)2R'M#CmlB`f(h6kqYCA2'"YLYiqA*'kmCF1*h6l +HHZI2LN'lIC`i@3`!6TRTcc+bD4)R"GGYVfT2"ikpr5QSFASG4N,VPJUT'!pFE6$ +3M`FPKKmFKE,JFN1&%!mb"JrU-19hHEU[BaY[p2&!p)1*ar"J[p@C68-)m@!#0MR +`YTZ(T5h0"MALZM&Xb#'EBEM8J-((!e&Tdpr#!hQ'F-J+(0e"$4#JaH*!!hhD +Q*E+mXK@8m8S%9$Lf29FB6f@f$cPH*c0d#2PLq3raJ*Z`L,TmFmCel&6@XpeQZA- +BJ`Ma)2XN(XMXhIfqej%-%N)m+$ZQ,ql#Z18G8HFeL6(%JbV"JdBrd0c9U5[9Ppk +5hYaT$4+MNhN+MFibFTkHVGN2"U6GFAAcL3EfVj$MKhUbDiq$B)SY"#%kG,E) +@Qkd!0X5E4jQ6(AX6V`0E*Icj!l(0HmH"H#Fk"p0-Ze2pbN!0[f&lqrAeVAjeG@f +40G6h!eYNpH1dZhk,,*H#!Z!'fM$JR!*3h*IP+3A!,E9&eY0p2kCPf#,VhHIG"EB +kc'll6X4Z!rA4#C!!4lK&eP!H!pXbpDKL4M9d!Y6$U(e1J$b#,E*1jA&"l62cFh0 +AYlE)NNGL@f#A,E+5CliNYPGqH2cfVY5pKf"LLka(i2r"VNe2Fl[1I%@m994qIZj +`2Flh@EK&eP!H!eYNpH34ET&eX4j'CA%#p+Y4@C`!HA"dIZl&ZTSml"CC&r-B-rC +XN58E'%`ddk9VLV1T$CR4(0kDA2%Mr0LF$FI-'i$+KrEFrK33kANH6Q$FQ,JkF9V +APFFLC1-EFq*0NlX!6M,qFh[X(%6b-lrMR9*U2lFTkVf*Chmd%XpdaI@8a$aMd1- +P[18ie(eD+djh0Q%F%,hqXAc#[#IKZUS9Cl$q%UFDedQVH8Ij6-9eHMZ1$1*)A0U +1-ahA&HdiPa)6rQHpDGR5GTaCZ0l@MM-Eep[EFHEJfY'1!q@j["eR,UlhY2Yf(Ui +0l6McFAheUI(QD"+cZmr33r`i#h'pEl8q86kAieV@MJ22q2(9rSlbIJDZVh`-p`U +(G(@G+9G[(&MQMT2LJJ[Q)&'Y'lamN!$rbT@9CXbiRjCc*P2R*hT[2TMSVHbBQNK +0MYA8ZDN#Eb[ARhf*5Zbq$66ZNCkcGkPUN!2#0+Dp(G4H*ZrB8623+MRPZEipQhF +@0'E0966LA@MDA0[hjY5jT9)j+TAk,bb9'PB31CCEXS,!@LaK5jV$3G11r'"d$NP +9TBHD8H4l)h2DLr)"e+#UG('f90#ZYL2(pc,eXZUjh!QEPMZ-Y-9M4h#LTVApI@V +0MVl0[&flq5,FP[G[98N,'p`X,3@P4Y!)N!"Y0Ve64k1lQhK,Y'KN(h*UMP6hJP1 +hUKS[6E*CciPf"PC&GEZf'pMDG982!M)K6qBaG8CCVq+V068SiT*IEAprR$'hjId +AUQ3kbccUI6mSKfTGdDp@A3hKZ$e6XlbUMQYE8CbP4kXr''K,*G%M"p!dlD@kYF$ +U5%&A,NE)VLSr0)l1fX$!+m*&ceCVE+[aSMMVUq1XZ5h[hkE@3+dlV*)9*`LMR$q +Rme'JNUKCUej!ZAEV"C8-jjh)VZR`A0DUSK*S24aBmaEbPLVYFNZMMPIHEG9ef," +XIEQ&q-e$`qLr`lV!c#X+1LT%j3`,f+@'5b8EI9fV&fcGB$ZZRXaXf6CMKHKmDH` +1VhU*[E&[LefcJP)8@%i8AQ+rB'0I2pALA4DkAXc2CDdlI,64%6G5238lF"V4'&E +YN5Q%'r0je90ZeZZ,3qLMpQ$H+8FeB%+$%cCFDc&MHA-XED,EmQ`JbB&!GA[0HT% +EA8P(,0hFUpC-!MN5kp*ld!@0IYQT1$V)@Bd'5T0BJdEE%RG43QeDfpb9,DV'ZiA +,HkUVm3%-BJ2SVX-ialUaVXDlVZkDI[MJmqk"bmc%,R9kEQ6h&25`R88Vi2#!H`V +&bHI#rN!qlr2C`S166TQ2M4qfd$abrbMm88dq1HTDM2Ij)PlYb[f,M5!HU[M91D` +Q*T5RI$M``@HmFpDXD1jT4jf"DeYXfa1V9fq+(Br(LY+AijTG4DENVBeYLp5'P%U +m-,Bp5fh&lH856f4)leDaVF1i`AG+LUhN8e*[,el*-G9DbG&e`khF*bGFZ8m@BR, +-VGcRVd!dGZ*BZFpImGC*Yh+I(3IUCPfjEl-6rR3*%ZI(FALZh1I@'3!X#hIpQ9Q +KC&eVmPcfRE&YB!@A6em6VmcL[I9HTZ&Q@VP[U&m(9Zi,q[8cVAjeGDhF0p6h!b[ +hpH1dZhlP2TH#!Z!+@VR[M!*3A#lU+3A!0E9bhm@q(p-bV0chGZp!iY"E[XYZqdl +%EJ2ed3Q3!%HiFYp3(J1VaI@SBNBeG!,8`kKp6S!mJTAl6Z9a3HdVVYbAI2V4PIX +qdlATMYHF@,R[SBf2VY`hA)rcI4DZh$H8am$+I6ejK#[hADb(89QF!2eU9"BR3"i +FA6EJBPe0(REP[SYjM"Pl9Zk6PahbC`d['EHZ*af2B,rbPQGHmb#UqTDRS-ApG5C +L5l[-F9aB#PciJP,2ZlHM'bl-aYCl*FGaSIEQVlcl'9cT`ZPfNL#4"9cB$9bSa0U +1l+ISEMYE!3VS$"%ZE#-ZI1h`'cX![!9aHTd$%"Ib#ePDA%MFdM0hpZ($ph9f`i9 +l34C1i-,a&h4bJ`@cXL`EBCVl,r5mjTl$KcqclC%JHD,TGMY64V2M)k#A+Gj&PTU +6K90+pX`eEaeBG01mL[)9+hCTh($%S3Areb$N&DFQc0k`[(LkAb+`q5ZlcjT&CPq +'[eQrNF9P1Dr!rdH@FY(YCdh@2%GCFb4*jYT5Qm""9RC-[!NKjbpPcA5&9beP66T +brqXUKZ&Y&F8iM`R+RBe`HkUSSI09P-$La*ZF[kTLP,@TSKMR,T99cZ!bYQk%`ak +8U9LXcU#Je@E[*&IE[S[q#IHJ6(@'fcNRa!-8+1%(4r&feZ@'#L%HP(5Ffj28he[ +0(EFRkD5IH6$f**hFb@j2dP2E9cK26reS$Z$hjS*6ElLkq-6B5"I*FAMZ5FTB!DI +1RU5,cGj,'mV,!E*MmDL&JEfTr[b"f1Dpim"e[$ZCpL3GkYH"28Q$IRepUepGAAZ +5$[Ap`*kNr6MYVYq6e+@J!,L#pL3pS`!80m*l5J&`6He*HV([al3-Hj+qqlbl`&D +(f@hILGKYS$ik!I))pb3GbQ0J(m`H9FbSKNk!HKLec`Q3!%H`*qQT2#kSIF8p5H@ +4@,3RUCc+$jrBNc6M2VSRkA!pc[GCZ#IT8"i$Hj,fj"(Z5AUa(NCPF3,dUe&CR!" +jF(4$P)Ye0ARB28N[jM&Ql0Q60,mGU4i[RPVVqMPYT6#b[XrQ(!M(LrH*fh%5)e` +`"kDaE[$b3IiV9cE6-&-E@XkC6*fIk,hjB++hXQ0U)M8j9P2RTJUmV9arpL8UXIX +f,(lf5-rCZe3e0F@9eB,GccULZYA)@@%%9TYHD2LK5KCYYc4BJ80p[Db5qD'*K[D +'4`Z,RUf5"4har8[1U6X48UK+&fG,`lVLH$V6$%)r80ejeiqbYZr"YhPS$2&@Clf ++(dG2KilAVj+"MTU"Tm[&aBC@DhB-$*bSDAT(Iem[DV'hP,H#8!m'e6R'@Mb!@qh +!CTAdp2biVN4CVk`A%#IKP[+3!$$DJcP080RRfl1PLKHURVUeN!$cbdl&dF'd8ij +UU%Zple@FDM233mdS3U@QXBVePMGRKF1"0@r0Z$VMqd%j90f)[R)aJM55$9eV6ZF +M9,Jq0qkJAcT9GaBKpde@2E81'FJ,*%RX6Ke%aGQ41He&F@e0[4C[a@e*AhbVhB, +EdViqhQTlijV@aM89[aDRV08kpPp$)3SFViVfb@Q[LUUCVPb&G0NhJJV,"KVeIM2 +1FZP&c'Ej`%@S3iXGq+ilB`@$GZ6iAMi!VD)#em4C,ihVJ'h*4Da'lF"@P4af`SC +V,Bji8E#SNXb[dBVXfXlXU&TAb%j-l8%9MM5+HL'##,6EReI*mGa1(5(66C!!K'5 +`L@a@e'"&ZZM8Y8U@5P8GP5,dGNHC#,%c4TJfA0[38S)bf5D5@"[TZZT'`fmfIEB +2VEbUM&Gp)D+XM#-RZQGQr)@iMPAX!5Q'D$D5q"%h8Yhd@"eS[!CXhE5fZ5YE92X +q(Xr6!H#5q`jKGJj!GafQFY@0GHflje$Ap--(cqZ(bmc%,R9kEQ6h&1DelbaD!Gq +!hP-S6MiApJIbHCrUdi166TP[aKkfG)38%hI"(pVjb9(ABVc2&r(i5ZjIE!6aE+b +[S[ZlX-e[qA$JJmpijkaCN8l5MMU$T-[BpULcF(e6l(KF23Hh,mFeZiVlEAPVBpX +LY5'P%Y`R,j'i3'h&c5b(*r&%-["Z&CXXHMIZMbA&9[a,XGfGP2bTeHi-,h3lN!$ +$8V-2Rh2Qb2*q%mef$6A&fG5'X(C"Sf'IIc6%jQ`iCYijSTDP2KXM4#*rH`H%fRL +AiUJY#4%A$$)ij(SjNpGR*SC(eUI@$`m@"h&YcQD+kcZV0%"qHq8m9(#4c3p,V,6 +II)TIJ$J@klbVp[!ja0-R4,#%QNTFR6LYkmVMPA-#C"QIFB+3!"A3$R3rXFHR'[E +TS5kJiiM33r2E@CUY-#XTKTRjR1dKAMi8hbbJ#cC1[pJmQf&[4TP5bRL%QSNIBfZ +!Ua3L26bqFimpkj3K`1bC,Z!Yi(J$0EC+j92jE*VL4mI#BrA8URBcHPQ[N`4Ld$+ +&0q)&SC*25J!(%A2QGl`PeaGcDF$H@j!!X$NX+bVAVUlPQJe@31+![Lmq'5GIef" +[`E%Z3KaHiXMHBh*,3@"fc1eJbKY&Ypb1PA*&S((,m3121j!!Q@R96YFGb14GeJE +YDL[8UD'QilBQ[VY6MNYZ"l,-cd)YQ`XiSHH#-l2'qABD#pQ4-l-HjP9hkLJeXY" +`XCApNqq+ed,p)DbS3'II,,[,6NDQ4aqklfVM)&-)$hhQrU26S`ppmVTiHM34h#E +6Sdherqii)DC(ZfQ16)mHQEJE6G5eIl"L5bI+kG'P(*0V4p$+hrdc5jUTYrjaTFf +9GS4-LAD$5"8$4r3,LMSkL$VI%Q0QK!(66mCa1Tbc'`9BIPC$RGP`YIcJl'6Rqm( +CJJGMe)6"f5YF0e@)V-La1`%X8HrS1)l'`GPM6C&aXU0Vc%cZ8,V'c2kIY'Xq$fI +%1M3Q$cI11M4pbdcq[c`F!$KNmR!$V'IMJKi)l[iDr[TAQjqkj8E&ZQJ@KMB6FX1 +KRf0TK$2@h1&bdK'9R2Y6cbP$lH'*Z@&-9fUFIM'(+,*rMa0Z+FL'dI&L"i#P),m +AhJ9f&[If%NFF-(d`PNG3dq!XjC-6%dFjA'ERj*54LL4!HYS*1EBd1jSG(i(8j-Q +p@Zj6j$jIlP2P2N2Z-q9qk8T5*8r(QJRlrFL(,5RqTA,2VX4*pK4YGe0a&X0LG`C +@i'J1d5aR)+QERf#0f$0LpqpcH*F0#8eKj(i&lc,RFClFjdUFk5X*ThS+Lf'NkdF +6(Lm*qK9D)2FbZIX&Z86ZPC,`G%R8G)VX$6PEr+XNlL5j6jEl4)NlGk8JQCqIeKE +VhhQX#9)5dq3Xpi9b[h`PG[Qk54hkcF$@BHSmE0ba0jAabpb'`a4-%M@G)d&04mM +G&%lZTP"bRb9h[f#Q%D53!+EPCI9-8`5acf'fccpPI1e,AFHVTUc8(-Ud)r'#jec +YH+&6eLRV$0Z[ebf[R&Tbk%aC3@!YGL)M&%k')a$,Si"-Dah)RS8S1jIM)(a2@ik +61E,BTcMNic!KZIkaI-+m*q'kkZ3DNP!!ZGkmQRH8ca4FYlIM6-Fefkl2$&a,fh( +BN!$hYRBF9[kl[4eR&UiGl6LcFEfm(3H'F8qlcaJKhG#1-aIA9jf+1#DQGl62JVe +6iBTb[9rL62THR!@ihVGDabM[bh!YDmGCL1XV@h'kFDT`A06V@EEG$*UCU)I4m4F +ajCMDAd'rRZRpdkrKBVRLT``db(3T,Xq!AmFa[`9l*3r*,rACPYre,`EG1flbLra +Q)EmNr55rb+q8r+BmhUkkI1BC60MkCIq959UrEAYJ8b+9i3CZ0PlC4cPYAiP*'AR +e!bEH9Dq(6EIN,82HL9dQhXFr"jY3'dlkCEJX0hk2EQ*LeLq*[NQFBIcHaC(R1U` +qLhSRHNeq9e,"dJGXf9Cqj42[C-,@l`E`pj+mm9[`TkbCpKqeR'cbqaAflcM*qrf +ic$$aERirE"A'l`Ir#Rhm-H1hp#ZXMFEEcCVC2,k5KBhHSDlN1Xhir3@jGkAi2G, +UXmhF*KYp!ErIBfcVGp0[`$E"q%e"rhSQ[h+,+q&10(iPa)dkNpqIX(lS$q4"[eD +BH"h[BifYhcc`A1m6aUrTGq#!$N%mfGYEqk$m-ZD(lN"qp+hfpi0[JSdYZVQ#Bam +fIQpR$DBC[aV8f(Z@b@2$"`PNeQmaqr9YaZpP[mEHd[`qJSYCG$GafY[r$MCd"cP +,IJmpCHYApS&IKB1Z&YU-2Xp)A9rl(`3bkrF4k!EA5Vch%c2&cTP'r$KHMd,@+#6 +AVd'-c([U8Ec85HMhJka,Fceb+85(IL8EfD-5$pb0r%+mI#Ne"+0m5QjX&flaXZ` +IQ*1ZXT!!qTG@['II$4XaJ6Ab8lbmJre+A[MpHJ[2aRmHY[Q50pLMH2P,(f'ZkJI +Z@,`XVh0rC[3&kK(LjE0r'cEd"2a#[$ai)f`k!Im0m2IamPiZ6I--L3HZ+%j-q`a +X9iJIbjmSAQjm$faA'VqIRQ[KCIf,i+#,jb4C$m@cUC5RU6re`fEaX[aCA16M@H* +hI3Z(2NIHX%MmhY,#bjF6Rq!1FUiqf-,,CAr2fLXrJ#GB[#c2rKD"4ZY(A44A$K2 +li9PbVN@G&#r,V[Yc*UCjX(k6pX%Gj"M2%Ep0+hJ!Cj!!,G)jcb('@l`X(b92ZXE +i,IY8#bpI#Xa,E$0qYH`RaF[Vf8[,K6r4IaB[bi[Xq9VMer#UCE`XIc9l46FMI!L +V6rKi14kj*Lif0,)#fkaI@c4er8AL+$%T(EbL4[!b&-ZqJKS)Ml4iQIIcZVq1fqf +#Pf'mF[D2MjHKAj,pURhmb$f`JHhiIEc&,cGbjBERLYqMVAL2[JifAAXK4GkSH,R +d!GMS+IaHfm+c2@q%EBA`DITImI*$V*@Z6eA1Zq,P`QYKdp8q8PpZi@8p1(4#PTY +*NeGSIRH4Ck`bIC!!!YG8[#al2hQ2VTaKpT&AR-J4)pB),k(r,9k@hFUkbVldj0% +!RZ2MjEh-$5j*(ra8#bqRIBded$cbH&Rfk8r$TNZ8CEPTKZ,3&-E@*ALQ[ED&Pmp +i1fb0aQme0V6hmA,0'q$3C2cQXQm8,rFcYrA56p49F@AaRj!!-eQr6H#C2VmFph) +iQ'hU*4ipVAd`(GLFQ*6mIUC9TmRXh4E"[rr8`XY1jUc2N4T49mA,XRrF$iH0aUr +Z[eYikEf9KE"qmiNIbLprlC@`E6Cq@m"aIEcFIi!1Y[pZ4YiqAQiRaX"Ca'mRq*b +2Pjqk(KjJ![@$"rYiQ4GP[@XrKMaH*ALCpdYX"qiQKJ8[3lpTM12MCHMRNAGTIa` +K4Qm62r*AI[P1iKbF'Mmd!ifhP0abZrLabElLj@6@i"E"&ELTkM([S`CJYZ8A@J3 +2X(KC[S-jkHBLFfpUiHAL6m+Qfk)NZBD)aFZb$pi#Qkk*Y1c0,EbF4@h$,L,L[30 +jqRMjQm35p"2S$hfV1(%hZB(ZkVD!2&2amK2NE(B$(Zm2J6f6EcEaMU2R%V+1A3R +a9r(X!@SBZQI,!Z+lmX[DIE#TMMEhYPEIc#6f`drT!h"@mA)EHDHZ)V-9I-[(bqX +q#JI9lkkP$U*kc+28X(6KU#A%&m@9&QS"UZXGicDVLTHl@!0`JAMdJrE"SPI$TQZ +H,#2H+"rk0@)V033@i,+Uahb-2D`kihC`G*pI,LC1k0)T0a2I&5qVUBATQL2ANFm +T[pc&2Y"PHMi)A2Eam[lli##mR[jl(h*9[#cl!$K%BYli2B`qmI(b5`r"3pFB[iD +kL)qAiHEX$b-2EdQ2#IfQNEX),KUm$2hQ84Icm6,[jcd)lMAqTRT82DCh*VY4Mq6 +'HL0%[0![G3EiA2+Ur(JBUG2H4FkU$p$QhS',kUaK21mdiTVNGj!!I44ZKej1hH@ +$iKIbhATLj0[%,m6ekql#j5Va#qZkM$USlDH*Gc#HlK0c2AR!8Z2h9Q+SlNCI3Pd +X(IY05K$6L3r040[EDI`-lX,&b!mHS2RGrpH`JHhJ!Ia*mrX)X4jZ4Al`4T[Ia(R +@9Gqih2+0jI`Q9VR`bYf50reYmjZdPEDA',qlU-0TITpP$m(&b!pFe[V0Bmd%9dd +mY!UYhdcbaCFD[bELMZEh#'YkMr%l5RjZmj[d"ZSZB#EjJDPD[rp!$N(pL8FHQPm +VYC9A5(krM-XEkZ%M1YpkmY,hLPqq[j0VUCRpK[L&rIeKkU62&ja6MCX)%m$4!ek +Bpr01TalRid6H,r&XpV12Fk(IGR,ak`8A3lmQpT[P56GqLM`-AJ"d5ee99mKY)Jq +ierKGKMj4r-lG4Xa$(a#rCb+'iRHZrk[`Z-rNPb('@0k6ZjYB#AH@XjPF`I+U'ap +Llk*T8)ph,219h"rp,@a`"$PEb)dXVmTGc*Va4N$ki29FTNEcDk,qJ4BKjpA%"XZ +VFNmMrk#'p!'iU2A,8FY!!j6kl56[XE`UGq@(iB(Q56`d')hh@q6-j%9BY&L,(lR +,U(QJ48JHZk(j+8r0lDA'"*qPjF42F5AhIZ,I6aLrea!E,+lFq#AU8ZLVp$GiErP +dlMh8*0#D`!Rd#-ZRFkpLVk-"iTIRIcGqm@(Bd$5S(cA3IVUFfZJE6ChfN!!2@Ik +AZ`"[&"*[%lrIAHCrZ8&L*Aa+r2CqBCRrjHlq%'aS34,U*kR,@2kA1qm'f0"R*0i +qp*[b[pa1BZfEK+I#kk`1NEZ6IB`fJNYHImVY)Kk6#b8#Ak`1NHZPGS!H++H0I0l +U",QcL(9[0AQ2)lrem6A%ZHR%Y5V`-hKaRMmP3q"LL4*me6FN"[r39G%[`GHmAq* +Af!Fq(ihm`"dIGd-rHa4hmhlHYH`VLl[9HpLVF"E*qbMUNGPKr!j6ZraCirG$`&r +&hHUA8q[RVBVir6"`CdBYpT[mGGB%IL'RP$c2iQ+eaGj$Kj&iRHacLl[9Yl*R`&Y +`#2b`r9Gp2I8cp'IkMhkeZ&Yp"h9PY$[b%(kJZ&[Gi"X$q*Vi(D!@ER'h@K22i"6 +8qk&P(+hqGElE3&-LRQL6LV[9ee)VHBraZi2BVr&qKhM'ZaMmrR!CGkZrr$IN@0E +[MAM,SVKEr5&U13m+r`!R,1j@Rdrp'liQm3laABh&hHSm-C3h#2L"(aChU`m3iq' +$q0'(&RHVCmJjU5Gqj'PaYlVr%l$a&J1rhfleNdIZbTXJm61pCA'hqQh-PAi4[cI +M(BlLERAkRq$"1`laH`XjU-AGkYqP,S*@6(jSi4ChU`r`$BaG)LRj"qJEaGh*hb! +@`6[Nh%$X+4Im#r&T#hRR$X(,%2rHJI`#A-`[r*5mPARlZ*Mh5ea-AZ(MBKM[2G5 +*I&`X,JkPZ"M'kb+f@9aXqMJeUBFP$qNjaFA'KiQ,F%raqe9`%FA&TR2iaJ9Z)Ri +I31pHDZ)eh8AYM(G$Y!$pCh'Vk8kqHB$l5,bh%9FX,MDGahKS(G3MrikND5-a'fj +)2$LZaF@QAfD0H&-MIMm,6Uqif,5'ZB)$i[GcI20KFE(T$2)`X!Xrp%@Yhh6L*Hq +mm*2BLSY0,k'@J'BSIMp22,$a'Vp%A3HHL"r[4LbH06j)[%6Ea!pHD['XkII*AF! +dr2#hH0Ddb2F"i#eqk%m@cjSX[[8#Ur&$kp8qH)Kp`aXCr0$r,*iehXmh#Z#$q2d +"hUFTRM9G4Yi[["+r6m@kKI9l,ppXS$AK4adYRM@pPpS5lc[`%ma62'[D5*hJ%kD +2Mj,6qlJ9iNS6ZC62md*Fq@1mir&q,XkMiTrj4Z,hMGqRS@HRhf[m$T-EJ1(LpeR +8dBqhL'q``'6aqpbrYq+Y*lHRAm6[6i%0IV`0j'EJLIKp!6c(MrGMe(6rb2Mp'Gr +RDE`h%-qSTrMp0qKVIV`rT6EmDH2hPp#Fr(K',k%Qi[FPk-eq202#q)VI9m"aJhV +`pSQh(Z,h2r"16q0GmJ[N@V`2%Th*!blim6l%0f#I-hj*jQ2j9X@YY%Rpm8[KhBE +bVBVA%r0jfb9q@I")[aiI)+Fh@ZMr"`"'`J!!: diff --git a/mac/tkMacResource.r b/mac/tkMacResource.r index 23a2000..76bd528 100644 --- a/mac/tkMacResource.r +++ b/mac/tkMacResource.r @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacResource.r 1.35 97/11/03 17:16:34 + * SCCS: @(#) tkMacResource.r 1.38 98/02/10 10:38:07 */ /* @@ -73,12 +73,7 @@ resource 'vers' (2) { * will load the TEXT resource named "Init". */ -read 'TEXT' (0, "Init", purgeable, preload) - ":::tcl" TCL_VERSION ":library:init.tcl"; -read 'TEXT' (1, "History", purgeable, preload) - ":::tcl" TCL_VERSION ":library:history.tcl"; -read 'TEXT' (2, "Word", purgeable,preload) - ":::tcl" TCL_VERSION ":library:word.tcl"; +#include "tclMacTclCode.r" read 'TEXT' (10, "tk", purgeable, preload) "::library:tk.tcl"; read 'TEXT' (11, "button", purgeable, preload) "::library:button.tcl"; @@ -97,7 +92,6 @@ read 'TEXT' (23, "tkerror", purgeable, preload) "::library:bgerror.tcl"; read 'TEXT' (24, "Console", purgeable, preload) "::library:console.tcl"; read 'TEXT' (25, "msgbox", purgeable, preload) "::library:msgbox.tcl"; read 'TEXT' (26, "comdlg", purgeable, preload) "::library:comdlg.tcl"; -read 'TEXT' (27, "prolog", purgeable, preload) "::library:prolog.ps"; /* @@ -130,18 +124,20 @@ resource 'STR#' (128, "Tcl Environment Variables") { */ resource 'DLOG' (128, "Default About Box", purgeable) { - {85, 107, 243, 406}, dBoxProc, visible, goAway, 0, + {85, 107, 260, 412}, dBoxProc, visible, goAway, 0, 128, "", centerMainScreen }; resource 'DITL' (128, "About Box", purgeable) { { - {128, 128, 148, 186}, Button {enabled, "Ok"}, - { 14, 108, 117, 310}, StaticText {disabled, + {143, 147, 167, 201}, Button {enabled, "Ok"}, + { 14, 108, 137, 314}, StaticText {disabled, "Wish - Windowing Shell" "\n" "based on Tcl " - TCL_PATCH_LEVEL " & Tk " TK_PATCH_LEVEL "\n\n" "Ray Johnson" "\n" - "Sun Microsystems Labs" "\n" "ray.johnson@eng.sun.com"}, - { 11, 24, 111, 92}, Picture {enabled, 128} + TCL_PATCH_LEVEL " & Tk " TK_PATCH_LEVEL "\n\n" + "Ray Johnson & Jim Ingham" "\n" + "Sun Microsystems Labs" "\n" "ray.johnson@eng.sun.com" + "\n" "jim.ingham@eng.sun.com"}, + { 19, 24, 119, 92}, Picture {enabled, 128} } }; diff --git a/mac/tkMacSend.c b/mac/tkMacSend.c index 85065ac..dc4e8fd 100644 --- a/mac/tkMacSend.c +++ b/mac/tkMacSend.c @@ -6,18 +6,41 @@ * to interpreter. This current implementation for the Mac * has most functionality stubed out. * + * The current plan, which we have not had time to implement, is + * for the first Wish app to create a gestalt of type 'WIsH'. + * This gestalt will point to a table, in system memory, of + * Tk apps. Each Tk app, when it starts up, will register their + * name, and process ID, in this table. This will allow us to + * implement "tk appname". + * + * Then the send command will look up the process id of the target + * app in this table, and send an AppleEvent to that process. The + * AppleEvent handler is much like the do script handler, except that + * you have to specify the name of the tk app as well, since there may + * be many interps in one wish app, and you need to send it to the + * right one. + * + * Implementing this has been on our list of things to do, but what + * with the demise of Tcl at Sun, and the lack of resources at + * Scriptics it may not get done for awhile. So this sketch is + * offered for the brave to attempt if they need the functionality... + * * Copyright (c) 1989-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. * - * SCCS: @(#) tkMacSend.c 1.7 96/12/03 11:48:27 + * SCCS: @(#) tkMacSend.c 1.9 98/02/18 11:01:26 */ +#include <Gestalt.h> #include "tkPort.h" #include "tkInt.h" +EXTERN int Tk_SendObjCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); + /* * The following structure is used to keep track of the * interpreters registered by this process. @@ -27,17 +50,12 @@ typedef struct RegisteredInterp { char *name; /* Interpreter's name (malloc-ed). */ Tcl_Interp *interp; /* Interpreter associated with * name. */ - TkWindow *winPtr; /* Main window for the application. */ 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. @@ -61,54 +79,19 @@ typedef struct NameRegistry { * 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. See format - * above; this is *not* terminated by the - * first null character. Dynamically - * allocated. */ + 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. - */ +static initialized = false; /* A flag to denote if we have initialized yet. */ -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. */ - Tk_TimerToken timeout; /* Token for timer handler used to check - * up on target during long sends. */ - 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. */ +static RegisteredInterp *interpListPtr = NULL; +/* List of all interpreters + * registered by this process. */ /* * The information below is used for communication between processes @@ -206,9 +189,6 @@ int tkSendSerial = 0; 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)); @@ -221,8 +201,7 @@ static NameRegistry * RegOpen _ANSI_ARGS_((Tcl_Interp *interp, TkWindow *winPtr, int lock)); static void SendEventProc _ANSI_ARGS_((ClientData clientData, XEvent *eventPtr)); -static int SendInit _ANSI_ARGS_((Tcl_Interp *interp, - TkWindow *winPtr)); +static int SendInit _ANSI_ARGS_((Tcl_Interp *interp)); static Bool SendRestrictProc _ANSI_ARGS_((Display *display, XEvent *eventPtr, char *arg)); static int ServerSecure _ANSI_ARGS_((TkDisplay *dispPtr)); @@ -265,13 +244,103 @@ Tk_SetAppName( * "send" commands. Must be globally * unique. */ { - return name; + TkWindow *winPtr = (TkWindow *) tkwin; + Tcl_Interp *interp = winPtr->mainPtr->interp; + int i, suffix, offset, result; + int createCommand = 0; + RegisteredInterp *riPtr, *prevPtr; + char *actualName; + Tcl_DString dString; + Tcl_Obj *resultObjPtr, *interpNamePtr; + char *interpName; + + if (!initialized) { + SendInit(interp); + } + + /* + * See if the application is already registered; if so, remove its + * current name from the registry. The deletion of the command + * will take care of disposing of this entry. + */ + + for (riPtr = interpListPtr, prevPtr = NULL; riPtr != NULL; + prevPtr = riPtr, riPtr = riPtr->nextPtr) { + if (riPtr->interp == interp) { + if (prevPtr == NULL) { + interpListPtr = interpListPtr->nextPtr; + } else { + prevPtr->nextPtr = riPtr->nextPtr; + } + 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; + suffix = 1; + offset = 0; + Tcl_DStringInit(&dString); + + TkGetInterpNames(interp, tkwin); + resultObjPtr = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(resultObjPtr); + for (i = 0; ; ) { + result = Tcl_ListObjIndex(NULL, resultObjPtr, i, &interpNamePtr); + if (interpNamePtr == NULL) { + break; + } + interpName = Tcl_GetStringFromObj(interpNamePtr, NULL); + if (strcmp(actualName, interpName) == 0) { + if (suffix == 1) { + Tcl_DStringAppend(&dString, name, -1); + Tcl_DStringAppend(&dString, " #", 2); + offset = Tcl_DStringLength(&dString); + Tcl_DStringSetLength(&dString, offset + 10); + actualName = Tcl_DStringValue(&dString); + } + suffix++; + sprintf(actualName + offset, "%d", suffix); + i = 0; + } else { + i++; + } + } + + Tcl_DecrRefCount(resultObjPtr); + Tcl_ResetResult(interp); + + /* + * We have found a unique name. Now add it to the registry. + */ + + riPtr = (RegisteredInterp *) ckalloc(sizeof(RegisteredInterp)); + riPtr->interp = interp; + riPtr->name = ckalloc(strlen(actualName) + 1); + riPtr->nextPtr = interpListPtr; + interpListPtr = riPtr; + strcpy(riPtr->name, actualName); + + Tcl_CreateObjCommand(interp, "send", Tk_SendObjCmd, + (ClientData) riPtr, NULL /* TODO: DeleteProc */); + if (Tcl_IsSafe(interp)) { + Tcl_HideCommand(interp, "send", "send"); + } + Tcl_DStringFree(&dString); + + return riPtr->name; } /* *-------------------------------------------------------------- * - * Tk_SendCmd -- + * Tk_SendObjCmd -- * * This procedure is invoked to process the "send" Tcl command. * See the user documentation for details on what it does. @@ -286,15 +355,127 @@ Tk_SetAppName( */ int -Tk_SendCmd( - ClientData clientData, /* Information about sender (only - * dispPtr field is used). */ - Tcl_Interp *interp, /* Current interpreter. */ - int argc, /* Number of arguments. */ - char **argv) /* Argument strings. */ +Tk_SendObjCmd( + ClientData clientData, /* Used only for deletion */ + Tcl_Interp *interp, /* The interp we are sending from */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[]) /* The arguments */ { - Tcl_SetResult(interp, "Send not yet implemented", TCL_STATIC); - return TCL_ERROR; + static char *sendOptions[] = {"-async", "-displayof", "-", (char *) NULL}; + char *stringRep, *destName; + int async = 0; + int i, index, firstArg; + RegisteredInterp *riPtr; + Tcl_Obj *resultPtr, *listObjPtr; + int result; + + for (i = 1; i < (objc - 1); ) { + stringRep = Tcl_GetStringFromObj(objv[i], NULL); + if (stringRep[0] == '-') { + if (Tcl_GetIndexFromObj(interp, objv[i], sendOptions, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + if (index == 0) { + async = 1; + i++; + } else if (index == 1) { + i += 2; + } else { + i++; + } + } else { + break; + } + } + + if (objc < (i + 2)) { + Tcl_WrongNumArgs(interp, 1, objv, + "?options? interpName arg ?arg ...?"); + return TCL_ERROR; + } + + destName = Tcl_GetStringFromObj(objv[i], NULL); + firstArg = i + 1; + + resultPtr = Tcl_GetObjResult(interp); + + /* + * See if the target interpreter is local. If so, execute + * the command directly without going through the DDE 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 = interpListPtr; (riPtr != NULL) + && (strcmp(destName, riPtr->name)); riPtr = riPtr->nextPtr) { + /* + * Empty loop body. + */ + + } + + if (riPtr != NULL) { + /* + * This command is to a local interp. No need to go through + * the server. + */ + + Tcl_Interp *localInterp; + + Tcl_Preserve((ClientData) riPtr); + localInterp = riPtr->interp; + Tcl_Preserve((ClientData) localInterp); + if (firstArg == (objc - 1)) { + /* + * This might be one of those cases where the new + * parser is faster. + */ + + result = Tcl_EvalObj(localInterp, objv[firstArg], TCL_EVAL_DIRECT); + } else { + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); + for (i = firstArg; i < objc; i++) { + Tcl_ListObjAppendList(interp, listObjPtr, objv[i]); + } + Tcl_IncrRefCount(listObjPtr); + result = Tcl_EvalObj(localInterp, listObjPtr, TCL_EVAL_DIRECT); + Tcl_DecrRefCount(listObjPtr); + } + if (interp != localInterp) { + if (result == TCL_ERROR) { + /* Tcl_Obj *errorObjPtr; */ + + /* + * 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)); + /* errorObjPtr = Tcl_GetObjVar2(localInterp, "errorCode", NULL, + TCL_GLOBAL_ONLY); + Tcl_SetObjErrorCode(interp, errorObjPtr); */ + } + Tcl_SetObjResult(interp, Tcl_GetObjResult(localInterp)); + } + Tcl_Release((ClientData) riPtr); + Tcl_Release((ClientData) localInterp); + } else { + /* + * This is a non-local request. Send the script to the server and poll + * it for a result. TODO!!! + */ + } + +done: + return result; } /* @@ -324,8 +505,19 @@ TkGetInterpNames( Tk_Window tkwin) /* Window whose display is to be used * for the lookup. */ { - Tcl_SetResult(interp, "Send not yet implemented", TCL_STATIC); - return TCL_ERROR; + Tcl_Obj *listObjPtr; + RegisteredInterp *riPtr; + + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); + riPtr = interpListPtr; + while (riPtr != NULL) { + Tcl_ListObjAppendElement(interp, listObjPtr, + Tcl_NewStringObj(riPtr->name, -1)); + riPtr = riPtr->nextPtr; + } + + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; } /* @@ -348,11 +540,9 @@ TkGetInterpNames( static int SendInit( - Tcl_Interp *interp, /* Interpreter to use for error reporting + Tcl_Interp *interp) /* Interpreter to use for error reporting * (no errors are ever returned, but the * interpreter is needed anyway). */ - TkWindow *winPtr) /* Window that identifies the display to - * initialize. */ { return TCL_OK; } diff --git a/mac/tkMacShLib.exp b/mac/tkMacShLib.exp index 0c28a4c..04e397a 100644 --- a/mac/tkMacShLib.exp +++ b/mac/tkMacShLib.exp @@ -83,9 +83,7 @@ TkGetInterpNames TkGetMenuHashTable TkGetMenuIndex TkGetMiterPoints -TkGetNativeProlog TkGetPointerCoords -TkGetProlog TkGetServerInfo TkGetTransientMaster TkGrabDeadWindow diff --git a/mac/tkMacSubwindows.c b/mac/tkMacSubwindows.c index 65c1a7e..562a977 100644 --- a/mac/tkMacSubwindows.c +++ b/mac/tkMacSubwindows.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacSubwindows.c 1.81 97/10/29 11:46:54 + * SCCS: @(#) tkMacSubwindows.c 1.84 98/02/19 14:56:28 */ #include "tkInt.h" @@ -288,67 +288,76 @@ XResizeWindow( display->request++; SetPort((GrafPtr) destPort); - if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { - /* - * NOTE: we are not adding the new space to the update - * region. It is currently assumed that Tk will need - * to completely redraw anway. - */ - SizeWindow((WindowRef) destPort, - (short) width, (short) height, false); - TkMacInvalidateWindow(macWin, TK_WINDOW_ONLY); - TkMacInvalClipRgns(macWin->winPtr); - } else { - /* TODO: update all xOff & yOffs */ - int deltaX, deltaY, parentBorderwidth; - MacDrawable *macParent = macWin->winPtr->parentPtr->privatePtr; - - /* - * Find the Parent window - - * For an embedded window this will be its container. - */ - - if (Tk_IsEmbedded(macWin->winPtr)) { + if (Tk_IsTopLevel(macWin->winPtr)) { + if (!Tk_IsEmbedded(macWin->winPtr)) { + /* + * NOTE: we are not adding the new space to the update + * region. It is currently assumed that Tk will need + * to completely redraw anway. + */ + SizeWindow((WindowRef) destPort, + (short) width, (short) height, false); + TkMacInvalidateWindow(macWin, TK_WINDOW_ONLY); + TkMacInvalClipRgns(macWin->winPtr); + } else { + int deltaX, deltaY; + + /* + * Find the Parent window - + * For an embedded window this will be its container. + */ TkWindow *contWinPtr; contWinPtr = TkpGetOtherWindow(macWin->winPtr); - if (contWinPtr == NULL) { - panic("XMoveResizeWindow could not find container"); - } - macParent = contWinPtr->privatePtr; - /* - * NOTE: Here we should handle out of process embedding. - */ - - } else { - macParent = macWin->winPtr->parentPtr->privatePtr; - if (macParent == NULL) { - return; /* TODO: Probably should be a panic */ + if (contWinPtr != NULL) { + MacDrawable *macParent = contWinPtr->privatePtr; + + TkMacInvalClipRgns(macParent->winPtr); + TkMacInvalidateWindow(macWin, TK_PARENT_WINDOW); + + deltaX = macParent->xOff + + macWin->winPtr->changes.x - macWin->xOff; + deltaY = macParent->yOff + + macWin->winPtr->changes.y - macWin->yOff; + + UpdateOffsets(macWin->winPtr, deltaX, deltaY); + } else { + /* + * This is the case where we are embedded in + * another app. At this point, we are assuming that + * the changes.x,y is not maintained, if you need + * the info get it from Tk_GetRootCoords, + * and that the toplevel sits at 0,0 when it is drawn. + */ + + TkMacInvalidateWindow(macWin, TK_PARENT_WINDOW); + UpdateOffsets(macWin->winPtr, 0, 0); } + + } + } else { + /* TODO: update all xOff & yOffs */ + int deltaX, deltaY, parentBorderwidth; + MacDrawable *macParent = macWin->winPtr->parentPtr->privatePtr; + + if (macParent == NULL) { + return; /* TODO: Probably should be a panic */ } - TkMacInvalClipRgns(macParent->winPtr); + TkMacInvalClipRgns(macParent->winPtr); TkMacInvalidateWindow(macWin, TK_PARENT_WINDOW); deltaX = - macWin->xOff; deltaY = - macWin->yOff; - /* - * If macWin->winPtr is an embedded window, don't offset by its - * parent's borderwidth... - */ - - if (!Tk_IsEmbedded(macWin->winPtr)) { - parentBorderwidth = macWin->winPtr->parentPtr->changes.border_width; - } else { - parentBorderwidth = 0; - } + parentBorderwidth = macWin->winPtr->parentPtr->changes.border_width; + deltaX += macParent->xOff + parentBorderwidth + macWin->winPtr->changes.x; deltaY += macParent->yOff + parentBorderwidth + macWin->winPtr->changes.y; - + UpdateOffsets(macWin->winPtr, deltaX, deltaY); } } @@ -744,6 +753,9 @@ TkMacUpdateClipRgn( TkMacUpdateClipRgn(contWinPtr); SectRgn(rgn, contWinPtr->privatePtr->aboveClipRgn, rgn); + } else if (gMacEmbedHandler != NULL) { + gMacEmbedHandler->getClipProc((Tk_Window) winPtr, tmpRgn); + SectRgn(rgn, tmpRgn, rgn); } /* @@ -883,6 +895,7 @@ TkMacGetDrawablePort( Drawable drawable) { MacDrawable *macWin = (MacDrawable *) drawable; + GWorldPtr resultPort = NULL; if (macWin == NULL) { return NULL; @@ -917,18 +930,27 @@ TkMacGetDrawablePort( contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr); if (contWinPtr != NULL) { - return TkMacGetDrawablePort((Drawable) contWinPtr->privatePtr); + resultPort = TkMacGetDrawablePort( + (Drawable) contWinPtr->privatePtr); + } else if (gMacEmbedHandler != NULL) { + resultPort = gMacEmbedHandler->getPortProc( + (Tk_Window) macWin->winPtr); + if (resultPort == NULL) { + panic("Embed Handler couldn't find port"); + return NULL; + } } else { - panic("TkMacGetDrawablePort couldn't find container"); - return NULL; - } + panic("TkMacGetDrawablePort couldn't find container"); + return NULL; - /* - * NOTE: Here we should handle out of process embedding. - */ + /* + * NOTE: Here we should handle out of process embedding. + */ + } + } - + return resultPort; } /* diff --git a/mac/tkMacTest.c b/mac/tkMacTest.c index 46a7bb1..b1b9db0 100644 --- a/mac/tkMacTest.c +++ b/mac/tkMacTest.c @@ -9,10 +9,11 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacTest.c 1.2 96/12/15 14:34:00 + * SCCS: @(#) tkMacTest.c 1.3 97/09/23 16:25:54 */ #include <Types.h> +#include <tcl.h> /* * Forward declarations of procedures defined later in this file: diff --git a/mac/tkMacWindowMgr.c b/mac/tkMacWindowMgr.c index 7c8206c..e04abd6 100644 --- a/mac/tkMacWindowMgr.c +++ b/mac/tkMacWindowMgr.c @@ -3,12 +3,12 @@ * * Implements common window manager functions for the Macintosh. * - * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * Copyright (c) 1995-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. * - * SCCS: @(#) tkMacWindowMgr.c 1.59 97/11/20 18:56:39 + * SCCS: @(#) tkMacWindowMgr.c 1.62 98/01/16 10:42:51 */ #include <Events.h> @@ -63,13 +63,14 @@ static int GenerateActivateEvents _ANSI_ARGS_((EventRecord *eventPtr, static int GenerateFocusEvent _ANSI_ARGS_((EventRecord *eventPtr, Window window)); static int GenerateKeyEvent _ANSI_ARGS_((EventRecord *eventPtr, - Window window)); + Window window, UInt32 savedCode)); static int GenerateUpdateEvent _ANSI_ARGS_((EventRecord *eventPtr, Window window)); static void GenerateUpdates _ANSI_ARGS_((RgnHandle updateRgn, TkWindow *winPtr)); static int GeneratePollingEvents _ANSI_ARGS_((void)); -static int GeneratePollingEvents2 _ANSI_ARGS_((Window window)); +static int GeneratePollingEvents2 _ANSI_ARGS_((Window window, + int adjustCursor)); static OSErr TellWindowDefProcToCalcRegions _ANSI_ARGS_((WindowRef wRef)); static int WindowManagerMouse _ANSI_ARGS_((EventRecord *theEvent, Window window)); @@ -678,12 +679,18 @@ GenerateFocusEvent( static int GenerateKeyEvent( EventRecord *eventPtr, /* Incoming Mac event */ - Window window) /* Root X window for event. */ + Window window, /* Root X window for event. */ + UInt32 savedKeyCode) /* If non-zero, this is a lead byte which + * should be combined with the character + * in this event to form one multi-byte + * character. */ { Point where; Tk_Window tkwin; XEvent event; - + unsigned char byte; + char buf[16]; + /* * The focus must be in the FrontWindow on the Macintosh. * We then query Tk to determine the exact Tk window @@ -695,6 +702,17 @@ GenerateKeyEvent( if (tkwin == NULL) { return false; } + byte = (unsigned char) (eventPtr->message & charCodeMask); + if ((savedKeyCode == 0) && + (Tcl_ExternalToUtf(NULL, NULL, (char *) &byte, 1, 0, NULL, + buf, sizeof(buf), NULL, NULL, NULL) != TCL_OK)) { + /* + * This event specifies a lead byte. Wait for the second byte + * to come in before sending the XEvent. + */ + + return false; + } where.v = eventPtr->where.v; where.h = eventPtr->where.h; @@ -709,7 +727,10 @@ GenerateKeyEvent( GlobalToLocal(&where); Tk_TopCoordsToWindow(tkwin, where.h, where.v, &event.xkey.x, &event.xkey.y); - event.xkey.keycode = eventPtr->message; + + event.xkey.keycode = byte | + ((savedKeyCode & charCodeMask) << 8) | + ((eventPtr->message & keyCodeMask) << 8); event.xany.serial = Tk_Display(tkwin)->request; event.xkey.window = Tk_WindowId(tkwin); @@ -810,7 +831,7 @@ GeneratePollingEvents() } Tk_UpdatePointer(tkwin, whereGlobal.h, whereGlobal.v, TkMacButtonKeyState()); - + /* * Finally, we make sure the proper cursor is installed. The installation * is polled to 1) make our resize hack work, and 2) make sure we have the @@ -849,7 +870,8 @@ GeneratePollingEvents() static int GeneratePollingEvents2( - Window window) + Window window, + int adjustCursor) { Tk_Window tkwin, rootwin; WindowRef whichwindow, frontWin; @@ -889,6 +911,7 @@ GeneratePollingEvents2( } } + /* * The following call will generate the appropiate X events and * adjust any state that Tk must remember. @@ -899,15 +922,17 @@ GeneratePollingEvents2( } Tk_UpdatePointer(tkwin, whereGlobal.h, whereGlobal.v, TkMacButtonKeyState()); - + /* * Finally, we make sure the proper cursor is installed. The installation * is polled to 1) make our resize hack work, and 2) make sure we have the * proper cursor even if someone else changed the cursor out from under * us. */ - TkMacInstallCursor(0); - + + if (adjustCursor) { + TkMacInstallCursor(0); + } return true; } @@ -1105,6 +1130,7 @@ TkMacConvertEvent( WindowRef whichWindow; Window window; int eventFound = false; + static UInt32 savedKeyCode; switch (eventPtr->what) { case nullEvent: @@ -1148,11 +1174,28 @@ TkMacConvertEvent( break; } } + /* fall through */ + case keyUp: whichWindow = FrontWindow(); + if (whichWindow == NULL) { + /* + * This happens if we get a key event before Tk has had a + * chance to actually create and realize ".", if they type + * when "." is withdrawn(!), or between the time "." is + * destroyed and the app exits. + */ + + return false; + } window = TkMacGetXWindow(whichWindow); - eventFound |= GenerateKeyEvent(eventPtr, window); + if (GenerateKeyEvent(eventPtr, window, savedKeyCode) == 0) { + savedKeyCode = eventPtr->message; + return false; + } + eventFound = true; break; + case activateEvt: window = TkMacGetXWindow((WindowRef) eventPtr->message); eventFound |= GenerateActivateEvents(eventPtr, window); @@ -1205,6 +1248,7 @@ TkMacConvertEvent( break; } + savedKeyCode = 0; return eventFound; } @@ -1214,7 +1258,7 @@ TkMacConvertEvent( * TkMacConvertTkEvent -- * * This function converts a Macintosh event into zero or more - * Tcl events. + * Tcl events. It is intended for use in Netscape-style embedding. * * Results: * Returns 1 if event added to Tcl queue, 0 otherwse. @@ -1232,15 +1276,36 @@ TkMacConvertTkEvent( { int eventFound = false; Point where; + static UInt32 savedKeyCode; + + /* + * By default, assume it is legal for us to set the cursor + */ + + Tk_MacTkOwnsCursor(1); switch (eventPtr->what) { case nullEvent: + /* + * We get NULL events only when the cursor is NOT over + * the plugin. Otherwise we get updateCursor events. + * We will not generate polling events or move the cursor + * in this case. + */ + + eventFound = false; + break; case adjustCursorEvent: - if (GeneratePollingEvents2(window)) { + if (GeneratePollingEvents2(window, 1)) { eventFound = true; } break; case updateEvt: + /* + * It is possibly not legal for us to set the cursor + */ + + Tk_MacTkOwnsCursor(0); if (GenerateUpdateEvent(eventPtr, window)) { eventFound = true; } @@ -1267,10 +1332,24 @@ TkMacConvertTkEvent( break; } } + /* fall through. */ + case keyUp: - eventFound |= GenerateKeyEvent(eventPtr, window); + if (GenerateKeyEvent(eventPtr, window, savedKeyCode) == 0) { + savedKeyCode = eventPtr->message; + return false; + } + eventFound = true; break; + case activateEvt: + /* + * It is probably not legal for us to set the cursor + * here, since we don't know where the mouse is in the + * window that is being activated. + */ + + Tk_MacTkOwnsCursor(0); eventFound |= GenerateActivateEvents(eventPtr, window); eventFound |= GenerateFocusEvent(eventPtr, window); break; @@ -1291,10 +1370,18 @@ TkMacConvertTkEvent( * Do clipboard conversion. */ switch ((eventPtr->message & osEvtMessageMask) >> 24) { + /* + * It is possibly not legal for us to set the cursor. + * Netscape sends us these events all the time... + */ + + Tk_MacTkOwnsCursor(0); + case mouseMovedMessage: - if (GeneratePollingEvents2(window)) { + /* if (GeneratePollingEvents2(window, 0)) { eventFound = true; - } + } NEXT LINE IS TEMPORARY */ + eventFound = false; break; case suspendResumeMessage: if (!(eventPtr->message & resumeFlag)) { @@ -1318,7 +1405,7 @@ TkMacConvertTkEvent( } break; } - + savedKeyCode = 0; return eventFound; } @@ -1516,7 +1603,6 @@ TellWindowDefProcToCalcRegions( * Assuming there are no errors we now call the window definition * procedure to tell it to calculate the regions for the window. */ - if (err == noErr) { (void) CallWindowDefProc((UniversalProcPtr) *wdef, GetWVariant(wRef), wRef, wCalcRgns, 0); diff --git a/mac/tkMacWm.c b/mac/tkMacWm.c index 56c4b8a..4cd7920 100644 --- a/mac/tkMacWm.c +++ b/mac/tkMacWm.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacWm.c 1.72 97/10/29 13:27:30 + * SCCS: @(#) tkMacWm.c 1.77 98/02/18 11:03:54 */ #include <Gestalt.h> @@ -19,6 +19,7 @@ #include <Windows.h> #include <ToolUtils.h> +#include <tclMac.h> #include "tkPort.h" #include "tkInt.h" #include "tkMacInt.h" @@ -26,14 +27,12 @@ #include "tkScrollbar.h" /* - * If HAVE_APPEARANCE is defined in MW_TkHeader.pch then we must have the - * Appearance manager header & library. If so we can use these new API's to - * have the iconify code do the right thing. + * We now require the Appearance headers. They come with CodeWarrior Pro, + * and are on the SDK CD. However, we do not require the Appearance + * extension */ - -#ifdef HAVE_APPEARANCE -# include <Appearance.h> -#endif + +#include <Appearance.h> /* * A data structure of the following type holds information for @@ -313,7 +312,6 @@ void MacMoveWindow(WindowRef window, int x, int y); * Forward declarations for procedures defined in this file: */ -static int HaveAppearance _ANSI_ARGS_((void)); static void InitialWindowBounds _ANSI_ARGS_((TkWindow *winPtr, Rect *geometry)); static int ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp, @@ -532,7 +530,7 @@ TkWmMapWindow( */ XMapWindow(winPtr->display, winPtr->window); - + /* * Now that the window is visable we can determine the offset * from the window's content orgin to the window's decorative @@ -711,7 +709,7 @@ Tk_WmCmd( return TCL_ERROR; } if (argc == 2) { - interp->result = (wmTracing) ? "on" : "off"; + Tcl_SetResult(interp, ((wmTracing) ? "on" : "off"), TCL_STATIC); return TCL_OK; } return Tcl_GetBoolean(interp, argv[2], &wmTracing); @@ -741,9 +739,12 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->sizeHintsFlags & PAspect) { - sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x, + char buf[TCL_INTEGER_SPACE * 4]; + + sprintf(buf, "%d %d %d %d", wmPtr->minAspect.x, wmPtr->minAspect.y, wmPtr->maxAspect.x, wmPtr->maxAspect.y); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_OK; } @@ -758,7 +759,8 @@ Tk_WmCmd( } if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) || (denom2 <= 0)) { - interp->result = "aspect number can't be <= 0"; + Tcl_SetResult(interp, "aspect number can't be <= 0", + TCL_STATIC); return TCL_ERROR; } wmPtr->minAspect.x = numer1; @@ -779,7 +781,7 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->clientMachine != NULL) { - interp->result = wmPtr->clientMachine; + Tcl_SetResult(interp, wmPtr->clientMachine, TCL_STATIC); } return TCL_OK; } @@ -877,8 +879,9 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->cmdArgv != NULL) { - interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv); - interp->freeProc = (Tcl_FreeProc *) free; + Tcl_SetResult(interp, + Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv), + TCL_DYNAMIC); } return TCL_OK; } @@ -928,7 +931,8 @@ Tk_WmCmd( return TCL_ERROR; } if (argc == 3) { - interp->result = wmPtr->hints.input ? "passive" : "active"; + Tcl_SetResult(interp, (wmPtr->hints.input ? "passive" : "active"), + TCL_STATIC); return TCL_OK; } c = argv[3][0]; @@ -945,6 +949,7 @@ Tk_WmCmd( } else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0) && (length >= 2)) { Window window; + char buf[TCL_INTEGER_SPACE]; if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: must be \"", @@ -955,7 +960,8 @@ Tk_WmCmd( if (window == None) { window = Tk_WindowId((Tk_Window) winPtr); } - sprintf(interp->result, "0x%x", (unsigned int) window); + sprintf(buf, "0x%x", (unsigned int) window); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0) && (length >= 2)) { char xSign, ySign; @@ -968,6 +974,8 @@ Tk_WmCmd( return TCL_ERROR; } if (argc == 3) { + char buf[16 + TCL_INTEGER_SPACE * 4]; + xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+'; ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+'; if (wmPtr->gridWin != NULL) { @@ -979,8 +987,9 @@ Tk_WmCmd( width = winPtr->changes.width; height = winPtr->changes.height; } - sprintf(interp->result, "%dx%d%c%d%c%d", width, height, - xSign, wmPtr->x, ySign, wmPtr->y); + sprintf(buf, "%dx%d%c%d%c%d", width, height, xSign, wmPtr->x, + ySign, wmPtr->y); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if (*argv[3] == '\0') { @@ -1001,9 +1010,12 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->sizeHintsFlags & PBaseSize) { - sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth, + char buf[TCL_INTEGER_SPACE * 4]; + + sprintf(buf, "%d %d %d %d", wmPtr->reqGridWidth, wmPtr->reqGridHeight, wmPtr->widthInc, wmPtr->heightInc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_OK; } @@ -1030,19 +1042,19 @@ Tk_WmCmd( return TCL_ERROR; } if (reqWidth < 0) { - interp->result = "baseWidth can't be < 0"; + Tcl_SetResult(interp, "baseWidth can't be < 0", TCL_STATIC); return TCL_ERROR; } if (reqHeight < 0) { - interp->result = "baseHeight can't be < 0"; + Tcl_SetResult(interp, "baseHeight can't be < 0", TCL_STATIC); return TCL_ERROR; } if (widthInc < 0) { - interp->result = "widthInc can't be < 0"; + Tcl_SetResult(interp, "widthInc can't be < 0", TCL_STATIC); return TCL_ERROR; } if (heightInc < 0) { - interp->result = "heightInc can't be < 0"; + Tcl_SetResult(interp, "heightInc can't be < 0", TCL_STATIC); return TCL_ERROR; } Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc, @@ -1062,7 +1074,7 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->hints.flags & WindowGroupHint) { - interp->result = wmPtr->leaderName; + Tcl_SetResult(interp, wmPtr->leaderName, TCL_STATIC); } return TCL_OK; } @@ -1095,8 +1107,9 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->hints.flags & IconPixmapHint) { - interp->result = Tk_NameOfBitmap(winPtr->display, - wmPtr->hints.icon_pixmap); + Tcl_SetResult(interp, + Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_pixmap), + TCL_STATIC); } return TCL_OK; } @@ -1155,8 +1168,9 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->hints.flags & IconMaskHint) { - interp->result = Tk_NameOfBitmap(winPtr->display, - wmPtr->hints.icon_mask); + Tcl_SetResult(interp, + Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_mask), + TCL_STATIC); } return TCL_OK; } @@ -1181,7 +1195,9 @@ Tk_WmCmd( return TCL_ERROR; } if (argc == 3) { - interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : ""; + Tcl_SetResult(interp, + ((wmPtr->iconName != NULL) ? wmPtr->iconName : ""), + TCL_STATIC); return TCL_OK; } else { wmPtr->iconName = Tk_GetUid(argv[3]); @@ -1201,8 +1217,11 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->hints.flags & IconPositionHint) { - sprintf(interp->result, "%d %d", wmPtr->hints.icon_x, + char buf[TCL_INTEGER_SPACE * 2]; + + sprintf(buf, "%d %d", wmPtr->hints.icon_x, wmPtr->hints.icon_y); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_OK; } @@ -1230,7 +1249,7 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->icon != NULL) { - interp->result = Tk_PathName(wmPtr->icon); + Tcl_SetResult(interp, Tk_PathName(wmPtr->icon), TCL_STATIC); } return TCL_OK; } @@ -1284,8 +1303,10 @@ Tk_WmCmd( return TCL_ERROR; } if (argc == 3) { - sprintf(interp->result, "%d %d", wmPtr->maxWidth, - wmPtr->maxHeight); + char buf[TCL_INTEGER_SPACE * 2]; + + sprintf(buf, "%d %d", wmPtr->maxWidth, wmPtr->maxHeight); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK) @@ -1305,8 +1326,10 @@ Tk_WmCmd( return TCL_ERROR; } if (argc == 3) { - sprintf(interp->result, "%d %d", wmPtr->minWidth, - wmPtr->minHeight); + char buf[TCL_INTEGER_SPACE * 2]; + + sprintf(buf, "%d %d", wmPtr->minWidth, wmPtr->minHeight); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK) @@ -1330,9 +1353,9 @@ Tk_WmCmd( } if (argc == 3) { if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) { - interp->result = "1"; + Tcl_SetResult(interp, "1", TCL_STATIC); } else { - interp->result = "0"; + Tcl_SetResult(interp, "0", TCL_STATIC); } return TCL_OK; } @@ -1353,9 +1376,9 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->sizeHintsFlags & USPosition) { - interp->result = "user"; + Tcl_SetResult(interp, "user", TCL_STATIC); } else if (wmPtr->sizeHintsFlags & PPosition) { - interp->result = "program"; + Tcl_SetResult(interp, "program", TCL_STATIC); } return TCL_OK; } @@ -1410,7 +1433,7 @@ Tk_WmCmd( for (protPtr = wmPtr->protPtr; protPtr != NULL; protPtr = protPtr->nextPtr) { if (protPtr->protocol == protocol) { - interp->result = protPtr->command; + Tcl_SetResult(interp, protPtr->command, TCL_STATIC); return TCL_OK; } } @@ -1454,9 +1477,12 @@ Tk_WmCmd( return TCL_ERROR; } if (argc == 3) { - sprintf(interp->result, "%d %d", + char buf[TCL_INTEGER_SPACE * 2]; + + sprintf(buf, "%d %d", (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1, (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK) @@ -1489,9 +1515,9 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->sizeHintsFlags & USSize) { - interp->result = "user"; + Tcl_SetResult(interp, "user", TCL_STATIC); } else if (wmPtr->sizeHintsFlags & PSize) { - interp->result = "program"; + Tcl_SetResult(interp, "program", TCL_STATIC); } return TCL_OK; } @@ -1523,20 +1549,20 @@ Tk_WmCmd( return TCL_ERROR; } if (wmPtr->iconFor != NULL) { - interp->result = "icon"; + Tcl_SetResult(interp, "icon", TCL_STATIC); } else { switch (wmPtr->hints.initial_state) { case NormalState: - interp->result = "normal"; + Tcl_SetResult(interp, "normal", TCL_STATIC); break; case IconicState: - interp->result = "iconic"; + Tcl_SetResult(interp, "iconic", TCL_STATIC); break; case WithdrawnState: - interp->result = "withdrawn"; + Tcl_SetResult(interp, "withdrawn", TCL_STATIC); break; case ZoomState: - interp->result = "zoomed"; + Tcl_SetResult(interp, "zoomed", TCL_STATIC); break; } } @@ -1548,8 +1574,9 @@ Tk_WmCmd( return TCL_ERROR; } if (argc == 3) { - interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid - : winPtr->nameUid; + Tcl_SetResult(interp, + ((wmPtr->titleUid != NULL) ? wmPtr->titleUid : winPtr->nameUid), + TCL_STATIC); return TCL_OK; } else { wmPtr->titleUid = Tk_GetUid(argv[3]); @@ -1568,7 +1595,7 @@ Tk_WmCmd( } if (argc == 3) { if (wmPtr->master != None) { - interp->result = wmPtr->masterWindowName; + Tcl_SetResult(interp, wmPtr->masterWindowName, TCL_STATIC); } return TCL_OK; } @@ -2148,7 +2175,7 @@ UpdateSizeHints( * * Results: * A standard Tcl return value, plus an error message in - * interp->result if an error occurs. + * the interp's result if an error occurs. * * Side effects: * The size and/or location of winPtr may change. @@ -2333,12 +2360,26 @@ Tk_GetRootCoords( y += winPtr->changes.y + winPtr->changes.border_width; } else { + Point theOffset; - /* - * NOTE: Here we should handle - * out of process embedding. - */ - + if (gMacEmbedHandler->getOffsetProc != NULL) { + /* + * We do not require that the changes.x & changes.y for + * a non-Tk master window be kept up to date. So we + * first subtract off the possibly bogus values that have + * been added on at the top of this pass through the loop, + * and then call out to the getOffsetProc to give us + * the correct offset. + */ + + x -= winPtr->changes.x + winPtr->changes.border_width; + y -= winPtr->changes.y + winPtr->changes.border_width; + + gMacEmbedHandler->getOffsetProc((Tk_Window) winPtr, &theOffset); + + x += theOffset.h; + y += theOffset.v; + } break; } } @@ -3318,15 +3359,19 @@ TkSetWMName( { Str255 pTitle; GWorldPtr macWin; + int destWrote; if (Tk_IsEmbedded(winPtr)) { return; } + Tcl_UtfToExternal(NULL, NULL, titleUid, + strlen(titleUid), 0, NULL, + (char *) &pTitle[1], + 255, NULL, &destWrote, NULL); /* Internalize native */ + pTitle[0] = destWrote; - macWin = TkMacGetDrawablePort(winPtr->window); - - strcpy((char *) pTitle + 1, titleUid); - pTitle[0] = strlen(titleUid); + macWin = TkMacGetDrawablePort(winPtr->window); + SetWTitle((WindowPtr) macWin, pTitle); } @@ -3685,42 +3730,42 @@ TkUnsupported1Cmd( switch (wmPtr->style) { case noGrowDocProc: case documentProc: - interp->result = "documentProc"; + Tcl_SetResult(interp, "documentProc", TCL_STATIC); break; case dBoxProc: - interp->result = "dBoxProc"; + Tcl_SetResult(interp, "dBoxProc", TCL_STATIC); break; case plainDBox: - interp->result = "plainDBox"; + Tcl_SetResult(interp, "plainDBox", TCL_STATIC); break; case altDBoxProc: - interp->result = "altDBoxProc"; + Tcl_SetResult(interp, "altDBoxProc", TCL_STATIC); break; case movableDBoxProc: - interp->result = "movableDBoxProc"; + Tcl_SetResult(interp, "movableDBoxProc", TCL_STATIC); break; case zoomDocProc: case zoomNoGrow: - interp->result = "zoomDocProc"; + Tcl_SetResult(interp, "zoomDocProc", TCL_STATIC); break; case rDocProc: - interp->result = "rDocProc"; + Tcl_SetResult(interp, "rDocProc", TCL_STATIC); break; case floatProc: case floatGrowProc: - interp->result = "floatProc"; + Tcl_SetResult(interp, "floatProc", TCL_STATIC); break; case floatZoomProc: case floatZoomGrowProc: - interp->result = "floatZoomProc"; + Tcl_SetResult(interp, "floatZoomProc", TCL_STATIC); break; case floatSideProc: case floatSideGrowProc: - interp->result = "floatSideProc"; + Tcl_SetResult(interp, "floatSideProc", TCL_STATIC); break; case floatSideZoomProc: case floatSideZoomGrowProc: - interp->result = "floatSideZoomProc"; + Tcl_SetResult(interp, "floatSideZoomProc", TCL_STATIC); break; default: panic("invalid style"); @@ -3861,6 +3906,13 @@ TkMacMakeRealWindowExist( TkMacMakeRealWindowExist(contWinPtr->privatePtr->toplevel->winPtr); macWin->flags |= TK_HOST_EXISTS; return; + } else if (gMacEmbedHandler != NULL) { + if (gMacEmbedHandler->containerExistProc != NULL) { + if (gMacEmbedHandler->containerExistProc((Tk_Window) winPtr) != TCL_OK) { + panic("ContainerExistProc could not make container"); + } + } + return; } else { panic("TkMacMakeRealWindowExist could not find container"); } @@ -4148,8 +4200,7 @@ TkpWmSetState(winPtr, state) Tk_UnmapWindow((Tk_Window) winPtr); } else if (state == IconicState) { Tk_UnmapWindow((Tk_Window) winPtr); -#ifdef HAVE_APPEARANCE - if (HaveAppearance()) { + if (TkMacHaveAppearance()) { /* * The window always gets unmapped. However, if we can show the * icon version of the window (collapsed) we make the window visable @@ -4163,14 +4214,11 @@ TkpWmSetState(winPtr, state) CollapseWindow((WindowPtr) macWin, true); } } -#endif } else if (state == NormalState) { Tk_MapWindow((Tk_Window) winPtr); -#ifdef HAVE_APPEARANCE - if (HaveAppearance()) { + if (TkMacHaveAppearance()) { CollapseWindow((WindowPtr) macWin, false); } -#endif } else if (state == ZoomState) { /* TODO: need to support zoomed windows */ } @@ -4178,7 +4226,7 @@ TkpWmSetState(winPtr, state) /* *---------------------------------------------------------------------- * - * HaveAppearance -- + * TkMacHaveAppearance -- * * Determine if the appearance manager is available on this Mac. * We cache the result so future calls are fast. @@ -4192,22 +4240,20 @@ TkpWmSetState(winPtr, state) *---------------------------------------------------------------------- */ -static int -HaveAppearance() +int +TkMacHaveAppearance() { static initialized = false; - static int haveAppearance = false; + static int TkMacHaveAppearance = false; long response = 0; OSErr err = noErr; -#ifdef HAVE_APPEARANCE if (!initialized) { err = Gestalt(gestaltAppearanceAttr, &response); if (err == noErr) { - haveAppearance = true; + TkMacHaveAppearance = true; } } -#endif - return haveAppearance; + return TkMacHaveAppearance; } diff --git a/mac/tkMacXStubs.c b/mac/tkMacXStubs.c index f1042c2..4f52e41 100644 --- a/mac/tkMacXStubs.c +++ b/mac/tkMacXStubs.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacXStubs.c 1.87 97/11/20 18:35:29 + * SCCS: @(#) tkMacXStubs.c 1.89 97/11/26 13:10:52 */ #include "tkInt.h" @@ -46,7 +46,7 @@ */ static TkDisplay *gMacDisplay = NULL; /* Macintosh display. */ -static char *macScreenName = "Macintosh:0"; +static char *macScreenName = ":0"; /* Default name of macintosh display. */ /* @@ -541,7 +541,8 @@ TkGetServerInfo( Tk_Window tkwin) /* Token for window; this selects a * particular display and server. */ { - char buffer[50], buffer2[50]; + char buffer[8 + TCL_INTEGER_SPACE * 2]; + char buffer2[TCL_INTEGER_SPACE]; sprintf(buffer, "X%dR%d ", ProtocolVersion(Tk_Display(tkwin)), ProtocolRevision(Tk_Display(tkwin))); |