Attachment "tkMacOSXDialog.c" to
ticket [1156388f]
added by
bgriffin
2005-06-06 02:10:33.
/*
* tkMacOSXDialog.c --
*
* Contains the Mac implementation of the common dialog boxes.
*
* Copyright (c) 1996-1997 Sun Microsystems, Inc.
* Copyright 2001, Apple Computer, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tkMacOSXDialog.c,v 1.13 2005/05/14 20:48:14 das Exp $
*/
#include <Carbon/Carbon.h>
#include "tkPort.h"
#include "tkInt.h"
#include "tkMacOSXInt.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 tkMacOSXResource.r
*/
#define OPEN_BOX 130
#define OPEN_POPUP 131
#define OPEN_MENU 132
#define OPEN_POPUP_ITEM 10
#define SAVE_FILE 0
#define OPEN_FILE 1
#define CHOOSE_FOLDER 2
#define MATCHED 0
#define UNMATCHED 1
#define TK_DEFAULT_ABOUT 128
/*
* The following structure is used in the GetFileName() function. It stored
* information about the file dialog and the file filters.
*/
typedef struct _OpenFileData {
FileFilterList fl; /* List of file filters. */
SInt16 curType; /* The filetype currently being listed. */
short initialType; /* Type to use initially */
short popupItem; /* Item number of the popup in the dialog. */
short usePopup; /* True if we show the popup menu (this */
/* is an open operation and the */
/* -filetypes option is set). */
} OpenFileData;
/*
* The following structure is used in the tk_messageBox
* implementation.
*/
typedef struct {
WindowRef windowRef;
int buttonIndex;
} CallbackUserData;
static OSStatus AlertHandler _ANSI_ARGS_(( EventHandlerCallRef callRef,
EventRef eventRef, void *userData ));
static Boolean MatchOneType _ANSI_ARGS_((StringPtr fileNamePtr, OSType fileType,
OpenFileData *myofdPtr, FileFilter *filterPtr));
static pascal Boolean OpenFileFilterProc(AEDesc* theItem, void* info,
NavCallBackUserData callBackUD,
NavFilterModes filterMode );
pascal void OpenEventProc(NavEventCallbackMessage callBackSelector,
NavCBRecPtr callBackParms,
NavCallBackUserData callBackUD );
static void InitFileDialogs();
static int NavServicesGetFile(Tcl_Interp *interp, OpenFileData *ofd,
AEDesc *initialDescPtr,
char *initialFile, AEDescList *selectDescPtr,
CFStringRef title, CFStringRef message,
CONST char *initialType, int multiple, int isOpen);
static int HandleInitialDirectory (Tcl_Interp *interp,
char *initialFile, char *initialDir,
FSRef *dirRef,
AEDescList *selectDescPtr,
AEDesc *dirDescPtr);
/*
* Have we initialized the file dialog subsystem
*/
static int fileDlgInited = 0;
/*
* Filter and hook functions used by the tk_getOpenFile and tk_getSaveFile
* commands.
*/
NavObjectFilterUPP openFileFilterUPP;
NavEventUPP openFileEventUPP;
/*
*----------------------------------------------------------------------
*
* Tk_ChooseColorObjCmd --
*
* This procedure implements the color dialog box for the Mac
* platform. See the user documentation for details on what it
* does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
int
Tk_ChooseColorObjCmd(
ClientData clientData, /* Main window associated with interpreter. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *CONST objv[]) /* Argument objects. */
{
Tk_Window parent;
char *title;
int i, picked, srcRead, dstWrote;
ColorPickerInfo cpinfo;
static int inited = 0;
static RGBColor in;
static CONST 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;
}
}
}
cpinfo.theColor.profile = 0L;
cpinfo.theColor.color.rgb.red = in.red;
cpinfo.theColor.color.rgb.green = in.green;
cpinfo.theColor.color.rgb.blue = in.blue;
cpinfo.dstProfile = 0L;
cpinfo.flags = kColorPickerCanModifyPalette
| kColorPickerCanAnimatePalette;
cpinfo.placeWhere = kDeepestColorScreen;
cpinfo.pickerType = 0L;
cpinfo.eventProc = NULL;
cpinfo.colorProc = NULL;
cpinfo.colorProcData = 0;
/* This doesn't seem to actually set the title! */
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;
}
if (picked != 0) {
char result[32];
sprintf(result, "#%02x%02x%02x", in.red >> 8, in.green >> 8,
in.blue >> 8);
Tcl_AppendResult(interp, result, NULL);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tk_GetOpenFileObjCmd --
*
* This procedure implements the "open file" dialog box for the
* Mac platform. See the user documentation for details on what
* it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See user documentation.
*----------------------------------------------------------------------
*/
int
Tk_GetOpenFileObjCmd(
ClientData clientData, /* Main window associated with interpreter. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *CONST objv[]) /* Argument objects. */
{
int i, result, multiple;
OpenFileData ofd;
Tk_Window parent;
CFStringRef message, title;
AEDesc initialDesc = {typeNull, NULL};
FSRef dirRef;
AEDesc *initialPtr = NULL;
AEDescList selectDesc = {typeNull, NULL};
char *initialFile = NULL, *initialDir = NULL;
Tcl_Obj *typeVariablePtr = NULL;
CONST char *initialtype = NULL;
static CONST char *openOptionStrings[] = {
"-defaultextension", "-filetypes",
"-initialdir", "-initialfile",
"-message", "-multiple",
"-parent", "-title",
"-typevariable", NULL
};
enum openOptions {
OPEN_DEFAULT, OPEN_FILETYPES,
OPEN_INITDIR, OPEN_INITFILE,
OPEN_MESSAGE, OPEN_MULTIPLE,
OPEN_PARENT, OPEN_TITLE,
OPEN_TYPEVARIABLE
};
if (!fileDlgInited) {
InitFileDialogs();
}
result = TCL_ERROR;
parent = (Tk_Window) clientData;
multiple = false;
title = NULL;
message = NULL;
TkInitFileFilters(&ofd.fl);
ofd.curType = 0;
ofd.initialType = -1;
ofd.popupItem = OPEN_POPUP_ITEM;
ofd.usePopup = 1;
for (i = 1; i < objc; i += 2) {
char *choice;
int index, choiceLen;
char *string;
if (Tcl_GetIndexFromObj(interp, objv[i], openOptionStrings, "option",
TCL_EXACT, &index) != TCL_OK) {
result = TCL_ERROR;
goto end;
}
if (i + 1 == objc) {
string = Tcl_GetStringFromObj(objv[i], NULL);
Tcl_AppendResult(interp, "value for \"", string, "\" missing",
(char *) NULL);
result = TCL_ERROR;
goto end;
}
switch (index) {
case OPEN_DEFAULT:
break;
case OPEN_FILETYPES:
if (TkGetFileFilters(interp, &ofd.fl, objv[i + 1], 0)
!= TCL_OK) {
result = TCL_ERROR;
goto end;
}
break;
case OPEN_TYPEVARIABLE:
typeVariablePtr = objv[i + 1];
break;
case OPEN_INITDIR:
initialDir = Tcl_GetStringFromObj(objv[i + 1], NULL);
break;
case OPEN_INITFILE:
initialFile = Tcl_GetStringFromObj(objv[i + 1], NULL);
break;
case OPEN_MESSAGE:
choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
message = CFStringCreateWithBytes(NULL, (unsigned char*) choice, choiceLen,
kCFStringEncodingUTF8, false);
break;
case OPEN_MULTIPLE:
if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &multiple)
!= TCL_OK) {
result = TCL_ERROR;
goto end;
}
break;
case OPEN_PARENT:
choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
parent = Tk_NameToWindow(interp, choice, parent);
if (parent == NULL) {
result = TCL_ERROR;
goto end;
}
break;
case OPEN_TITLE:
choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
title = CFStringCreateWithBytes(NULL, (unsigned char*) choice, choiceLen,
kCFStringEncodingUTF8, false);
break;
}
}
if (HandleInitialDirectory(interp, initialFile, initialDir, &dirRef,
&selectDesc, &initialDesc) != TCL_OK) {
result = TCL_ERROR;
goto end;
}
if (initialDesc.descriptorType == typeFSRef) {
initialPtr = &initialDesc;
}
if (typeVariablePtr) {
initialtype = Tcl_GetVar(interp, Tcl_GetString(typeVariablePtr), 0);
}
result = NavServicesGetFile(interp, &ofd, initialPtr,
NULL, &selectDesc,
title, message, initialtype, multiple, OPEN_FILE);
if (typeVariablePtr) {
int i = ofd.curType;
FileFilter *filterPtr;
for (filterPtr = ofd.fl.filters;
filterPtr && i > 0; i--) {
filterPtr = filterPtr->next;
}
Tcl_SetVar(interp, Tcl_GetString(typeVariablePtr), filterPtr->name, 0);
}
end:
TkFreeFileFilters(&ofd.fl);
AEDisposeDesc(&initialDesc);
AEDisposeDesc(&selectDesc);
if (title != NULL) {
CFRelease(title);
}
if (message != NULL) {
CFRelease(message);
}
return result;
}
/*
*----------------------------------------------------------------------
*
* Tk_GetSaveFileObjCmd --
*
* Same as Tk_GetOpenFileCmd but opens a "save file" dialog box
* instead
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See user documentation.
*----------------------------------------------------------------------
*/
int
Tk_GetSaveFileObjCmd(
ClientData clientData, /* Main window associated with interpreter. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *CONST objv[]) /* Argument objects. */
{
int i, result;
char *initialFile = NULL;
Tk_Window parent;
AEDesc initialDesc = {typeNull, NULL};
AEDesc *initialPtr = NULL;
FSRef dirRef;
CFStringRef title, message;
OpenFileData ofd;
static CONST char *saveOptionStrings[] = {
"-defaultextension", "-filetypes", "-initialdir", "-initialfile",
"-message", "-parent", "-title", "-typevariable",
NULL
};
enum saveOptions {
SAVE_DEFAULT, SAVE_FILETYPES, SAVE_INITDIR, SAVE_INITFILE,
SAVE_MESSAGE, SAVE_PARENT, SAVE_TITLE, SAVE_TYPEVARIABLE
};
if (!fileDlgInited) {
InitFileDialogs();
}
result = TCL_ERROR;
parent = (Tk_Window) clientData;
title = NULL;
message = NULL;
for (i = 1; i < objc; i += 2) {
char *choice;
int index, choiceLen;
char *string;
if (Tcl_GetIndexFromObj(interp, objv[i], saveOptionStrings, "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;
}
switch (index) {
case SAVE_DEFAULT:
break;
case SAVE_FILETYPES:
/* Currently unimplemented - what would we do here anyway? */
break;
case SAVE_TYPEVARIABLE:
/* Ignored since filetypes is ignored */
break;
case SAVE_INITDIR:
choice = Tcl_GetStringFromObj(objv[i + 1], NULL);
if (HandleInitialDirectory(interp, NULL, choice, &dirRef,
NULL, &initialDesc) != TCL_OK) {
result = TCL_ERROR;
goto end;
}
break;
case SAVE_INITFILE:
initialFile = Tcl_GetStringFromObj(objv[i + 1], NULL);
break;
case SAVE_MESSAGE:
choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
message = CFStringCreateWithBytes(NULL, (unsigned char*) choice, choiceLen,
kCFStringEncodingUTF8, false);
break;
case SAVE_PARENT:
choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
parent = Tk_NameToWindow(interp, choice, parent);
if (parent == NULL) {
result = TCL_ERROR;
goto end;
}
break;
case SAVE_TITLE:
choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
title = CFStringCreateWithBytes(NULL, (unsigned char*) choice, choiceLen,
kCFStringEncodingUTF8, false);
break;
}
}
TkInitFileFilters(&ofd.fl);
ofd.usePopup = 0;
if (initialDesc.descriptorType == typeFSRef) {
initialPtr = &initialDesc;
}
result = NavServicesGetFile(interp, &ofd, initialPtr, initialFile, NULL,
title, message, NULL, false, SAVE_FILE);
end:
AEDisposeDesc(&initialDesc);
if (title != NULL) {
CFRelease(title);
}
if (message != NULL) {
CFRelease(message);
}
return result;
}
/*
*----------------------------------------------------------------------
*
* Tk_ChooseDirectoryObjCmd --
*
* This procedure implements the "tk_chooseDirectory" dialog box
* for the Windows platform. See the user documentation for details
* on what it does.
*
* Results:
* See user documentation.
*
* Side effects:
* A modal dialog window is created. Tcl_SetServiceMode() is
* called to allow background events to be processed
*
*----------------------------------------------------------------------
*/
int
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. */
{
int i, result;
Tk_Window parent;
AEDesc initialDesc = {typeNull, NULL};
AEDesc *initialPtr = NULL;
FSRef dirRef;
CFStringRef message, title;
OpenFileData ofd;
static CONST char *chooseOptionStrings[] = {
"-initialdir", "-message", "-mustexist", "-parent", "-title", NULL
};
enum chooseOptions {
CHOOSE_INITDIR, CHOOSE_MESSAGE, CHOOSE_MUSTEXIST,
CHOOSE_PARENT, CHOOSE_TITLE
};
if (!NavServicesAvailable()) {
return TCL_ERROR;
}
if (!fileDlgInited) {
InitFileDialogs();
}
result = TCL_ERROR;
parent = (Tk_Window) clientData;
title = NULL;
message = NULL;
for (i = 1; i < objc; i += 2) {
char *choice;
int index, choiceLen;
char *string;
if (Tcl_GetIndexFromObj(interp, objv[i], chooseOptionStrings, "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;
}
switch (index) {
case CHOOSE_INITDIR:
choice = Tcl_GetStringFromObj(objv[i + 1], NULL);
if (HandleInitialDirectory(interp, NULL, choice, &dirRef,
NULL, &initialDesc) != TCL_OK) {
result = TCL_ERROR;
goto end;
}
break;
case CHOOSE_MESSAGE:
choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
message = CFStringCreateWithBytes(NULL, (unsigned char*) choice, choiceLen,
kCFStringEncodingUTF8, false);
break;
case CHOOSE_PARENT:
choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
parent = Tk_NameToWindow(interp, choice, parent);
if (parent == NULL) {
result = TCL_ERROR;
goto end;
}
break;
case CHOOSE_TITLE:
choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen);
title = CFStringCreateWithBytes(NULL, (unsigned char*) choice, choiceLen,
kCFStringEncodingUTF8, false);
break;
}
}
TkInitFileFilters(&ofd.fl);
ofd.usePopup = 0;
if (initialDesc.descriptorType == typeFSRef) {
initialPtr = &initialDesc;
}
result = NavServicesGetFile(interp, &ofd, initialPtr, NULL, NULL,
title, message, NULL, false, CHOOSE_FOLDER);
end:
AEDisposeDesc(&initialDesc);
if (title != NULL) {
CFRelease(title);
}
if (message != NULL) {
CFRelease(message);
}
return result;
}
int
HandleInitialDirectory (
Tcl_Interp *interp,
char *initialFile,
char *initialDir,
FSRef *dirRef,
AEDescList *selectDescPtr,
AEDesc *dirDescPtr)
{
Tcl_DString ds;
OSErr err;
Boolean isDirectory;
char *dirName = NULL;
int result = TCL_OK;
if (initialDir != NULL) {
dirName = Tcl_TranslateFileName(interp, initialDir, &ds);
if (dirName == NULL) {
return TCL_ERROR;
}
err = FSPathMakeRef((unsigned char*) dirName,
dirRef, &isDirectory);
if (err != noErr) {
Tcl_AppendResult(interp, "bad directory \"",
initialDir, "\"", NULL);
result = TCL_ERROR;
goto end;
}
if (!isDirectory) {
Tcl_AppendResult(interp, "-intialdir \"",
initialDir, " is a file, not a directory.\"", NULL);
result = TCL_ERROR;
goto end;
}
AECreateDesc(typeFSRef, dirRef, sizeof(*dirRef), dirDescPtr);
}
if (initialFile != NULL && selectDescPtr != NULL) {
FSRef fileRef;
AEDesc fileDesc;
char *namePtr;
if (initialDir != NULL) {
Tcl_DStringAppend(&ds, "/", 1);
Tcl_DStringAppend(&ds, initialFile, -1);
namePtr = Tcl_DStringValue(&ds);
} else {
namePtr = initialFile;
}
AECreateList(NULL, 0, false, selectDescPtr);
err = FSPathMakeRef((unsigned char*) namePtr, &fileRef, &isDirectory);
if (err != noErr) {
Tcl_AppendResult(interp, "bad initialfile \"", initialFile,
"\" file does not exist.", NULL);
return TCL_ERROR;
}
AECreateDesc(typeFSRef, &fileRef, sizeof(fileRef), &fileDesc);
AEPutDesc(selectDescPtr, 1, &fileDesc);
AEDisposeDesc(&fileDesc);
}
end:
if (dirName != NULL) {
Tcl_DStringFree(&ds);
}
return result;
}
static void
InitFileDialogs()
{
fileDlgInited = 1;
openFileFilterUPP = NewNavObjectFilterUPP(OpenFileFilterProc);
openFileEventUPP = NewNavEventUPP(OpenEventProc);
}
static int
NavServicesGetFile(
Tcl_Interp *interp,
OpenFileData *ofdPtr,
AEDesc *initialDescPtr,
char *initialFile,
AEDescList *selectDescPtr,
CFStringRef title,
CFStringRef message,
CONST char *initialtype,
int multiple,
int isOpen)
{
NavReplyRecord theReply;
NavDialogCreationOptions diagOptions;
NavDialogRef dialogRef = NULL;
CFStringRef * menuItemNames = NULL;
OSErr err;
Tcl_Obj *theResult = NULL;
int result;
err = NavGetDefaultDialogCreationOptions(&diagOptions);
if (err!=noErr) {
return TCL_ERROR;
}
diagOptions.location.h = -1;
diagOptions.location.v = -1;
diagOptions.optionFlags = kNavDontAutoTranslate
+ kNavDontAddTranslateItems;
if (multiple) {
diagOptions.optionFlags += kNavAllowMultipleFiles;
}
diagOptions.modality = kWindowModalityAppModal;
if (ofdPtr != NULL && ofdPtr->usePopup) {
FileFilter *filterPtr;
filterPtr = ofdPtr->fl.filters;
if (filterPtr == NULL) {
ofdPtr->usePopup = 0;
}
}
if (ofdPtr != NULL && ofdPtr->usePopup) {
FileFilter *filterPtr;
int index = 0;
ofdPtr->curType = 0;
menuItemNames = (CFStringRef *)ckalloc(ofdPtr->fl.numFilters
* sizeof(CFStringRef));
for (filterPtr = ofdPtr->fl.filters; filterPtr != NULL;
filterPtr = filterPtr->next, index++) {
menuItemNames[index] = CFStringCreateWithCString(NULL,
filterPtr->name, kCFStringEncodingUTF8);
if (initialtype && strcmp(filterPtr->name, initialtype) == 0) {
ofdPtr->initialType = index;
}
}
diagOptions.popupExtension = CFArrayCreate(NULL,
(const void **) menuItemNames, ofdPtr->fl.numFilters, NULL);
} else {
diagOptions.optionFlags += kNavNoTypePopup;
diagOptions.popupExtension = NULL;
}
/*
* This is required to allow App packages to be selectable in the
* file dialogs...
*/
diagOptions.optionFlags += kNavSupportPackages;
diagOptions.clientName = CFStringCreateWithCString(NULL, "Wish", kCFStringEncodingUTF8);
diagOptions.message = message;
diagOptions.windowTitle = title;
if (initialFile) {
diagOptions.saveFileName = CFStringCreateWithCString(NULL,
initialFile, kCFStringEncodingUTF8);
} else {
diagOptions.saveFileName = NULL;
}
diagOptions.actionButtonLabel = NULL;
diagOptions.cancelButtonLabel = NULL;
diagOptions.preferenceKey = 0;
/*
* Now process the selection list. We have to use the popupExtension
* to fill the menu.
*/
if (isOpen == OPEN_FILE) {
err = NavCreateGetFileDialog(&diagOptions,
NULL,
openFileEventUPP,
NULL,
openFileFilterUPP,
ofdPtr,
&dialogRef);
if (err != noErr) {
fprintf(stderr,"NavCreateGetFileDialog failed, %d\n", err );
dialogRef = NULL;
}
} else if (isOpen == SAVE_FILE) {
err = NavCreatePutFileDialog(&diagOptions, 'TEXT', 'WIsH',
openFileEventUPP, NULL, &dialogRef);
if (err!=noErr){
fprintf(stderr,"NavCreatePutFileDialog failed, %d\n", err );
dialogRef = NULL;
}
} else if (isOpen == CHOOSE_FOLDER) {
err = NavCreateChooseFolderDialog(&diagOptions, openFileEventUPP,
openFileFilterUPP, NULL, &dialogRef);
if (err!=noErr){
fprintf(stderr,"NavCreateChooseFolderDialog failed, %d\n", err );
dialogRef = NULL;
}
}
if (dialogRef) {
if (initialDescPtr != NULL) {
NavCustomControl (dialogRef, kNavCtlSetLocation, initialDescPtr);
}
if ((selectDescPtr != NULL)
&& (selectDescPtr->descriptorType != typeNull)) {
NavCustomControl(dialogRef, kNavCtlSetSelection, selectDescPtr);
}
if ((err = NavDialogRun(dialogRef)) != noErr ){
fprintf(stderr,"NavDialogRun failed, %d\n", err );
} else {
if ((err = NavDialogGetReply(dialogRef, &theReply)) != noErr) {
fprintf(stderr,"NavGetReply failed, %d\n", err );
}
}
}
/*
* Most commands assume that the file dialogs return a single
* item, not a list. So only build a list if multiple is true...
*/
if (err == noErr) {
if (multiple) {
theResult = Tcl_NewListObj(0, NULL);
} else {
theResult = Tcl_NewObj();
}
if (!theResult) {
err = memFullErr;
}
}
if (theReply.validRecord && err == noErr) {
AEDesc resultDesc;
long count;
FSRef fsRef;
char pathPtr[1024];
int pathValid = 0;
err = AECountItems(&theReply.selection, &count);
if (err == noErr) {
long i;
for (i = 1; i <= count; i++ ) {
err = AEGetNthDesc(&theReply.selection,
i, typeFSRef, NULL, &resultDesc);
pathValid = 0;
if (err == noErr) {
if ((err = AEGetDescData(&resultDesc, &fsRef, sizeof(fsRef)))
!= noErr ) {
fprintf(stderr,"AEGetDescData failed %d\n", err );
} else {
if ((err = FSRefMakePath(&fsRef, (unsigned char*) pathPtr, 1024)) ) {
fprintf(stderr,"FSRefMakePath failed, %d\n", err );
} else {
if (isOpen == SAVE_FILE) {
CFStringRef saveNameRef;
char saveName [1024];
if ((saveNameRef = NavDialogGetSaveFileName(dialogRef))) {
if (CFStringGetCString(saveNameRef, saveName,
1024, kCFStringEncodingUTF8)) {
if (strlen(pathPtr) + strlen(saveName) < 1023) {
strcat(pathPtr, "/");
strcat(pathPtr, saveName);
pathValid = 1;
} else {
fprintf(stderr, "Path name too long\n");
}
} else {
fprintf(stderr, "CFStringGetCString failed\n");
}
} else {
fprintf(stderr, "NavDialogGetSaveFileName failed\n");
}
} else {
pathValid = 1;
}
if (pathValid) {
if (multiple) {
Tcl_ListObjAppendElement(interp, theResult,
Tcl_NewStringObj(pathPtr, -1));
} else {
Tcl_SetStringObj(theResult, pathPtr, -1);
}
}
}
}
AEDisposeDesc(&resultDesc);
}
}
}
err = NavDisposeReply(&theReply);
Tcl_SetObjResult(interp, theResult);
result = TCL_OK;
} else if (err == userCanceledErr) {
result = TCL_OK;
} else {
result = TCL_ERROR;
}
/*
* Clean up any allocated strings
* dispose of things in reverse order of creation
*/
if (diagOptions.windowTitle) {
CFRelease(diagOptions.windowTitle);
}
if (diagOptions.saveFileName) {
CFRelease(diagOptions.saveFileName);
}
if (diagOptions.message) {
CFRelease(diagOptions.message);
}
if (diagOptions.clientName) {
CFRelease(diagOptions.clientName);
}
/*
* dispose of the CFArray diagOptions.popupExtension
*/
if (menuItemNames) {
int i;
for (i = 0;i < ofdPtr->fl.numFilters; i++) {
CFRelease(menuItemNames[i]);
}
ckfree((void *)menuItemNames);
}
if (diagOptions.popupExtension != NULL) {
CFRelease(diagOptions.popupExtension);
}
return result;
}
static pascal Boolean
OpenFileFilterProc(
AEDesc* theItem, void* info,
NavCallBackUserData callBackUD,
NavFilterModes filterMode )
{
OpenFileData *ofdPtr = (OpenFileData *) callBackUD;
if (!ofdPtr || !ofdPtr->usePopup) {
return true;
} else {
if (ofdPtr->fl.numFilters == 0) {
return true;
} else {
if ((theItem->descriptorType == typeFSS)
|| (theItem->descriptorType == typeFSRef)) {
NavFileOrFolderInfo* theInfo = (NavFileOrFolderInfo *) info;
char fileName[256];
int result;
if ( !theInfo->isFolder ) {
OSType fileType;
StringPtr fileNamePtr;
Tcl_DString fileNameDString;
int i;
FileFilter *filterPtr;
fileType =
theInfo->fileAndFolder.fileInfo.finderInfo.fdType;
Tcl_DStringInit (&fileNameDString);
if (theItem->descriptorType == typeFSS) {
int len;
fileNamePtr = (((FSSpec *) *theItem->dataHandle)->name);
len = fileNamePtr[0];
strncpy(fileName, (char*) fileNamePtr + 1, len);
fileName[len] = '\0';
fileNamePtr = (unsigned char*) fileName;
} else if (theItem->descriptorType == typeFSRef) {
OSStatus err;
FSRef *theRef = (FSRef *) *theItem->dataHandle;
HFSUniStr255 uniFileName;
err = FSGetCatalogInfo (theRef, kFSCatInfoNone, NULL,
&uniFileName, NULL, NULL);
if (err == noErr) {
Tcl_UniCharToUtfDString (
(Tcl_UniChar *) uniFileName.unicode,
uniFileName.length,
&fileNameDString);
fileNamePtr = (unsigned char*) Tcl_DStringValue(&fileNameDString);
} else {
fileNamePtr = NULL;
}
}
if (ofdPtr->usePopup) {
i = ofdPtr->curType;
for (filterPtr = ofdPtr->fl.filters;
filterPtr && i > 0; i--) {
filterPtr = filterPtr->next;
}
if (filterPtr) {
result = MatchOneType(fileNamePtr, fileType,
ofdPtr, filterPtr);
} else {
result = false;
}
} else {
/*
* We are not using the popup menu. In this case, the
* file is considered matched if it matches any of
* the file filters.
*/
result = UNMATCHED;
for (filterPtr = ofdPtr->fl.filters; filterPtr;
filterPtr = filterPtr->next) {
if (MatchOneType(fileNamePtr, fileType,
ofdPtr, filterPtr) == MATCHED) {
result = MATCHED;
break;
}
}
}
Tcl_DStringFree (&fileNameDString);
return (result == MATCHED);
} else {
return true;
}
}
}
return true;
}
}
pascal void
OpenEventProc(
NavEventCallbackMessage callBackSelector,
NavCBRecPtr callBackParams,
NavCallBackUserData callBackUD )
{
NavMenuItemSpec *chosenItem;
OpenFileData *ofd = (OpenFileData *) callBackUD;
static SInt32 otherEvent = ~(kNavCBCustomize|kNavCBStart|kNavCBTerminate
|kNavCBNewLocation|kNavCBShowDesktop|kNavCBSelectEntry|kNavCBAccept
|kNavCBCancel|kNavCBAdjustPreview);
if (callBackSelector == kNavCBStart) {
if (ofd && ofd->initialType >= 0) {
/* Select initial filter */
int i = ofd->initialType;
FileFilter *filterPtr;
for (filterPtr = ofd->fl.filters;
filterPtr && i > 0; i--) {
filterPtr = filterPtr->next;
}
if (filterPtr) {
NavMenuItemSpec selectItem;
OSStatus err;
selectItem.version = kNavMenuItemSpecVersion;
selectItem.menuCreator = 0;
selectItem.menuType = ofd->initialType;
selectItem.menuItemName[0] = strlen(filterPtr->name);
strncpy(&selectItem.menuItemName[1], filterPtr->name, 255);
err = NavCustomControl(callBackParams->context, kNavCtlSelectCustomType, &selectItem);
if (err != noErr) {
fprintf(stderr,"NavCustomControl kNavCtlSelectCustomType Failed, %d\n", (int)err );
}
}
}
}
if (callBackSelector == kNavCBPopupMenuSelect) {
chosenItem = (NavMenuItemSpec *) callBackParams->eventData.eventDataParms.param;
ofd->curType = chosenItem->menuType;
} else if (callBackSelector == kNavCBAdjustRect
|| (callBackSelector & otherEvent) != 0) {
while (Tcl_DoOneEvent(TCL_IDLE_EVENTS
| TCL_DONT_WAIT
| TCL_WINDOW_EVENTS)) {
/* Empty Body */
}
}
}
/*
*----------------------------------------------------------------------
*
* MatchOneType --
*
* Match a file with one file type in the list of file types.
*
* Results:
* Returns MATCHED if the file matches with the file type; returns
* UNMATCHED otherwise.
*
* Side effects:
* None
*
*----------------------------------------------------------------------
*/
static Boolean
MatchOneType(
StringPtr fileNamePtr, /* Name of the file */
OSType fileType, /* Type of the file, 0 means there was no specified type. */
OpenFileData * ofdPtr, /* Information about this file dialog */
FileFilter * filterPtr) /* Match the file described by pb against
* this filter */
{
FileFilterClause * clausePtr;
/*
* A file matches with a file type if it matches with at least one
* clause of the type.
*
* If the clause has both glob patterns and ostypes, the file must
* match with at least one pattern AND at least one ostype.
*
* If the clause has glob patterns only, the file must match with at least
* one pattern.
*
* If the clause has mac types only, the file must match with at least
* one mac type.
*
* If the clause has neither glob patterns nor mac types, it's
* considered an error.
*/
for (clausePtr = filterPtr->clauses; clausePtr;
clausePtr = clausePtr->next) {
int macMatched = 0;
int globMatched = 0;
GlobPattern * globPtr;
MacFileType * mfPtr;
if (clausePtr->patterns == NULL) {
globMatched = 1;
}
if (clausePtr->macTypes == NULL) {
macMatched = 1;
}
for (globPtr = clausePtr->patterns; globPtr;
globPtr = globPtr->next) {
char *q, *ext;
if (fileNamePtr == NULL) {
continue;
}
ext = globPtr->pattern;
if (ext[0] == '\0') {
/*
* We don't want any extensions: OK if the filename doesn't
* have "." in it
*/
for (q = (char*) fileNamePtr; *q; q++) {
if (*q == '.') {
goto glob_unmatched;
}
}
goto glob_matched;
}
if (Tcl_StringMatch((char*) fileNamePtr, ext)) {
goto glob_matched;
} else {
goto glob_unmatched;
}
glob_unmatched:
continue;
glob_matched:
globMatched = 1;
break;
}
for (mfPtr = clausePtr->macTypes; mfPtr; mfPtr = mfPtr->next) {
if (fileType == mfPtr->type) {
macMatched = 1;
break;
}
}
/*
* On Mac OS X, it is not uncommon for files to have NO
* file type. But folks with Tcl code on Classic MacOS pretty
* much assume that a generic file will have type TEXT. So
* if we were strict about matching types when the source file
* had NO type set, they would have to add another rule always
* with no fileType. To avoid that, we pass the macMatch side
* of the test if no fileType is set.
*/
if (globMatched && (macMatched || (fileType == 0))) {
return MATCHED;
}
}
return UNMATCHED;
}
/*
*----------------------------------------------------------------------
*
* TkAboutDlg --
*
* Displays the default Tk About box. This code uses Macintosh
* resources to define the content of the About Box.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
TkAboutDlg()
{
DialogPtr aboutDlog;
WindowRef windowRef;
short itemHit = -9;
aboutDlog = GetNewDialog(128, NULL, (void *) (-1));
if (!aboutDlog) {
return;
}
windowRef = GetDialogWindow(aboutDlog);
SelectWindow(windowRef);
while (itemHit != 1) {
ModalDialog( NULL, &itemHit);
}
DisposeDialog(aboutDlog);
aboutDlog = NULL;
SelectWindow(FrontNonFloatingWindow());
return;
}
/*
*----------------------------------------------------------------------
*
* Tk_MessageBoxObjCmd --
*
* Implements the tk_messageBox in native Mac OS X style.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* none
*
*----------------------------------------------------------------------
*/
int
Tk_MessageBoxObjCmd(
ClientData clientData, /* Main window associated with interpreter. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *CONST objv[]) /* Argument objects. */
{
Tk_Window tkwin = (Tk_Window) clientData;
AlertStdCFStringAlertParamRec paramCFStringRec;
AlertType alertType;
DialogRef dialogRef;
CFStringRef messageTextCF = NULL;
CFStringRef finemessageTextCF = NULL;
OSErr osError;
SInt16 itemHit;
Boolean haveDefaultOption = false;
Boolean haveParentOption = false;
char *str;
int index;
int defaultButtonIndex;
int defaultNativeButtonIndex; /* 1, 2, 3: right to left. */
int typeIndex;
int i;
int indexDefaultOption;
int result = TCL_OK;
static CONST char *movableAlertStrings[] = {
"-default", "-detail", "-icon",
"-message", "-parent",
"-title", "-type",
(char *)NULL
};
static CONST char *movableTypeStrings[] = {
"abortretryignore", "ok",
"okcancel", "retrycancel",
"yesno", "yesnocancel",
(char *)NULL
};
static CONST char *movableButtonStrings[] = {
"abort", "retry", "ignore",
"ok", "cancel", "yes", "no",
(char *)NULL
};
static CONST char *movableIconStrings[] = {
"error", "info", "question", "warning",
(char *)NULL
};
enum movableAlertOptions {
ALERT_DEFAULT, ALERT_DETAIL, ALERT_ICON,
ALERT_MESSAGE, ALERT_PARENT,
ALERT_TITLE, ALERT_TYPE
};
enum movableTypeOptions {
TYPE_ABORTRETRYIGNORE, TYPE_OK,
TYPE_OKCANCEL, TYPE_RETRYCANCEL,
TYPE_YESNO, TYPE_YESNOCANCEL
};
enum movableButtonOptions {
TEXT_ABORT, TEXT_RETRY, TEXT_IGNORE,
TEXT_OK, TEXT_CANCEL, TEXT_YES, TEXT_NO
};
enum movableIconOptions {
ICON_ERROR, ICON_INFO, ICON_QUESTION, ICON_WARNING
};
/*
* Need to map from 'movableButtonStrings' and its corresponding integer index,
* to the native button index, which is 1, 2, 3, from right to left.
* This is necessary to do for each separate '-type' of button sets.
*/
short buttonIndexAndTypeToNativeButtonIndex[][7] = {
/* abort retry ignore ok cancel yes no */
{1, 2, 3, 0, 0, 0, 0}, /* abortretryignore */
{0, 0, 0, 1, 0, 0, 0}, /* ok */
{0, 0, 0, 1, 2, 0, 0}, /* okcancel */
{0, 1, 0, 0, 2, 0, 0}, /* retrycancel */
{0, 0, 0, 0, 0, 1, 2}, /* yesno */
{0, 0, 0, 0, 3, 1, 2}, /* yesnocancel */
};
/*
* Need also the inverse mapping, from native button (1, 2, 3) to the
* descriptive button text string index.
*/
short nativeButtonIndexAndTypeToButtonIndex[][4] = {
{-1, 0, 1, 2}, /* abortretryignore */
{-1, 3, 0, 0}, /* ok */
{-1, 3, 4, 0}, /* okcancel */
{-1, 1, 4, 0}, /* retrycancel */
{-1, 5, 6, 0}, /* yesno */
{-1, 5, 6, 4}, /* yesnocancel */
};
alertType = kAlertPlainAlert;
typeIndex = TYPE_OK;
GetStandardAlertDefaultParams( ¶mCFStringRec, kStdCFStringAlertVersionOne );
paramCFStringRec.movable = true;
paramCFStringRec.helpButton = false;
paramCFStringRec.defaultButton = kAlertStdAlertOKButton;
for (i = 1; i < objc; i += 2) {
int iconIndex;
char *string;
if (Tcl_GetIndexFromObj( interp, objv[i], movableAlertStrings, "option",
TCL_EXACT, &index ) != TCL_OK) {
result = TCL_ERROR;
goto end;
}
if (i + 1 == objc) {
string = Tcl_GetStringFromObj( objv[i], NULL );
Tcl_AppendResult(interp, "value for \"", string, "\" missing",
(char *) NULL);
result = TCL_ERROR;
goto end;
}
switch (index) {
case ALERT_DEFAULT:
/*
* Need to postpone processing of this option until we are
* sure to know the '-type' as well.
*/
haveDefaultOption = true;
indexDefaultOption = i;
break;
case ALERT_DETAIL:
str = Tcl_GetStringFromObj( objv[i + 1], NULL );
finemessageTextCF = CFStringCreateWithCString( NULL, str, kCFStringEncodingUTF8 );
break;
case ALERT_ICON:
/* not sure about UTF translation here... */
if (Tcl_GetIndexFromObj( interp, objv[i + 1], movableIconStrings,
"value", TCL_EXACT, &iconIndex ) != TCL_OK) {
result = TCL_ERROR;
goto end;
}
switch (iconIndex) {
case ICON_ERROR:
alertType = kAlertStopAlert;
break;
case ICON_INFO:
alertType = kAlertNoteAlert;
break;
case ICON_QUESTION:
alertType = kAlertCautionAlert;
break;
case ICON_WARNING:
alertType = kAlertCautionAlert;
break;
}
break;
case ALERT_MESSAGE:
str = Tcl_GetStringFromObj( objv[i + 1], NULL );
messageTextCF = CFStringCreateWithCString( NULL, str, kCFStringEncodingUTF8 );
break;
case ALERT_PARENT:
str = Tcl_GetStringFromObj( objv[i + 1], NULL );
tkwin = Tk_NameToWindow( interp, str, tkwin );
if (tkwin == NULL) {
result = TCL_ERROR;
goto end;
}
haveParentOption = true;
break;
case ALERT_TITLE:
break;
case ALERT_TYPE:
/* not sure about UTF translation here... */
if (Tcl_GetIndexFromObj( interp, objv[i + 1], movableTypeStrings,
"value", TCL_EXACT, &typeIndex ) != TCL_OK) {
result = TCL_ERROR;
goto end;
}
switch (typeIndex) {
case TYPE_ABORTRETRYIGNORE:
paramCFStringRec.defaultText = CFSTR("Abort");
paramCFStringRec.cancelText = CFSTR("Retry");
paramCFStringRec.otherText = CFSTR("Ignore");
break;
case TYPE_OK:
paramCFStringRec.defaultText = CFSTR("OK");
break;
case TYPE_OKCANCEL:
paramCFStringRec.defaultText = CFSTR("OK");
paramCFStringRec.cancelText = CFSTR("Cancel");
break;
case TYPE_RETRYCANCEL:
paramCFStringRec.defaultText = CFSTR("Retry");
paramCFStringRec.cancelText = CFSTR("Cancel");
break;
case TYPE_YESNO:
paramCFStringRec.defaultText = CFSTR("Yes");
paramCFStringRec.cancelText = CFSTR("No");
break;
case TYPE_YESNOCANCEL:
paramCFStringRec.defaultText = CFSTR("Yes");
paramCFStringRec.cancelText = CFSTR("No");
paramCFStringRec.otherText = CFSTR("Cancel");
break;
}
break;
}
}
if (haveDefaultOption) {
/*
* Any '-default' option needs to know the '-type' option, which is why
* we do this here.
*/
str = Tcl_GetStringFromObj( objv[indexDefaultOption + 1], NULL );
if (Tcl_GetIndexFromObj( interp, objv[indexDefaultOption + 1],
movableButtonStrings, "value", TCL_EXACT,
&defaultButtonIndex ) != TCL_OK) {
result = TCL_ERROR;
goto end;
}
/* Need to map from "ok" etc. to 1, 2, 3, right to left. */
defaultNativeButtonIndex =
buttonIndexAndTypeToNativeButtonIndex[typeIndex][defaultButtonIndex];
if (defaultNativeButtonIndex == 0) {
Tcl_SetObjResult( interp,
Tcl_NewStringObj( "Illegel default option", -1 ));
result = TCL_ERROR;
goto end;
}
paramCFStringRec.defaultButton = defaultNativeButtonIndex;
}
SetThemeCursor( kThemeArrowCursor );
if (haveParentOption) {
TkWindow *winPtr;
MacDrawable *macWin;
WindowRef windowRef;
EventTargetRef notifyTarget;
EventHandlerUPP handler;
CallbackUserData data;
const EventTypeSpec kEvents[] = {
{kEventClassCommand, kEventProcessCommand}
};
winPtr = (TkWindow *) tkwin;
/*
* Create the underlying Mac window for this Tk window.
*/
macWin = (MacDrawable *) winPtr->window;
windowRef = GetWindowFromPort( TkMacOSXGetDrawablePort((Drawable) macWin) );
notifyTarget = GetWindowEventTarget( windowRef );
osError = CreateStandardSheet( alertType, messageTextCF,
finemessageTextCF, ¶mCFStringRec,
notifyTarget, &dialogRef );
if(osError != noErr) {
result = TCL_ERROR;
goto end;
}
data.windowRef = windowRef;
data.buttonIndex = 1;
handler = NewEventHandlerUPP( AlertHandler );
InstallEventHandler(notifyTarget, handler,
GetEventTypeCount(kEvents),
kEvents, &data, NULL );
osError = ShowSheetWindow( GetDialogWindow(dialogRef), windowRef );
if(osError != noErr) {
result = TCL_ERROR;
goto end;
}
osError = RunAppModalLoopForWindow( windowRef );
itemHit = data.buttonIndex;
DisposeEventHandlerUPP( handler );
} else {
osError = CreateStandardAlert( alertType, messageTextCF,
finemessageTextCF, ¶mCFStringRec, &dialogRef );
if(osError != noErr) {
result = TCL_ERROR;
goto end;
}
osError = RunStandardAlert( dialogRef, NULL, &itemHit );
}
if(osError == noErr) {
int ind;
/*
* Map 'itemHit' (1, 2, 3) to descriptive text string.
*/
ind = nativeButtonIndexAndTypeToButtonIndex[typeIndex][itemHit];
Tcl_SetObjResult( interp,
Tcl_NewStringObj( movableButtonStrings[ind], -1 ));
} else {
result = TCL_ERROR;
}
end:
if (finemessageTextCF != NULL) {
CFRelease( finemessageTextCF );
}
if (messageTextCF != NULL) {
CFRelease( messageTextCF );
}
return result;
}
/*
*----------------------------------------------------------------------
*
* AlertHandler --
*
* Carbon event handler for the Standard Sheet dialog.
*
* Results:
* OSStatus if event handled or not.
*
* Side effects:
* May set userData.
*
*----------------------------------------------------------------------
*/
static OSStatus
AlertHandler( EventHandlerCallRef callRef, EventRef eventRef, void *userData )
{
OSStatus result = eventNotHandledErr;
HICommand cmd;
CallbackUserData *dataPtr = (CallbackUserData *) userData;
GetEventParameter( eventRef, kEventParamDirectObject, typeHICommand,
NULL, sizeof(cmd), NULL, &cmd );
switch (cmd.commandID) {
case kHICommandOK:
dataPtr->buttonIndex = 1;
result = noErr;
break;
case kHICommandCancel:
dataPtr->buttonIndex = 2;
result = noErr;
break;
case kHICommandOther:
dataPtr->buttonIndex = 3;
result = noErr;
break;
}
if (result == noErr) {
result = QuitAppModalLoopForWindow( dataPtr->windowRef );
}
return result;
}