summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXInit.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/tkMacOSXInit.c')
-rw-r--r--macosx/tkMacOSXInit.c216
1 files changed, 189 insertions, 27 deletions
diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c
index 5f415c8..f99124b 100644
--- a/macosx/tkMacOSXInit.c
+++ b/macosx/tkMacOSXInit.c
@@ -1,7 +1,7 @@
/*
- * tkUnixInit.c --
+ * tkMacOSXInit.c --
*
- * This file contains Unix-specific interpreter initialization
+ * This file contains Mac OS X -specific interpreter initialization
* functions.
*
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
@@ -10,11 +10,14 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkMacOSXInit.c,v 1.3.2.2 2004/07/25 01:57:41 wolfsuit Exp $
+ * RCS: @(#) $Id: tkMacOSXInit.c,v 1.3.2.3 2004/11/11 01:26:43 das Exp $
*/
#include "tkInt.h"
#include "tkMacOSXInt.h"
+#include "tclInt.h"
+#include <sys/stat.h>
+#include <mach-o/dyld.h>
/*
* The Init script (common to Windows and Unix platforms) is
@@ -23,6 +26,15 @@
#include "tkInitScript.h"
/*
+ * Define the following to 0 to not attempt to use an undocumented SPI
+ * to notify the window server that an unbundled executable is a full
+ * GUI application after loading Tk.
+ */
+#ifndef MAC_OSX_TK_USE_CPS_SPI
+#define MAC_OSX_TK_USE_CPS_SPI 1
+#endif
+
+/*
* The following structures are used to map the script/language codes of a
* font to the name that should be passed to Tcl_GetEncoding() to obtain
* the encoding for that font. The set of numeric constants is fixed and
@@ -72,6 +84,11 @@ static Map scriptMap[] = {
Tcl_Encoding TkMacOSXCarbonEncoding = NULL;
+/*
+ * If the App is in an App package, then we want to add the Scripts
+ * directory to the auto_path.
+ */
+static char scriptPath[PATH_MAX + 1] = "";
/*
*----------------------------------------------------------------------
@@ -95,30 +112,27 @@ int
TkpInit(interp)
Tcl_Interp *interp;
{
- char tkLibPath[1024];
- int result;
- static int menusInitialized = false;
- static int carbonEncodingInitialized = false;
+ static char tkLibPath[PATH_MAX + 1];
+ static int tkMacOSXInitialized = false;
/*
* Since it is possible for TkInit to be called multiple times
- * and we don't want to do the menu initialization multiple times
+ * and we don't want to do the initialization multiple times
* we protect against doing it more than once.
*/
- if (menusInitialized == false) {
- menusInitialized = true;
+ if (tkMacOSXInitialized == false) {
+ CFStringEncoding encoding;
+ char *encodingStr = NULL;
+ int i;
+
+ tkMacOSXInitialized = true;
+
Tk_MacOSXSetupTkNotifier();
TkMacOSXInitAppleEvents(interp);
TkMacOSXInitMenus(interp);
TkMacOSXUseAntialiasedText(interp, TRUE);
TkMacOSXInitCGDrawing(interp, TRUE, 3);
- }
-
- if (carbonEncodingInitialized == false) {
- CFStringEncoding encoding;
- char *encodingStr = NULL;
- int i;
encoding = CFStringGetSystemEncoding();
@@ -136,20 +150,112 @@ TkpInit(interp)
if (TkMacOSXCarbonEncoding == NULL) {
TkMacOSXCarbonEncoding = Tcl_GetEncoding (NULL, NULL);
}
- }
+
+ /*
+ * When Tk is in a framework, force tcl_findLibrary to look in the
+ * framework scripts directory.
+ * FIXME: Should we come up with a more generic way of doing this?
+ */
+
+ Tcl_MacOSXOpenVersionedBundleResources(interp,
+ "com.tcltk.tklibrary", TK_VERSION, 1, 1024, tkLibPath);
+
+ /*
+ * If we don't have a TTY and stdin is a special character file of length 0,
+ * (e.g. /dev/null, which is what Finder sets when double clicking Wish)
+ * then use the Tk based console interpreter.
+ */
- /*
- * When Tk is in a framework, force tcl_findLibrary to look in the
- * framework scripts directory.
- * FIXME: Should we come up with a more generic way of doing this?
- */
-
- result = Tcl_MacOSXOpenVersionedBundleResources(interp,
- "com.tcltk.tklibrary", TK_VERSION, 1, 1024, tkLibPath);
-
- if (result != TCL_ERROR) {
+ if (!isatty(0)) {
+ struct stat st;
+ if (fstat(0, &st) || (S_ISCHR(st.st_mode) && st.st_blocks == 0)) {
+ Tk_InitConsoleChannels(interp);
+ Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDIN));
+ Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDOUT));
+ Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDERR));
+ if (Tk_CreateConsoleWindow(interp) == TCL_OK) {
+ /* Only show the console if we don't have a startup script */
+ if (TclGetStartupScriptPath() == NULL) {
+ Tcl_Eval(interp, "console show");
+ }
+ }
+ }
+ }
+#if MAC_OSX_TK_USE_CPS_SPI
+ /*
+ * If we are loaded into an executable that is not a bundled application,
+ * the window server does not let us come to the foreground.
+ * For such an executable, we attempt to use an undocumented SPI to
+ * notify the window server that we are now a full GUI application.
+ */
+ {
+ /* Check whether we are a bundled executable: */
+ int bundledExecutable = 0;
+ CFBundleRef bundleRef = CFBundleGetMainBundle();
+ CFURLRef bundleUrl = NULL;
+ if (bundleRef) {
+ bundleUrl = CFBundleCopyBundleURL(bundleRef);
+ }
+ if (bundleUrl) {
+ /*
+ * A bundled executable is two levels down from its main bundle
+ * directory (e.g. Wish.app/Contents/MacOS/Wish), whereas
+ * an unbundled executable's main bundle directory is just
+ * the directory containing the executable.
+ * So to check whether we are bundled, we delete the last three
+ * path components of the executable's url and compare the
+ * resulting url with the main bundle url.
+ */
+ int j = 3;
+ CFURLRef url = CFBundleCopyExecutableURL(bundleRef);
+ while (url && j--) {
+ CFURLRef parent = CFURLCreateCopyDeletingLastPathComponent(NULL, url);
+ CFRelease(url);
+ url = parent;
+ }
+ if (url) {
+ bundledExecutable = CFEqual(bundleUrl, url);
+ CFRelease(url);
+ }
+ CFRelease(bundleUrl);
+ }
+
+ /* If we are not a bundled executable, attempt to use the CPS SPI: */
+ if (!bundledExecutable) {
+ /*
+ * Load the CPS SPI symbol dynamically, so that we don't break
+ * if it every disappears or changes its name.
+ */
+ OSErr (*cpsEnableForegroundOperation)(ProcessSerialNumberPtr) = NULL;
+ NSSymbol nsSymbol;
+ if(NSIsSymbolNameDefinedWithHint(
+ "_CPSEnableForegroundOperation", "CoreGraphics")) {
+ nsSymbol = NSLookupAndBindSymbolWithHint(
+ "_CPSEnableForegroundOperation", "CoreGraphics");
+ if(nsSymbol) {
+ cpsEnableForegroundOperation = NSAddressOfSymbol(nsSymbol);
+ }
+ }
+ if (cpsEnableForegroundOperation) {
+ ProcessSerialNumber psn = { 0, kCurrentProcess };
+ /*
+ * Let the window server know that we are a foregroundable app
+ */
+ cpsEnableForegroundOperation(&psn);
+ }
+ }
+ }
+#endif /* MAC_OSX_TK_USE_CPS_SPI */
+ }
+
+ if (tkLibPath[0] != '\0') {
Tcl_SetVar(interp, "tk_library", tkLibPath, TCL_GLOBAL_ONLY);
}
+
+ if (scriptPath[0] != '\0') {
+ Tcl_SetVar(interp, "auto_path", scriptPath,
+ TCL_GLOBAL_ONLY|TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
+ }
return Tcl_Eval(interp, initScript);
}
@@ -221,3 +327,59 @@ TkpDisplayWarning(msg, title)
Tcl_WriteChars(errChannel, "\n", 1);
}
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXDefaultStartupScript --
+ *
+ *
+ * On MacOS X, we look for a file in the Resources/Scripts
+ * directory called AppMain.tcl and if found, we set argv[1] to
+ * that, so that the rest of the code will find it, and add the
+ * Scripts folder to the auto_path. If we don't find the startup
+ * script, we just bag it, assuming the user is starting up some
+ * other way.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * TclSetStartupScriptFileName() called when AppMain.tcl found.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkMacOSXDefaultStartupScript(void)
+{
+ CFBundleRef bundleRef;
+
+ bundleRef = CFBundleGetMainBundle();
+
+ if (bundleRef != NULL) {
+ CFURLRef appMainURL;
+ appMainURL = CFBundleCopyResourceURL(bundleRef,
+ CFSTR("AppMain"),
+ CFSTR("tcl"),
+ CFSTR("Scripts"));
+
+ if (appMainURL != NULL) {
+ CFURLRef scriptFldrURL;
+ char startupScript[PATH_MAX + 1];
+
+ if (CFURLGetFileSystemRepresentation (appMainURL, true,
+ startupScript, PATH_MAX)) {
+ TclSetStartupScriptFileName(startupScript);
+ scriptFldrURL = CFURLCreateCopyDeletingLastPathComponent(
+ NULL, appMainURL);
+ if (scriptFldrURL != NULL) {
+ CFURLGetFileSystemRepresentation(scriptFldrURL,
+ true, scriptPath, PATH_MAX);
+ CFRelease(scriptFldrURL);
+ }
+ }
+ CFRelease(appMainURL);
+ }
+ }
+}