diff options
Diffstat (limited to 'macosx/tkMacOSXDialog.c')
-rw-r--r-- | macosx/tkMacOSXDialog.c | 2147 |
1 files changed, 725 insertions, 1422 deletions
diff --git a/macosx/tkMacOSXDialog.c b/macosx/tkMacOSXDialog.c index e283f5c..fe39d8c 100644 --- a/macosx/tkMacOSXDialog.c +++ b/macosx/tkMacOSXDialog.c @@ -4,108 +4,217 @@ * Contains the Mac implementation of the common dialog boxes. * * Copyright (c) 1996-1997 Sun Microsystems, Inc. - * Copyright 2001, Apple Computer, Inc. - * Copyright (c) 2006-2008 Daniel A. Steffen <das@users.sourceforge.net> + * Copyright 2001-2009, Apple Inc. + * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net> * * 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.43 2008/12/10 05:02:52 das Exp $ + * RCS: @(#) $Id: tkMacOSXDialog.c,v 1.44 2009/06/29 14:35:01 das Exp $ */ #include "tkMacOSXPrivate.h" #include "tkFileFilter.h" -#ifndef StrLength -#define StrLength(s) (*((unsigned char *) (s))) -#endif -#ifndef StrBody -#define StrBody(s) ((char *) (s) + 1) -#endif - -#define OPEN_POPUP_ITEM 10 +static const char *const colorOptionStrings[] = { + "-initialcolor", "-parent", "-title", NULL +}; +enum colorOptions { + COLOR_INITIAL, COLOR_PARENT, COLOR_TITLE +}; -#define SAVE_FILE 0 -#define OPEN_FILE 1 -#define CHOOSE_FOLDER 2 +static const char *const openOptionStrings[] = { + "-defaultextension", "-filetypes", "-initialdir", "-initialfile", + "-message", "-multiple", "-parent", "-title", "-typevariable", + "-command", NULL +}; +enum openOptions { + OPEN_DEFAULT, OPEN_FILETYPES, OPEN_INITDIR, OPEN_INITFILE, + OPEN_MESSAGE, OPEN_MULTIPLE, OPEN_PARENT, OPEN_TITLE, + OPEN_TYPEVARIABLE, OPEN_COMMAND, +}; +static const char *const saveOptionStrings[] = { + "-defaultextension", "-filetypes", "-initialdir", "-initialfile", + "-message", "-parent", "-title", "-typevariable", "-command", NULL +}; +enum saveOptions { + SAVE_DEFAULT, SAVE_FILETYPES, SAVE_INITDIR, SAVE_INITFILE, + SAVE_MESSAGE, SAVE_PARENT, SAVE_TITLE, SAVE_TYPEVARIABLE, SAVE_COMMAND, +}; +static const char *const chooseOptionStrings[] = { + "-initialdir", "-message", "-mustexist", "-parent", "-title", "-command", + NULL +}; +enum chooseOptions { + CHOOSE_INITDIR, CHOOSE_MESSAGE, CHOOSE_MUSTEXIST, CHOOSE_PARENT, + CHOOSE_TITLE, CHOOSE_COMMAND, +}; +typedef struct { + Tcl_Interp *interp; + Tcl_Obj *cmdObj; + int multiple; +} FilePanelCallbackInfo; -#define MATCHED 0 -#define UNMATCHED 1 +static const char *const alertOptionStrings[] = { + "-default", "-detail", "-icon", "-message", "-parent", "-title", + "-type", "-command", NULL +}; +enum alertOptions { + ALERT_DEFAULT, ALERT_DETAIL, ALERT_ICON, ALERT_MESSAGE, ALERT_PARENT, + ALERT_TITLE, ALERT_TYPE, ALERT_COMMAND, +}; +typedef struct { + Tcl_Interp *interp; + Tcl_Obj *cmdObj; + int typeIndex; +} AlertCallbackInfo; +static const char *const alertTypeStrings[] = { + "abortretryignore", "ok", "okcancel", "retrycancel", "yesno", + "yesnocancel", NULL +}; +enum alertTypeOptions { + TYPE_ABORTRETRYIGNORE, TYPE_OK, TYPE_OKCANCEL, TYPE_RETRYCANCEL, + TYPE_YESNO, TYPE_YESNOCANCEL +}; +static const char *const alertIconStrings[] = { + "error", "info", "question", "warning", NULL +}; +enum alertIconOptions { + ICON_ERROR, ICON_INFO, ICON_QUESTION, ICON_WARNING +}; +static const char *const alertButtonStrings[] = { + "abort", "retry", "ignore", "ok", "cancel", "yes", "no", NULL +}; -#define TK_DEFAULT_ABOUT 128 +static const NSString *const alertButtonNames[][3] = { + [TYPE_ABORTRETRYIGNORE] = {@"Abort", @"Retry", @"Ignore"}, + [TYPE_OK] = {@"OK"}, + [TYPE_OKCANCEL] = {@"OK", @"Cancel"}, + [TYPE_RETRYCANCEL] = {@"Retry", @"Cancel"}, + [TYPE_YESNO] = {@"Yes", @"No"}, + [TYPE_YESNOCANCEL] = {@"Yes", @"No", @"Cancel"}, +}; +static const NSAlertStyle alertStyles[] = { + [ICON_ERROR] = NSWarningAlertStyle, + [ICON_INFO] = NSInformationalAlertStyle, + [ICON_QUESTION] = NSWarningAlertStyle, + [ICON_WARNING] = NSCriticalAlertStyle, +}; /* - * The following structures are used in the GetFileName() function. They store - * information about the file dialog and the file filters. + * Need to map from 'alertButtonStrings' 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. */ -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; - -typedef struct NavHandlerUserData { - OpenFileData *ofdPtr; - NavReplyRecord reply; - OSStatus err; - CFStringRef saveNameRef; - int sheet; - WindowRef dialogWindow, origUnavailWindow; - WindowModality origModality; -} NavHandlerUserData; +static const short alertButtonIndexAndTypeToNativeButtonIndex[][7] = { + /* abort retry ignore ok cancel yes no */ + [TYPE_ABORTRETRYIGNORE] = {1, 2, 3, 0, 0, 0, 0}, + [TYPE_OK] = {0, 0, 0, 1, 0, 0, 0}, + [TYPE_OKCANCEL] = {0, 0, 0, 1, 2, 0, 0}, + [TYPE_RETRYCANCEL] = {0, 1, 0, 0, 2, 0, 0}, + [TYPE_YESNO] = {0, 0, 0, 0, 0, 1, 2}, + [TYPE_YESNOCANCEL] = {0, 0, 0, 0, 3, 1, 2}, +}; /* - * The following structure is used in the tk_messageBox implementation. + * Need also the inverse mapping, from NSAlertFirstButtonReturn etc to the + * descriptive button text string index. */ -typedef struct { - int buttonIndex; - WindowRef dialogWindow, origUnavailWindow; - WindowModality origModality; - EventHandlerRef handlerRef; -} AlertHandlerUserData; - - -static OSStatus AlertHandler(EventHandlerCallRef callRef, - EventRef eventRef, void *userData); -static Boolean MatchOneType(StringPtr fileNamePtr, OSType fileType, - OpenFileData *myofdPtr, FileFilter *filterPtr); -static pascal Boolean OpenFileFilterProc(AEDesc* theItem, void* info, - NavCallBackUserData callBackUD, - NavFilterModes filterMode); -static pascal void OpenEventProc(NavEventCallbackMessage callBackSelector, - NavCBRecPtr callBackParms, - NavCallBackUserData callBackUD); -static void InitFileDialogs(void); -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, - Tk_Window parent); -static int HandleInitialDirectory(Tcl_Interp *interp, - char *initialFile, char *initialDir, FSRef *dirRef, - AEDescList *selectDescPtr, AEDesc *dirDescPtr); +static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = { + [TYPE_ABORTRETRYIGNORE] = {0, 1, 2}, + [TYPE_OK] = {3, 0, 0}, + [TYPE_OKCANCEL] = {3, 4, 0}, + [TYPE_RETRYCANCEL] = {1, 4, 0}, + [TYPE_YESNO] = {5, 6, 0}, + [TYPE_YESNOCANCEL] = {5, 6, 4}, +}; -/* - * Have we initialized the file dialog subsystem - */ +#pragma mark TKApplication(TKDialog) -static int fileDlgInited = 0; +@interface NSColorPanel(TKDialog) +- (void)_setUseModalAppearance:(BOOL)flag; +@end -/* - * Filter and hook functions used by the tk_getOpenFile and tk_getSaveFile - * commands. - */ +@implementation TKApplication(TKDialog) +- (void)tkFilePanelDidEnd:(NSSavePanel *)panel returnCode:(NSInteger)returnCode + contextInfo:(void *)contextInfo { + FilePanelCallbackInfo *callbackInfo = contextInfo; -static NavObjectFilterUPP openFileFilterUPP; -static NavEventUPP openFileEventUPP; + if (returnCode == NSFileHandlingPanelOKButton) { + Tcl_Obj *resultObj; + if (callbackInfo->multiple) { + resultObj = Tcl_NewListObj(0, NULL); + for (NSString *name in [(NSOpenPanel*)panel filenames]) { + Tcl_ListObjAppendElement(callbackInfo->interp, resultObj, + Tcl_NewStringObj([name UTF8String], -1)); + } + } else { + resultObj = Tcl_NewStringObj([[panel filename] UTF8String], -1); + } + if (callbackInfo->cmdObj) { + Tcl_Obj **objv, **tmpv; + int objc, result = Tcl_ListObjGetElements(callbackInfo->interp, + callbackInfo->cmdObj, &objc, &objv); + if (result == TCL_OK && objc) { + tmpv = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj *) * (objc + 2)); + memcpy(tmpv, objv, sizeof(Tcl_Obj *) * objc); + tmpv[objc] = resultObj; + TkBackgroundEvalObjv(callbackInfo->interp, objc + 1, tmpv, + TCL_EVAL_GLOBAL); + ckfree((char *)tmpv); + } + } else { + Tcl_SetObjResult(callbackInfo->interp, resultObj); + } + } else if (returnCode == NSFileHandlingPanelCancelButton) { + Tcl_ResetResult(callbackInfo->interp); + } + if (panel == [NSApp modalWindow]) { + [NSApp stopModalWithCode:returnCode]; + } + if (callbackInfo->cmdObj) { + Tcl_DecrRefCount(callbackInfo->cmdObj); + ckfree((char*) callbackInfo); + } +} +- (void)tkAlertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode + contextInfo:(void *)contextInfo { + AlertCallbackInfo *callbackInfo = contextInfo; + + if (returnCode != NSAlertErrorReturn) { + Tcl_Obj *resultObj = Tcl_NewStringObj(alertButtonStrings[ + alertNativeButtonIndexAndTypeToButtonIndex[callbackInfo-> + typeIndex][returnCode - NSAlertFirstButtonReturn]], -1); + if (callbackInfo->cmdObj) { + Tcl_Obj **objv, **tmpv; + int objc, result = Tcl_ListObjGetElements(callbackInfo->interp, + callbackInfo->cmdObj, &objc, &objv); + if (result == TCL_OK && objc) { + tmpv = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj *) * (objc + 2)); + memcpy(tmpv, objv, sizeof(Tcl_Obj *) * objc); + tmpv[objc] = resultObj; + TkBackgroundEvalObjv(callbackInfo->interp, objc + 1, tmpv, + TCL_EVAL_GLOBAL); + ckfree((char *)tmpv); + } + } else { + Tcl_SetObjResult(callbackInfo->interp, resultObj); + } + } + if ([alert window] == [NSApp modalWindow]) { + [NSApp stopModalWithCode:returnCode]; + } + if (callbackInfo->cmdObj) { + Tcl_DecrRefCount(callbackInfo->cmdObj); + ckfree((char*) callbackInfo); + } +} +@end +#pragma mark - + /* *---------------------------------------------------------------------- * @@ -130,32 +239,19 @@ Tk_ChooseColorObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - OSStatus err; int result = TCL_ERROR; Tk_Window parent, tkwin = clientData; - const char *title; - int i, srcRead, dstWrote; - CMProfileRef prof; - NColorPickerInfo cpinfo; - static RGBColor color = {0xffff, 0xffff, 0xffff}; - static const char *const optionStrings[] = { - "-initialcolor", "-parent", "-title", NULL - }; - enum options { - COLOR_INITIAL, COLOR_PARENT, COLOR_TITLE - }; - - title = "Choose a color:"; - bzero(&cpinfo, sizeof(cpinfo)); - cpinfo.theColor.color.rgb.red = color.red; - cpinfo.theColor.color.rgb.green = color.green; - cpinfo.theColor.color.rgb.blue = color.blue; + const char *title = NULL; + int i; + NSColor *color = nil, *initialColor = nil; + NSColorPanel *colorPanel; + NSInteger returnCode, numberOfComponents = 0; for (i = 1; i < objc; i += 2) { int index; const char *option, *value; - if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, "option", + if (Tcl_GetIndexFromObj(interp, objv[i], colorOptionStrings, "option", TCL_EXACT, &index) != TCL_OK) { goto end; } @@ -167,7 +263,7 @@ Tk_ChooseColorObjCmd( } value = Tcl_GetString(objv[i + 1]); - switch ((enum options) index) { + switch (index) { case COLOR_INITIAL: { XColor *colorPtr; @@ -175,9 +271,7 @@ Tk_ChooseColorObjCmd( if (colorPtr == NULL) { goto end; } - cpinfo.theColor.color.rgb.red = colorPtr->red; - cpinfo.theColor.color.rgb.green = colorPtr->green; - cpinfo.theColor.color.rgb.blue = colorPtr->blue; + initialColor = TkMacOSXGetNSColor(NULL, colorPtr->pixel); Tk_FreeColor(colorPtr); break; } @@ -194,39 +288,44 @@ Tk_ChooseColorObjCmd( } } } - - ChkErr(CMGetDefaultProfileBySpace, cmRGBData, &prof); - cpinfo.theColor.profile = prof; - cpinfo.dstProfile = prof; - cpinfo.flags = kColorPickerDialogIsMoveable | kColorPickerDialogIsModal; - cpinfo.placeWhere = kCenterOnMainScreen; - /* Currently, this does not actually change the colorpicker title */ - Tcl_UtfToExternal(NULL, TkMacOSXCarbonEncoding, title, -1, 0, NULL, - StrBody(cpinfo.prompt), 255, &srcRead, &dstWrote, NULL); - StrLength(cpinfo.prompt) = (unsigned char) dstWrote; - - TkMacOSXTrackingLoop(1); - err = ChkErr(NPickColor, &cpinfo); - TkMacOSXTrackingLoop(0); - ChkErr(CMCloseProfile, prof); - if ((err == noErr) && (cpinfo.newColorChosen != 0)) { + colorPanel = [NSColorPanel sharedColorPanel]; + [colorPanel orderOut:NSApp]; + [colorPanel setContinuous:NO]; + [colorPanel setBecomesKeyOnlyIfNeeded:NO]; + [colorPanel setShowsAlpha: NO]; + [colorPanel _setUseModalAppearance:YES]; + if (title) { + NSString *s = [[NSString alloc] initWithUTF8String:title]; + [colorPanel setTitle:s]; + [s release]; + } + if (initialColor) { + [colorPanel setColor:initialColor]; + } + returnCode = [NSApp runModalForWindow:colorPanel]; + if (returnCode == NSOKButton) { + color = [[colorPanel color] colorUsingColorSpace: + [NSColorSpace genericRGBColorSpace]]; + numberOfComponents = [color numberOfComponents]; + } + if (color && numberOfComponents >= 3 && numberOfComponents <= 4) { + CGFloat components[4]; char colorstr[8]; - color.red = cpinfo.theColor.color.rgb.red; - color.green = cpinfo.theColor.color.rgb.green; - color.blue = cpinfo.theColor.color.rgb.blue; - snprintf(colorstr, 8, "#%02x%02x%02x", color.red >> 8, - color.green >> 8, color.blue >> 8); + [color getComponents:components]; + snprintf(colorstr, 8, "#%02x%02x%02x", + (short)(components[0] * 255), + (short)(components[1] * 255), + (short)(components[2] * 255)); Tcl_SetObjResult(interp, Tcl_NewStringObj(colorstr, 7)); } else { Tcl_ResetResult(interp); } result = TCL_OK; - - end: +end: return result; } - + /* *---------------------------------------------------------------------- * @@ -250,83 +349,59 @@ Tk_GetOpenFileObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - int i, result = TCL_ERROR, multiple = 0; - OpenFileData ofd; - Tk_Window parent = NULL; - CFStringRef message = NULL, title = NULL; - 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 *const 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(); - } - TkInitFileFilters(&ofd.fl); - ofd.curType = 0; - ofd.initialType = -1; - ofd.popupItem = OPEN_POPUP_ITEM; - ofd.usePopup = 1; - + Tk_Window tkwin = clientData; + char *str; + int i, result = TCL_ERROR, haveParentOption = 0; + int index, len, multiple = 0; + FileFilterList fl; + Tcl_Obj *cmdObj = NULL, *typeVariablePtr = NULL; + FilePanelCallbackInfo callbackInfoStruct; + FilePanelCallbackInfo *callbackInfo = &callbackInfoStruct; + NSString *directory = nil, *filename = nil; + NSString *message, *title, *type; + NSWindow *parent; + NSMutableArray *fileTypes = nil; + NSOpenPanel *panel = [NSOpenPanel openPanel]; + NSInteger returnCode = NSAlertErrorReturn; + + TkInitFileFilters(&fl); for (i = 1; i < objc; i += 2) { - char *choice; - int index, choiceLen; - char *string; - Tcl_Obj *types; - if (Tcl_GetIndexFromObj(interp, objv[i], openOptionStrings, "option", TCL_EXACT, &index) != TCL_OK) { goto end; } if (i + 1 == objc) { - string = Tcl_GetString(objv[i]); - Tcl_AppendResult(interp, "value for \"", string, "\" missing", - NULL); + str = Tcl_GetString(objv[i]); + Tcl_AppendResult(interp, "value for \"", str, "\" missing", NULL); goto end; } - switch (index) { case OPEN_DEFAULT: break; case OPEN_FILETYPES: - types = objv[i + 1]; - if (TkGetFileFilters(interp, &ofd.fl, types, 0) != TCL_OK) { + if (TkGetFileFilters(interp, &fl, objv[i + 1], 0) != TCL_OK) { goto end; } break; case OPEN_INITDIR: - initialDir = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - /* empty strings should be like no selection given */ - if (choiceLen == 0) { - initialDir = NULL; + str = Tcl_GetStringFromObj(objv[i + 1], &len); + if (len) { + directory = [[[NSString alloc] initWithUTF8String:str] + autorelease]; } break; case OPEN_INITFILE: - initialFile = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - /* empty strings should be like no selection given */ - if (choiceLen == 0) { - initialFile = NULL; + str = Tcl_GetStringFromObj(objv[i + 1], &len); + if (len) { + filename = [[[NSString alloc] initWithUTF8String:str] + autorelease]; } break; case OPEN_MESSAGE: - choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - if (message) { - CFRelease(message); - } - message = CFStringCreateWithBytes(NULL, (unsigned char *) choice, - choiceLen, kCFStringEncodingUTF8, false); + message = [[NSString alloc] initWithUTF8String: + Tcl_GetString(objv[i + 1])]; + [panel setMessage:message]; + [message release]; break; case OPEN_MULTIPLE: if (Tcl_GetBooleanFromObj(interp, objv[i + 1], @@ -335,73 +410,101 @@ Tk_GetOpenFileObjCmd( } break; case OPEN_PARENT: - choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - parent = Tk_NameToWindow(interp, choice, clientData); - if (parent == NULL) { + str = Tcl_GetStringFromObj(objv[i + 1], &len); + tkwin = Tk_NameToWindow(interp, str, tkwin); + if (!tkwin) { goto end; } + haveParentOption = 1; break; case OPEN_TITLE: - choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - if (title) { - CFRelease(title); - } - title = CFStringCreateWithBytes(NULL, (unsigned char *) choice, - choiceLen, kCFStringEncodingUTF8, false); + title = [[NSString alloc] initWithUTF8String: + Tcl_GetString(objv[i + 1])]; + [panel setTitle:title]; + [title release]; break; case OPEN_TYPEVARIABLE: typeVariablePtr = objv[i + 1]; break; + case OPEN_COMMAND: + cmdObj = objv[i+1]; + break; } } - - if (HandleInitialDirectory(interp, initialFile, initialDir, &dirRef, - &selectDesc, &initialDesc) != TCL_OK) { - 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, parent); - - if (typeVariablePtr) { - FileFilter *filterPtr = ofd.fl.filters; - int i = ofd.curType; - - while (filterPtr && i-- > 0) { - filterPtr = filterPtr->next; + if (fl.filters) { + fileTypes = [NSMutableArray array]; + for (FileFilter *filterPtr = fl.filters; filterPtr; + filterPtr = filterPtr->next) { + for (FileFilterClause *clausePtr = filterPtr->clauses; clausePtr; + clausePtr = clausePtr->next) { + for (GlobPattern *globPtr = clausePtr->patterns; globPtr; + globPtr = globPtr->next) { + str = globPtr->pattern; + while (*str && (*str == '*' || *str == '.')) { + str++; + } + if (*str) { + type = [[NSString alloc] initWithUTF8String:str]; + if (![fileTypes containsObject:type]) { + [fileTypes addObject:type]; + } + [type release]; + } + } + for (MacFileType *mfPtr = clausePtr->macTypes; mfPtr; + mfPtr = mfPtr->next) { + if (mfPtr->type) { + type = NSFileTypeForHFSTypeCode(mfPtr->type); + if (![fileTypes containsObject:type]) { + [fileTypes addObject:type]; + } + } + } + } } - Tcl_SetVar(interp, Tcl_GetString(typeVariablePtr), filterPtr ? - filterPtr->name : "", 0); - } - - end: - TkFreeFileFilters(&ofd.fl); - if (initialDesc.dataHandle) { - ChkErr(AEDisposeDesc, &initialDesc); } - if (selectDesc.dataHandle) { - ChkErr(AEDisposeDesc, &selectDesc); - } - if (title) { - CFRelease(title); + [panel setAllowsMultipleSelection:multiple]; + if (cmdObj) { + callbackInfo = (FilePanelCallbackInfo *) + ckalloc(sizeof(FilePanelCallbackInfo)); + if (Tcl_IsShared(cmdObj)) { + cmdObj = Tcl_DuplicateObj(cmdObj); + } + Tcl_IncrRefCount(cmdObj); + } + callbackInfo->cmdObj = cmdObj; + callbackInfo->interp = interp; + callbackInfo->multiple = multiple; + parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window); + if (haveParentOption && parent && ![parent attachedSheet]) { + [panel beginSheetForDirectory:directory file:filename types:fileTypes + modalForWindow:parent modalDelegate:NSApp didEndSelector: + @selector(tkFilePanelDidEnd:returnCode:contextInfo:) + contextInfo:callbackInfo]; + returnCode = cmdObj ? NSAlertOtherReturn : + [NSApp runModalForWindow:panel]; + } else { + returnCode = [panel runModalForDirectory:directory file:filename + types:fileTypes]; + [NSApp tkFilePanelDidEnd:panel returnCode:returnCode + contextInfo:callbackInfo]; } - if (message) { - CFRelease(message); + result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR; + if (typeVariablePtr && result == TCL_OK) { + Tcl_SetVar(interp, Tcl_GetString(typeVariablePtr), "", 0); } +end: + TkFreeFileFilters(&fl); return result; } - + /* *---------------------------------------------------------------------- * * Tk_GetSaveFileObjCmd -- * - * Same as Tk_GetOpenFileCmd but opens a "save file" dialog box instead. + * This procedure implements the "save file" dialog box for the Mac + * platform. See the user documentation for details on what it does. * * Results: * A standard Tcl result. @@ -418,115 +521,148 @@ Tk_GetSaveFileObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - int i, result = TCL_ERROR; - char *initialFile = NULL; - Tk_Window parent = NULL; - AEDesc initialDesc = {typeNull, NULL}; - AEDesc *initialPtr = NULL; - FSRef dirRef; - CFStringRef title = NULL, message = NULL; - OpenFileData ofd; - static const char *const 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(); - } - - TkInitFileFilters(&ofd.fl); - ofd.curType = 0; - ofd.usePopup = 0; - + Tk_Window tkwin = clientData; + char *str; + int i, result = TCL_ERROR, haveParentOption = 0; + int index, len; + FileFilterList fl; + Tcl_Obj *cmdObj = NULL; + FilePanelCallbackInfo callbackInfoStruct; + FilePanelCallbackInfo *callbackInfo = &callbackInfoStruct; + NSString *directory = nil, *filename = nil, *defaultType = nil; + NSString *message, *title, *type; + NSWindow *parent; + NSMutableArray *fileTypes = nil; + NSSavePanel *panel = [NSSavePanel savePanel]; + NSInteger returnCode = NSAlertErrorReturn; + + TkInitFileFilters(&fl); for (i = 1; i < objc; i += 2) { - char *choice, *string; - int index, choiceLen; - Tcl_Obj *types; - if (Tcl_GetIndexFromObj(interp, objv[i], saveOptionStrings, "option", TCL_EXACT, &index) != TCL_OK) { goto end; } if (i + 1 == objc) { - string = Tcl_GetString(objv[i]); - Tcl_AppendResult(interp, "value for \"", string, "\" missing", + str = Tcl_GetString(objv[i]); + Tcl_AppendResult(interp, "value for \"", str, "\" missing", NULL); goto end; } switch (index) { case SAVE_DEFAULT: + str = Tcl_GetStringFromObj(objv[i + 1], &len); + while (*str && (*str == '*' || *str == '.')) { + str++; + } + if (*str) { + defaultType = [[[NSString alloc] initWithUTF8String:str] + autorelease]; + } break; case SAVE_FILETYPES: - types = objv[i + 1]; - if (TkGetFileFilters(interp, &ofd.fl, types, 0) != TCL_OK) { + if (TkGetFileFilters(interp, &fl, objv[i + 1], 0) != TCL_OK) { goto end; } break; case SAVE_INITDIR: - choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - /* empty strings should be like no selection given */ - if (choiceLen && HandleInitialDirectory(interp, NULL, choice, - &dirRef, NULL, &initialDesc) != TCL_OK) { - goto end; + str = Tcl_GetStringFromObj(objv[i + 1], &len); + if (len) { + directory = [[[NSString alloc] initWithUTF8String:str] + autorelease]; } break; case SAVE_INITFILE: - initialFile = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - /* empty strings should be like no selection given */ - if (choiceLen == 0) { - initialFile = NULL; + str = Tcl_GetStringFromObj(objv[i + 1], &len); + if (len) { + filename = [[[NSString alloc] initWithUTF8String:str] + autorelease]; } break; case SAVE_MESSAGE: - choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - if (message) { - CFRelease(message); - } - message = CFStringCreateWithBytes(NULL, (unsigned char *) choice, - choiceLen, kCFStringEncodingUTF8, false); + message = [[NSString alloc] initWithUTF8String: + Tcl_GetString(objv[i + 1])]; + [panel setMessage:message]; + [message release]; break; case SAVE_PARENT: - choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - parent = Tk_NameToWindow(interp, choice, (Tk_Window) clientData); - if (parent == NULL) { + str = Tcl_GetStringFromObj(objv[i + 1], &len); + tkwin = Tk_NameToWindow(interp, str, tkwin); + if (!tkwin) { goto end; } + haveParentOption = 1; break; case SAVE_TITLE: - choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - if (title) { - CFRelease(title); - } - title = CFStringCreateWithBytes(NULL, (unsigned char *) choice, - choiceLen, kCFStringEncodingUTF8, false); + title = [[NSString alloc] initWithUTF8String: + Tcl_GetString(objv[i + 1])]; + [panel setTitle:title]; + [title release]; + break; + case SAVE_TYPEVARIABLE: + break; + case SAVE_COMMAND: + cmdObj = objv[i+1]; break; } } - - if (initialDesc.descriptorType == typeFSRef) { - initialPtr = &initialDesc; - } - result = NavServicesGetFile(interp, &ofd, initialPtr, initialFile, NULL, - title, message, NULL, false, SAVE_FILE, parent); - TkFreeFileFilters(&ofd.fl); - end: - if (initialDesc.dataHandle) { - ChkErr(AEDisposeDesc, &initialDesc); - } - if (title) { - CFRelease(title); - } - if (message) { - CFRelease(message); + if (fl.filters || defaultType) { + fileTypes = [NSMutableArray array]; + [fileTypes addObject:defaultType ? defaultType : (id)kUTTypeContent]; + for (FileFilter *filterPtr = fl.filters; filterPtr; + filterPtr = filterPtr->next) { + for (FileFilterClause *clausePtr = filterPtr->clauses; clausePtr; + clausePtr = clausePtr->next) { + for (GlobPattern *globPtr = clausePtr->patterns; globPtr; + globPtr = globPtr->next) { + str = globPtr->pattern; + while (*str && (*str == '*' || *str == '.')) { + str++; + } + if (*str) { + type = [[NSString alloc] initWithUTF8String:str]; + if (![fileTypes containsObject:type]) { + [fileTypes addObject:type]; + } + [type release]; + } + } + } + } + [panel setAllowedFileTypes:fileTypes]; + [panel setAllowsOtherFileTypes:YES]; + } + [panel setCanSelectHiddenExtension:YES]; + [panel setExtensionHidden:NO]; + if (cmdObj) { + callbackInfo = (FilePanelCallbackInfo *) + ckalloc(sizeof(FilePanelCallbackInfo)); + if (Tcl_IsShared(cmdObj)) { + cmdObj = Tcl_DuplicateObj(cmdObj); + } + Tcl_IncrRefCount(cmdObj); + } + callbackInfo->cmdObj = cmdObj; + callbackInfo->interp = interp; + callbackInfo->multiple = 0; + parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window); + if (haveParentOption && parent && ![parent attachedSheet]) { + [panel beginSheetForDirectory:directory file:filename + modalForWindow:parent modalDelegate:NSApp didEndSelector: + @selector(tkFilePanelDidEnd:returnCode:contextInfo:) + contextInfo:callbackInfo]; + returnCode = cmdObj ? NSAlertOtherReturn : + [NSApp runModalForWindow:panel]; + } else { + returnCode = [panel runModalForDirectory:directory file:filename]; + [NSApp tkFilePanelDidEnd:panel returnCode:returnCode + contextInfo:callbackInfo]; } + result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR; +end: + TkFreeFileFilters(&fl); return result; } - + /* *---------------------------------------------------------------------- * @@ -552,184 +688,107 @@ Tk_ChooseDirectoryObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - int i, result = TCL_ERROR; - Tk_Window parent = NULL; - AEDesc initialDesc = {typeNull, NULL}, *initialPtr = NULL; - FSRef dirRef; - CFStringRef message = NULL, title = NULL; - OpenFileData ofd; - static const char *const chooseOptionStrings[] = { - "-initialdir", "-message", "-mustexist", "-parent", "-title", NULL - }; - enum chooseOptions { - CHOOSE_INITDIR, CHOOSE_MESSAGE, CHOOSE_MUSTEXIST, CHOOSE_PARENT, - CHOOSE_TITLE - }; - - if (!fileDlgInited) { - InitFileDialogs(); - } + Tk_Window tkwin = clientData; + char *str; + int i, result = TCL_ERROR, haveParentOption = 0; + int index, len, mustexist = 0; + Tcl_Obj *cmdObj = NULL; + FilePanelCallbackInfo callbackInfoStruct; + FilePanelCallbackInfo *callbackInfo = &callbackInfoStruct; + NSString *directory = nil, *filename = nil; + NSString *message, *title; + NSWindow *parent; + NSOpenPanel *panel = [NSOpenPanel openPanel]; + NSInteger returnCode = NSAlertErrorReturn; for (i = 1; i < objc; i += 2) { - char *string, *choice; - int index, choiceLen; - if (Tcl_GetIndexFromObj(interp, objv[i], chooseOptionStrings, "option", TCL_EXACT, &index) != TCL_OK) { goto end; } if (i + 1 == objc) { - string = Tcl_GetString(objv[i]); - Tcl_AppendResult(interp, "value for \"", string, "\" missing", - NULL); + str = Tcl_GetString(objv[i]); + Tcl_AppendResult(interp, "value for \"", str, "\" missing", NULL); goto end; } switch (index) { case CHOOSE_INITDIR: - choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - if (choiceLen && HandleInitialDirectory(interp, NULL, choice, - &dirRef, NULL, &initialDesc) != TCL_OK) { - goto end; + str = Tcl_GetStringFromObj(objv[i + 1], &len); + if (len) { + directory = [[[NSString alloc] initWithUTF8String:str] + autorelease]; } break; case CHOOSE_MESSAGE: - choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - if (message) { - CFRelease(message); + message = [[NSString alloc] initWithUTF8String: + Tcl_GetString(objv[i + 1])]; + [panel setMessage:message]; + [message release]; + break; + case CHOOSE_MUSTEXIST: + if (Tcl_GetBooleanFromObj(interp, objv[i + 1], + &mustexist) != TCL_OK) { + goto end; } - 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, clientData); - if (parent == NULL) { + str = Tcl_GetStringFromObj(objv[i + 1], &len); + tkwin = Tk_NameToWindow(interp, str, tkwin); + if (!tkwin) { goto end; } + haveParentOption = 1; break; case CHOOSE_TITLE: - choice = Tcl_GetStringFromObj(objv[i + 1], &choiceLen); - if (title) { - CFRelease(title); - } - title = CFStringCreateWithBytes(NULL, (unsigned char *) choice, - choiceLen, kCFStringEncodingUTF8, false); + title = [[NSString alloc] initWithUTF8String: + Tcl_GetString(objv[i + 1])]; + [panel setTitle:title]; + [title release]; + break; + case CHOOSE_COMMAND: + cmdObj = objv[i+1]; 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, parent); - TkFreeFileFilters(&ofd.fl); - end: - if (initialDesc.dataHandle) { - ChkErr(AEDisposeDesc, &initialDesc); - } - if (title) { - CFRelease(title); - } - if (message) { - CFRelease(message); - } - return result; -} - -/* - *---------------------------------------------------------------------- - * - * HandleInitialDirectory -- - * - * Helper for -initialdir setup. - * - * Results: - * Tcl result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -HandleInitialDirectory( - Tcl_Interp *interp, - char *initialFile, - char *initialDir, - FSRef *dirRef, - AEDescList *selectDescPtr, - AEDesc *dirDescPtr) -{ - Tcl_DString ds; - OSStatus err; - Boolean isDirectory; - char *dirName = NULL; - int result = TCL_ERROR; - - if (initialDir) { - dirName = Tcl_TranslateFileName(interp, initialDir, &ds); - if (dirName == NULL) { - goto end; - } - err = ChkErr(FSPathMakeRef, (unsigned char *) dirName, dirRef, - &isDirectory); - if (err != noErr) { - Tcl_AppendResult(interp, "bad directory \"", initialDir, "\"", - NULL); - goto end; - } - if (!isDirectory) { - Tcl_AppendResult(interp, "-intialdir \"", initialDir, "\"" - " is a file, not a directory.", NULL); - goto end; - } - ChkErr(AECreateDesc, typeFSRef, dirRef, sizeof(*dirRef), dirDescPtr); - } - - if (initialFile && selectDescPtr) { - FSRef fileRef; - AEDesc fileDesc; - char *namePtr; - - if (initialDir) { - Tcl_DStringAppend(&ds, "/", 1); - Tcl_DStringAppend(&ds, initialFile, -1); - namePtr = Tcl_DStringValue(&ds); - } else { - namePtr = initialFile; - } - - ChkErr(AECreateList, NULL, 0, false, selectDescPtr); - - err = ChkErr(FSPathMakeRef, (unsigned char *) namePtr, &fileRef, - &isDirectory); - if (err != noErr) { - Tcl_AppendResult(interp, "bad initialfile \"", initialFile, - "\" file does not exist.", NULL); - goto end; + [panel setPrompt:@"Choose"]; + [panel setCanChooseFiles:NO]; + [panel setCanChooseDirectories:YES]; + [panel setCanCreateDirectories:!mustexist]; + if (cmdObj) { + callbackInfo = (FilePanelCallbackInfo *) + ckalloc(sizeof(FilePanelCallbackInfo)); + if (Tcl_IsShared(cmdObj)) { + cmdObj = Tcl_DuplicateObj(cmdObj); } - ChkErr(AECreateDesc, typeFSRef, &fileRef, sizeof(fileRef), &fileDesc); - ChkErr(AEPutDesc, selectDescPtr, 1, &fileDesc); - ChkErr(AEDisposeDesc, &fileDesc); - } - result = TCL_OK; - end: - if (dirName) { - Tcl_DStringFree(&ds); + Tcl_IncrRefCount(cmdObj); + } + callbackInfo->cmdObj = cmdObj; + callbackInfo->interp = interp; + callbackInfo->multiple = 0; + parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window); + if (haveParentOption && parent && ![parent attachedSheet]) { + [panel beginSheetForDirectory:directory file:filename + modalForWindow:parent modalDelegate:NSApp didEndSelector: + @selector(tkFilePanelDidEnd:returnCode:contextInfo:) + contextInfo:callbackInfo]; + returnCode = cmdObj ? NSAlertOtherReturn : + [NSApp runModalForWindow:panel]; + } else { + returnCode = [panel runModalForDirectory:directory file:filename]; + [NSApp tkFilePanelDidEnd:panel returnCode:returnCode + contextInfo:callbackInfo]; } + result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR; +end: return result; } - + /* *---------------------------------------------------------------------- * - * InitFileDialogs -- + * TkAboutDlg -- * - * Initialize file dialog subsystem. + * Displays the default Tk About box. * * Results: * None. @@ -741,632 +800,76 @@ HandleInitialDirectory( */ void -InitFileDialogs(void) -{ - fileDlgInited = 1; - openFileFilterUPP = NewNavObjectFilterUPP(OpenFileFilterProc); - openFileEventUPP = NewNavEventUPP(OpenEventProc); -} - -/* - *---------------------------------------------------------------------- - * - * NavServicesGetFile -- - * - * Common wrapper for NavServices API. - * - * Results: - * Tcl result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -NavServicesGetFile( - Tcl_Interp *interp, - OpenFileData *ofdPtr, - AEDesc *initialDescPtr, - char *initialFile, - AEDescList *selectDescPtr, - CFStringRef title, - CFStringRef message, - const char *initialtype, - int multiple, - int isOpen, - Tk_Window parent) +TkAboutDlg(void) { - NavHandlerUserData data; - NavDialogCreationOptions options; - NavDialogRef dialogRef = NULL; - CFStringRef *menuItemNames = NULL; - OSStatus err; - Tcl_Obj *theResult = NULL; - int result = TCL_ERROR; - - bzero(&data, sizeof(data)); - err = NavGetDefaultDialogCreationOptions(&options); - if (err != noErr) { - return result; - } - options.optionFlags = kNavDontAutoTranslate | kNavDontAddTranslateItems - | kNavSupportPackages | kNavAllFilesInPopup; - if (multiple) { - options.optionFlags |= kNavAllowMultipleFiles; - } - options.modality = kWindowModalityAppModal; - if (parent && ((TkWindow *) parent)->window != None && - TkMacOSXHostToplevelExists(parent)) { - options.parentWindow = TkMacOSXDrawableWindow(Tk_WindowId(parent)); - TK_IF_HI_TOOLBOX (5, - /* - * Impossible to modify dialog modality with the Cocoa-based - * NavServices implementation. - */ - ) TK_ELSE_HI_TOOLBOX (5, - if (options.parentWindow) { - options.modality = kWindowModalityWindowModal; - data.sheet = 1; - } - ) TK_ENDIF - } - - /* - * Now process the selection list. We have to use the popupExtension - * to fill the menu. - */ - - if (ofdPtr && ofdPtr->usePopup) { - FileFilter *filterPtr = ofdPtr->fl.filters; - - if (filterPtr == NULL) { - ofdPtr->usePopup = 0; - } - } - if (ofdPtr && 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; - } - } - options.popupExtension = CFArrayCreate(NULL, - (const void **) menuItemNames, ofdPtr->fl.numFilters, NULL); - } else { - options.optionFlags |= kNavNoTypePopup; - options.popupExtension = NULL; - } - options.clientName = CFSTR("Wish"); - options.message = message; - options.windowTitle = title; - if (initialFile) { - options.saveFileName = CFStringCreateWithCString(NULL, initialFile, - kCFStringEncodingUTF8); + NSImage *image; + NSString *path = [NSApp tkFrameworkImagePath:@"Tk.tiff"]; + if (path) { + image = [[[NSImage alloc] initWithContentsOfFile:path] autorelease]; } else { - options.saveFileName = NULL; - } - if (isOpen == OPEN_FILE) { - data.ofdPtr = ofdPtr; - err = ChkErr(NavCreateGetFileDialog, &options, NULL, - openFileEventUPP, NULL, openFileFilterUPP, &data, &dialogRef); - } else if (isOpen == SAVE_FILE) { - err = ChkErr(NavCreatePutFileDialog, &options, 'TEXT', 'WIsH', - openFileEventUPP, &data, &dialogRef); - } else if (isOpen == CHOOSE_FOLDER) { - err = ChkErr(NavCreateChooseFolderDialog, &options, - openFileEventUPP, openFileFilterUPP, &data, &dialogRef); - } - if (err == noErr && dialogRef) { - if (initialDescPtr) { - ChkErr(NavCustomControl, dialogRef, kNavCtlSetLocation, - initialDescPtr); - } - if (selectDescPtr && selectDescPtr->descriptorType != typeNull) { - ChkErr(NavCustomControl, dialogRef, kNavCtlSetSelection, - selectDescPtr); - } - TkMacOSXTrackingLoop(1); - err = ChkErr(NavDialogRun, dialogRef); - if (err == noErr) { - if (data.sheet) { - data.dialogWindow = NavDialogGetWindow(dialogRef); - ChkErr(GetWindowModality, data.dialogWindow, - &data.origModality, &data.origUnavailWindow); - ChkErr(SetWindowModality, data.dialogWindow, - kWindowModalityAppModal, NULL); - ChkErr(RunAppModalLoopForWindow, data.dialogWindow); - } - err = data.err; - } - TkMacOSXTrackingLoop(0); - } - - /* - * 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 (err == noErr && data.reply.validRecord) { - AEDesc resultDesc; - long count, i; - FSRef fsRef; - char pathPtr[PATH_MAX + 1]; - char saveName[PATH_MAX + 1]; - - err = ChkErr(AECountItems, &data.reply.selection, &count); - if (err != noErr) { - /* - * There was an error when counting the items? Treat as if no - * items were chosen. - */ - - goto installResult; - } - - /* - * Process the chosen files. This will be one unless -multiple was - * specified. - */ - - for (i = 1; i <= count; i++) { - /* - * Get the name of the selected file. - */ - - err = ChkErr(AEGetNthDesc, &data.reply.selection, i, - typeFSRef, NULL, &resultDesc); - if (err != noErr) { - continue; - } - err = ChkErr(AEGetDescData, &resultDesc, &fsRef, sizeof(fsRef)); - if (err != noErr) { - goto nextFilename; - } - err = ChkErr(FSRefMakePath, &fsRef, (unsigned char *) pathPtr, - PATH_MAX + 1); - if (err != noErr) { - goto nextFilename; - } - - /* - * If we're saving the file, we're creating a new filename and - * must therefore check whether it is a legal filename (not - * exceeding path length limits, etc.) - */ - - if (isOpen == SAVE_FILE) { - if (!data.saveNameRef) { - TkMacOSXDbgMsg("NavDialogGetSaveFileName failed"); - goto nextFilename; - } - - if (!CFStringGetCString(data.saveNameRef, saveName, - PATH_MAX + 1, kCFStringEncodingUTF8)) { - TkMacOSXDbgMsg("CFStringGetCString failed"); - goto nextFilename; - } - - if (strlen(pathPtr) + strlen(saveName) >= PATH_MAX) { - TkMacOSXDbgMsg("Path name too long"); - goto nextFilename; - } - - strcat(pathPtr, "/"); - strcat(pathPtr, saveName); - } - - /* - * Got a valid file name; put it in the result object. - */ - - if (multiple) { - Tcl_ListObjAppendElement(interp, theResult, - Tcl_NewStringObj(pathPtr, -1)); - } else { - Tcl_SetStringObj(theResult, pathPtr, -1); - } - - nextFilename: - ChkErr(AEDisposeDesc, &resultDesc); - } - - installResult: - Tcl_SetObjResult(interp, theResult); - result = TCL_OK; - } else if (err == userCanceledErr) { - Tcl_ResetResult(interp); - result = TCL_OK; - } - - /* - * Clean up any allocated memory. - */ - - if (data.reply.validRecord) { - ChkErr(NavDisposeReply, &data.reply); - } - if (data.saveNameRef) { - CFRelease(data.saveNameRef); - } - if (options.saveFileName) { - CFRelease(options.saveFileName); - } - if (options.clientName) { - CFRelease(options.clientName); - } - if (menuItemNames) { - int i; - - for (i = 0; i < ofdPtr->fl.numFilters; i++) { - CFRelease(menuItemNames[i]); - } - ckfree((void *) menuItemNames); - } - if (options.popupExtension) { - CFRelease(options.popupExtension); - } - return result; + image = [NSApp applicationIconImage]; + } + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [dateFormatter setDateFormat:@"Y"]; + NSString *year = [dateFormatter stringFromDate:[NSDate date]]; + [dateFormatter release]; + NSMutableParagraphStyle *style = [[[NSParagraphStyle defaultParagraphStyle] + mutableCopy] autorelease]; + [style setAlignment:NSCenterTextAlignment]; + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: + @"Tcl & Tk", @"ApplicationName", + @"Tcl " TCL_VERSION " & Tk " TK_VERSION, @"ApplicationVersion", + @TK_PATCH_LEVEL, @"Version", + image, @"ApplicationIcon", + [NSString stringWithFormat:@"Copyright %1$C 1987-%2$@.", 0xA9, + year], @"Copyright", + [[[NSAttributedString alloc] initWithString: + [NSString stringWithFormat: + @"%1$C 1987-%2$@ Tcl Core Team." "\n\n" + "%1$C 2002-%2$@ Daniel A. Steffen." "\n\n" + "%1$C 2001-2009 Apple Inc." "\n\n" + "%1$C 2001-2002 Jim Ingham & Ian Reid" "\n\n" + "%1$C 1998-2000 Jim Ingham & Ray Johnson" "\n\n" + "%1$C 1998-2000 Scriptics Inc." "\n\n" + "%1$C 1996-1997 Sun Microsystems Inc.", 0xA9, year] attributes: + [NSDictionary dictionaryWithObject:style + forKey:NSParagraphStyleAttributeName]] autorelease], @"Credits", + nil]; + [NSApp orderFrontStandardAboutPanelWithOptions:options]; } - -/* - *---------------------------------------------------------------------- - * - * OpenEventProc -- - * - * NavServices event handling callback. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -pascal void -OpenEventProc( - NavEventCallbackMessage callBackSelector, - NavCBRecPtr callBackParams, - NavCallBackUserData callBackUD) -{ - NavHandlerUserData *data = (NavHandlerUserData*) callBackUD; - OpenFileData *ofd = data->ofdPtr; - - switch (callBackSelector) { - case kNavCBStart: - if (ofd && ofd->initialType >= 0) { - /* Select initial filter */ - FileFilter *filterPtr = ofd->fl.filters; - int i = ofd->initialType; - - while (filterPtr && i-- > 0) { - filterPtr = filterPtr->next; - } - if (filterPtr) { - NavMenuItemSpec selectItem; - - selectItem.version = kNavMenuItemSpecVersion; - selectItem.menuCreator = 0; - selectItem.menuType = ofd->initialType; - selectItem.menuItemName[0] = strlen(filterPtr->name); - strncpy((char *) &selectItem.menuItemName[1], - filterPtr->name, 255); - ChkErr(NavCustomControl, callBackParams->context, - kNavCtlSelectCustomType, &selectItem); - } - } - break; - case kNavCBPopupMenuSelect: - ofd->curType = ((NavMenuItemSpec *) - callBackParams->eventData.eventDataParms.param)->menuType; - break; - case kNavCBAccept: - case kNavCBCancel: - if (data->sheet) { - ChkErr(QuitAppModalLoopForWindow, data->dialogWindow); - ChkErr(SetWindowModality, data->dialogWindow, - data->origModality, data->origUnavailWindow); - } - break; - case kNavCBUserAction: - if (data->reply.validRecord) { - ChkErr(NavDisposeReply, &data->reply); - data->reply.validRecord = 0; - } - data->err = NavDialogGetReply(callBackParams->context, - &data->reply); - if (callBackParams->userAction == kNavUserActionSaveAs) { - data->saveNameRef = NavDialogGetSaveFileName( - callBackParams->context); - if (data->saveNameRef) { - CFRetain(data->saveNameRef); - } - } - break; - case kNavCBTerminate: - NavDialogDispose(callBackParams->context); - break; - case kNavCBEvent: - TkMacOSXRunTclEventLoop(); - break; - } -} - -/* - *---------------------------------------------------------------------- - * - * OpenFileFilterProc -- - * - * NavServices file filter callback. - * - * Results: - * Whether to use the file in question. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -pascal Boolean -OpenFileFilterProc( - AEDesc *theItem, - void *info, - NavCallBackUserData callBackUD, - NavFilterModes filterMode) -{ - OpenFileData *ofdPtr = ((NavHandlerUserData *) callBackUD)->ofdPtr; - int result = MATCHED; - - if (ofdPtr && ofdPtr->usePopup && ofdPtr->fl.numFilters > 0 && - ((theItem->descriptorType == typeFSS) - || (theItem->descriptorType == typeFSRef))) { - NavFileOrFolderInfo *theInfo = info; - char fileName[256]; - OSType fileType; - StringPtr fileNamePtr = NULL; - Tcl_DString fileNameDString; - int i; - FileFilter *filterPtr; - - if (!theInfo->isFolder) { - 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 = ChkErr(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); - } - } - 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 = UNMATCHED; - } - } 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); -} - -/* - *---------------------------------------------------------------------- - * - * 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 - * - *---------------------------------------------------------------------- - */ - -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; - } - 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 -- + * TkMacOSXStandardAboutPanelObjCmd -- * - * Displays the default Tk About box. This code uses Macintosh resources - * to define the content of the About Box. + * Implements the ::tk::mac::standardAboutPanel command. * * Results: - * None. + * A standard Tcl result. * * Side effects: - * None. + * none * *---------------------------------------------------------------------- */ -void -TkAboutDlg(void) +int +TkMacOSXStandardAboutPanelObjCmd( + ClientData clientData, /* Unused. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { - DialogPtr aboutDlog; - WindowRef windowRef; - short itemHit = -9; - - aboutDlog = GetNewDialog(TK_DEFAULT_ABOUT, NULL, (void *) (-1)); - if (!aboutDlog) { - return; + if (objc > 1) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return TCL_ERROR; } - windowRef = GetDialogWindow(aboutDlog); - SelectWindow(windowRef); - TkMacOSXTrackingLoop(1); - while (itemHit != 1) { - ModalDialog(NULL, &itemHit); - } - TkMacOSXTrackingLoop(0); - DisposeDialog(aboutDlog); - SelectWindow(ActiveNonFloatingWindow()); + [NSApp orderFrontStandardAboutPanelWithOptions:nil]; + return TCL_OK; } - + /* *---------------------------------------------------------------------- * @@ -1391,103 +894,30 @@ Tk_MessageBoxObjCmd( Tcl_Obj *const objv[]) /* Argument objects. */ { Tk_Window tkwin = clientData; - AlertStdCFStringAlertParamRec paramCFStringRec; - AlertType alertType; - DialogRef dialogRef; - CFStringRef messageTextCF = NULL, finemessageTextCF = NULL; - OSStatus err; - SInt16 itemHit; - Boolean haveDefaultOption = false, haveParentOption = false; char *str; - int index, defaultButtonIndex; - int defaultNativeButtonIndex; /* 1, 2, 3: right to left */ - int typeIndex, i, indexDefaultOption = 0, result = TCL_ERROR; - - static const char *const movableAlertStrings[] = { - "-default", "-detail", "-icon", "-message", "-parent", "-title", - "-type", NULL - }; - static const char *const movableTypeStrings[] = { - "abortretryignore", "ok", "okcancel", "retrycancel", "yesno", - "yesnocancel", NULL - }; - static const char *const movableButtonStrings[] = { - "abort", "retry", "ignore", "ok", "cancel", "yes", "no", NULL - }; - static const char *const movableIconStrings[] = { - "error", "info", "question", "warning", 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; + int i, result = TCL_ERROR, haveParentOption = 0; + int index, typeIndex, iconIndex, indexDefaultOption = 0; + int defaultNativeButtonIndex = 1; /* 1, 2, 3: right to left */ + Tcl_Obj *cmdObj = NULL; + AlertCallbackInfo callbackInfoStruct, *callbackInfo = &callbackInfoStruct; + NSString *message, *title; + NSWindow *parent; + NSArray *buttons; + NSAlert *alert = [NSAlert new]; + NSInteger returnCode = NSAlertErrorReturn; + + iconIndex = ICON_INFO; typeIndex = TYPE_OK; - - ChkErr(GetStandardAlertDefaultParams, ¶mCFStringRec, - kStdCFStringAlertVersionOne); - paramCFStringRec.movable = true; - paramCFStringRec.helpButton = false; - paramCFStringRec.defaultButton = kAlertStdAlertOKButton; - paramCFStringRec.cancelButton = kAlertStdAlertCancelButton; - for (i = 1; i < objc; i += 2) { - int iconIndex; - char *string; - - if (Tcl_GetIndexFromObj(interp, objv[i], movableAlertStrings, "option", + if (Tcl_GetIndexFromObj(interp, objv[i], alertOptionStrings, "option", TCL_EXACT, &index) != TCL_OK) { goto end; } if (i + 1 == objc) { - string = Tcl_GetString(objv[i]); - Tcl_AppendResult(interp, "value for \"", string, "\" missing", - NULL); + str = Tcl_GetString(objv[i]); + Tcl_AppendResult(interp, "value for \"", str, "\" missing", NULL); goto end; } - switch (index) { case ALERT_DEFAULT: /* @@ -1495,111 +925,65 @@ Tk_MessageBoxObjCmd( * know the '-type' as well. */ - haveDefaultOption = true; indexDefaultOption = i; break; case ALERT_DETAIL: - str = Tcl_GetString(objv[i + 1]); - if (finemessageTextCF) { - CFRelease(finemessageTextCF); - } - finemessageTextCF = CFStringCreateWithCString(NULL, str, - kCFStringEncodingUTF8); + message = [[NSString alloc] initWithUTF8String: + Tcl_GetString(objv[i + 1])]; + [alert setInformativeText:message]; + [message release]; break; case ALERT_ICON: - if (Tcl_GetIndexFromObj(interp, objv[i + 1], movableIconStrings, + if (Tcl_GetIndexFromObj(interp, objv[i + 1], alertIconStrings, "value", TCL_EXACT, &iconIndex) != TCL_OK) { 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_GetString(objv[i + 1]); - if (messageTextCF) { - CFRelease(messageTextCF); - } - messageTextCF = CFStringCreateWithCString(NULL, str, - kCFStringEncodingUTF8); + message = [[NSString alloc] initWithUTF8String: + Tcl_GetString(objv[i + 1])]; + [alert setMessageText:message]; + [message release]; break; case ALERT_PARENT: str = Tcl_GetString(objv[i + 1]); tkwin = Tk_NameToWindow(interp, str, tkwin); - if (tkwin == NULL) { + if (!tkwin) { goto end; } - if (((TkWindow *) tkwin)->window != None && - TkMacOSXHostToplevelExists(tkwin)) { - haveParentOption = true; - } + haveParentOption = 1; break; case ALERT_TITLE: - /* TODO: message box title missing? */ + title = [[NSString alloc] initWithUTF8String: + Tcl_GetString(objv[i + 1])]; + [[alert window] setTitle:title]; + [title release]; break; case ALERT_TYPE: - if (Tcl_GetIndexFromObj(interp, objv[i + 1], movableTypeStrings, + if (Tcl_GetIndexFromObj(interp, objv[i + 1], alertTypeStrings, "value", TCL_EXACT, &typeIndex) != TCL_OK) { goto end; } - switch (typeIndex) { - case TYPE_ABORTRETRYIGNORE: - paramCFStringRec.defaultText = CFSTR("Abort"); - paramCFStringRec.cancelText = CFSTR("Retry"); - paramCFStringRec.otherText = CFSTR("Ignore"); - paramCFStringRec.cancelButton = kAlertStdAlertOtherButton; - 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"); - paramCFStringRec.cancelButton = kAlertStdAlertOtherButton; - break; - } + break; + case ALERT_COMMAND: + cmdObj = objv[i+1]; break; } } - - if (haveDefaultOption) { + if (indexDefaultOption) { /* * Any '-default' option needs to know the '-type' option, which is why * we do this here. */ if (Tcl_GetIndexFromObj(interp, objv[indexDefaultOption + 1], - movableButtonStrings, "value", TCL_EXACT, &defaultButtonIndex) + alertButtonStrings, "value", TCL_EXACT, &index) != TCL_OK) { goto end; } @@ -1609,138 +993,56 @@ Tk_MessageBoxObjCmd( */ defaultNativeButtonIndex = - buttonIndexAndTypeToNativeButtonIndex[typeIndex][defaultButtonIndex]; - if (defaultNativeButtonIndex == 0) { + alertButtonIndexAndTypeToNativeButtonIndex[typeIndex][index]; + if (!defaultNativeButtonIndex) { Tcl_SetObjResult(interp, Tcl_NewStringObj("Illegal default option", -1)); goto end; } - paramCFStringRec.defaultButton = defaultNativeButtonIndex; - if (paramCFStringRec.cancelButton == defaultNativeButtonIndex) { - paramCFStringRec.cancelButton = 0; - } } - ChkErr(SetThemeCursor, kThemeArrowCursor); - - if (haveParentOption) { - AlertHandlerUserData data; - static EventHandlerUPP handler = NULL; - WindowRef windowRef; - const EventTypeSpec kEvents[] = { - {kEventClassCommand, kEventProcessCommand} - }; - - bzero(&data, sizeof(data)); - if (!handler) { - handler = NewEventHandlerUPP(AlertHandler); + [alert setIcon:[NSApp applicationIconImage]]; + [alert setAlertStyle:alertStyles[iconIndex]]; + i = 0; + while (i < 3 && alertButtonNames[typeIndex][i]) { + [alert addButtonWithTitle:(NSString*)alertButtonNames[typeIndex][i++]]; + } + buttons = [alert buttons]; + for (NSButton *b in buttons) { + NSString *ke = [b keyEquivalent]; + if (([ke isEqualToString:@"\r"] || [ke isEqualToString:@"\033"]) && + ![b keyEquivalentModifierMask]) { + [b setKeyEquivalent:@""]; } - windowRef = TkMacOSXDrawableWindow(Tk_WindowId(tkwin)); - if (!windowRef) { - goto end; - } - err = ChkErr(CreateStandardSheet, alertType, messageTextCF, - finemessageTextCF, ¶mCFStringRec, NULL, &dialogRef); - if(err != noErr) { - goto end; - } - data.dialogWindow = GetDialogWindow(dialogRef); - err = ChkErr(ShowSheetWindow, data.dialogWindow, windowRef); - if(err != noErr) { - DisposeDialog(dialogRef); - goto end; + } + [[buttons objectAtIndex:[buttons count]-1] setKeyEquivalent:@"\033"]; + [[buttons objectAtIndex:defaultNativeButtonIndex-1] setKeyEquivalent:@"\r"]; + if (cmdObj) { + callbackInfo = (AlertCallbackInfo *) ckalloc(sizeof(AlertCallbackInfo)); + if (Tcl_IsShared(cmdObj)) { + cmdObj = Tcl_DuplicateObj(cmdObj); } - ChkErr(GetWindowModality, data.dialogWindow, &data.origModality, - &data.origUnavailWindow); - ChkErr(SetWindowModality, data.dialogWindow, kWindowModalityAppModal, - NULL); - ChkErr(InstallEventHandler, GetWindowEventTarget(data.dialogWindow), - handler, GetEventTypeCount(kEvents), kEvents, &data, - &data.handlerRef); - TkMacOSXTrackingLoop(1); - ChkErr(RunAppModalLoopForWindow, data.dialogWindow); - TkMacOSXTrackingLoop(0); - itemHit = data.buttonIndex; + Tcl_IncrRefCount(cmdObj); + } + callbackInfo->cmdObj = cmdObj; + callbackInfo->interp = interp; + callbackInfo->typeIndex = typeIndex; + parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window); + if (haveParentOption && parent && ![parent attachedSheet]) { + [alert beginSheetModalForWindow:parent modalDelegate:NSApp + didEndSelector:@selector(tkAlertDidEnd:returnCode:contextInfo:) + contextInfo:callbackInfo]; + returnCode = cmdObj ? NSAlertOtherReturn : + [NSApp runModalForWindow:[alert window]]; } else { - err = ChkErr(CreateStandardAlert, alertType, messageTextCF, - finemessageTextCF, ¶mCFStringRec, &dialogRef); - if(err != noErr) { - goto end; - } - TkMacOSXTrackingLoop(1); - err = ChkErr(RunStandardAlert, dialogRef, NULL, &itemHit); - TkMacOSXTrackingLoop(0); - if (err != noErr) { - goto end; - } - } - if (err == noErr) { - /* - * Map 'itemHit' (1, 2, 3) to descriptive text string. - */ - - int ind = nativeButtonIndexAndTypeToButtonIndex[typeIndex][itemHit]; - - Tcl_SetObjResult(interp, Tcl_NewStringObj(movableButtonStrings[ind], - -1)); - result = TCL_OK; - } - - end: - if (finemessageTextCF) { - CFRelease(finemessageTextCF); - } - if (messageTextCF) { - CFRelease(messageTextCF); + returnCode = [alert runModal]; + [NSApp tkAlertDidEnd:alert returnCode:returnCode + contextInfo:callbackInfo]; } + result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR; +end: + [alert release]; return result; } - -/* - *---------------------------------------------------------------------- - * - * AlertHandler -- - * - * Carbon event handler for the Standard Sheet dialog. - * - * Results: - * OSStatus if event handled or not. - * - * Side effects: - * May set userData. - * - *---------------------------------------------------------------------- - */ - -OSStatus -AlertHandler( - EventHandlerCallRef callRef, - EventRef eventRef, - void *userData) -{ - AlertHandlerUserData *data = userData; - HICommand cmd; - - ChkErr(GetEventParameter,eventRef, kEventParamDirectObject, typeHICommand, - NULL, sizeof(cmd), NULL, &cmd); - switch (cmd.commandID) { - case kHICommandOK: - data->buttonIndex = 1; - break; - case kHICommandCancel: - data->buttonIndex = 2; - break; - case kHICommandOther: - data->buttonIndex = 3; - break; - } - if (data->buttonIndex) { - ChkErr(QuitAppModalLoopForWindow, data->dialogWindow); - ChkErr(RemoveEventHandler, data->handlerRef); - ChkErr(SetWindowModality, data->dialogWindow, - data->origModality, data->origUnavailWindow); - } - return eventNotHandledErr; -} /* *---------------------------------------------------------------------- @@ -1758,7 +1060,9 @@ typedef struct FontchooserData { Tcl_Obj *cmdObj; Tk_Window parent; } FontchooserData; +enum FontchooserEvent { FontchooserClosed, FontchooserSelection }; +static void FontchooserEvent(int kind); static Tcl_Obj *FontchooserCget(FontchooserData *fcdPtr, int optionIndex); static int FontchooserConfigureCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); @@ -1778,10 +1082,8 @@ const TkEnsemble tkFontchooserEnsemble[] = { }; static Tcl_Interp *fontchooserInterp = NULL; -static FMFontFamily fontPanelFontFamily = kInvalidFontFamily; -static FMFontStyle fontPanelFontStyle = -1; -static FMFontSize fontPanelFontSize = 0; -static FMFont fontPanelFontID = kInvalidFont; +static NSFont *fontPanelFont = nil; +static NSMutableDictionary *fontPanelFontAttributes = nil; static const char *fontchooserOptionStrings[] = { "-parent", "-title", "-font", "-command", @@ -1791,17 +1093,53 @@ enum FontchooserOption { FontchooserParent, FontchooserTitle, FontchooserFont, FontchooserCmd, FontchooserVisible }; + +@implementation TKApplication(TKFontPanel) +- (void)changeFont:(id)sender { + NSFontManager *fm = [NSFontManager sharedFontManager]; + if ([fm currentFontAction] == NSViaPanelFontAction) { + NSFont *font = [fm convertFont:fontPanelFont]; + if (![fontPanelFont isEqual:font]) { + [fontPanelFont release]; + fontPanelFont = [font retain]; + FontchooserEvent(FontchooserSelection); + } + } +} +- (void)changeAttributes:(id)sender { + NSDictionary *attributes = [sender convertAttributes: + fontPanelFontAttributes]; + if (![fontPanelFontAttributes isEqual:attributes]) { + [fontPanelFontAttributes setDictionary:attributes]; + FontchooserEvent(FontchooserSelection); + } +} +- (NSUInteger) validModesForFontPanel: (NSFontPanel *) fontPanel { + return (NSFontPanelStandardModesMask & ~NSFontPanelAllEffectsModeMask) | + NSFontPanelUnderlineEffectModeMask | + NSFontPanelStrikethroughEffectModeMask; +} +- (void)windowDidOrderOffScreen:(NSNotification *)notification { +#ifdef TK_MAC_DEBUG_NOTIFICATIONS + TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); +#endif + if ([[notification object] isEqual:[[NSFontManager sharedFontManager] + fontPanel:NO]]) { + FontchooserEvent(FontchooserClosed); + } +} +@end /* *---------------------------------------------------------------------- * - * TkMacOSXProcessFontEvent -- + * FontchooserEvent -- * * This processes events generated by user interaction with the * font panel. * * Results: - * True if Tk events are generated - false otherwise. + * None. * * Side effects: * Additional events may be place on the Tk event queue. @@ -1809,73 +1147,27 @@ enum FontchooserOption { *---------------------------------------------------------------------- */ -MODULE_SCOPE int -TkMacOSXProcessFontEvent( - TkMacOSXEvent * eventPtr, - MacEventStatus * statusPtr) +static void +FontchooserEvent( + int kind) { - OSStatus err; - int eventGenerated = 0; FontchooserData *fcdPtr; + Tcl_Obj *fontObj; - switch (eventPtr->eKind) { - case kEventFontPanelClosed: - case kEventFontSelection: - break; - default: - goto done; - } if (!fontchooserInterp) { - goto done; + return; } fcdPtr = Tcl_GetAssocData(fontchooserInterp, "::tk::fontchooser", NULL); - switch (eventPtr->eKind) { - case kEventFontPanelClosed: - if (!FPIsFontPanelVisible() && fcdPtr->parent != None) { + switch (kind) { + case FontchooserClosed: + if (fcdPtr->parent != None) { TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserVisibility"); fontchooserInterp = NULL; - eventGenerated = 1; } break; - case kEventFontSelection: { - Tcl_Obj *fontObj = NULL; - - fontPanelFontFamily = kInvalidFontFamily; - fontPanelFontStyle = -1; - fontPanelFontSize = 0; - fontPanelFontID = kInvalidFont; - err = ChkErr(GetEventParameter, eventPtr->eventRef, - kEventParamFMFontFamily, typeFMFontFamily, NULL, - sizeof(FMFontFamily), NULL, &fontPanelFontFamily); - err |= ChkErr(GetEventParameter, eventPtr->eventRef, - kEventParamFMFontStyle, typeFMFontStyle, NULL, - sizeof(FMFontStyle), NULL, &fontPanelFontStyle); - err |= ChkErr(GetEventParameter, eventPtr->eventRef, - kEventParamFMFontSize, typeFMFontSize, NULL, - sizeof(FMFontSize), NULL, &fontPanelFontSize); - if (err != noErr) { - /* - * No/incomplete QD font spec, use ATSUI font ID - */ - Fixed fontFixedSize; - - err = ChkErr(GetEventParameter, eventPtr->eventRef, - kEventParamATSUFontID, typeATSUFontID, NULL, - sizeof(ATSUFontID), NULL, &fontPanelFontID); - if (err == noErr) { - ChkErr(FMGetFontFamilyInstanceFromFont, fontPanelFontID, - &fontPanelFontFamily, &fontPanelFontStyle); - } - err = ChkErr(GetEventParameter, eventPtr->eventRef, - kEventParamATSUFontSize, typeATSUSize, NULL, - sizeof(Fixed), NULL, &fontFixedSize); - if (err == noErr) { - fontPanelFontSize = FixedToInt(fontFixedSize); - } - } - fontObj = TkMacOSXFontDescriptionForFMFontInfo( - fontPanelFontFamily, fontPanelFontStyle, - fontPanelFontSize, fontPanelFontID); + case FontchooserSelection: + fontObj = TkMacOSXFontDescriptionForNSFontAndNSFontAttributes( + fontPanelFont, fontPanelFontAttributes); if (fontObj) { if (fcdPtr->cmdObj) { int objc, result; @@ -1888,18 +1180,15 @@ TkMacOSXProcessFontEvent( (unsigned)(objc + 2)); memcpy(tmpv, objv, sizeof(Tcl_Obj *) * objc); tmpv[objc] = fontObj; - result = TkBackgroundEvalObjv(fontchooserInterp, - objc + 1, tmpv, TCL_EVAL_GLOBAL); + TkBackgroundEvalObjv(fontchooserInterp, objc + 1, tmpv, + TCL_EVAL_GLOBAL); ckfree((char *)tmpv); } } TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserFontChanged"); } break; - } } -done: - return eventGenerated; } /* @@ -1946,9 +1235,8 @@ FontchooserCget( break; } case FontchooserFont: { - resObj = TkMacOSXFontDescriptionForFMFontInfo( - fontPanelFontFamily, fontPanelFontStyle, - fontPanelFontSize, fontPanelFontID); + resObj = TkMacOSXFontDescriptionForNSFontAndNSFontAttributes( + fontPanelFont, fontPanelFontAttributes); if (!resObj) { resObj = Tcl_NewObj(); } @@ -1963,7 +1251,8 @@ FontchooserCget( break; } case FontchooserVisible: { - resObj = Tcl_NewBooleanObj(FPIsFontPanelVisible()); + resObj = Tcl_NewBooleanObj([[[NSFontManager sharedFontManager] + fontPanel:NO] isVisible]); break; } default: { @@ -2074,34 +1363,39 @@ FontchooserConfigureCmd( fcdPtr->titleObj = NULL; } break; - case FontchooserFont: { - + case FontchooserFont: Tcl_GetStringFromObj(objv[i+1], &len); if (len) { Tk_Font f = Tk_AllocFontFromObj(interp, tkwin, objv[i+1]); if (f) { - ATSUStyle atsuStyle; - - TkMacOSXFMFontInfoForFont(f, &fontPanelFontFamily, - &fontPanelFontStyle, &fontPanelFontSize, - &atsuStyle); - ChkErr(SetFontInfoForSelection, - kFontSelectionATSUIType, 1, &atsuStyle, NULL); + [fontPanelFont autorelease]; + fontPanelFont = [TkMacOSXNSFontForFont(f) retain]; + [fontPanelFontAttributes setDictionary: + TkMacOSXNSFontAttributesForFont(f)]; + [fontPanelFontAttributes removeObjectsForKeys:[NSArray + arrayWithObjects:NSFontAttributeName, + NSLigatureAttributeName, NSKernAttributeName, + nil]]; Tk_FreeFont(f); } else { return TCL_ERROR; } } else { - fontPanelFontFamily = kInvalidFontFamily; - ChkErr(SetFontInfoForSelection, - kFontSelectionATSUIType, 0, NULL, NULL); + [fontPanelFont release]; + fontPanelFont = nil; + [fontPanelFontAttributes removeAllObjects]; } - if (FPIsFontPanelVisible()) { + NSFontManager *fm = [NSFontManager sharedFontManager]; + NSFontPanel *fp = [fm fontPanel:NO]; + [fp setPanelFont:fontPanelFont isMultiple:NO]; + [fm setSelectedFont:fontPanelFont isMultiple:NO]; + [fm setSelectedAttributes:fontPanelFontAttributes + isMultiple:NO]; + if ([fp isVisible]) { TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserFontChanged"); } break; - } case FontchooserCmd: if (fcdPtr->cmdObj) { Tcl_DecrRefCount(fcdPtr->cmdObj); @@ -2155,8 +1449,13 @@ FontchooserShowCmd( Tk_CreateEventHandler(fcdPtr->parent, StructureNotifyMask, FontchooserParentEventHandler, fcdPtr); } - if (!FPIsFontPanelVisible()) { - ChkErr(FPShowHideFontPanel); + NSFontManager *fm = [NSFontManager sharedFontManager]; + NSFontPanel *fp = [fm fontPanel:YES]; + if ([fp delegate] != NSApp) { + [fp setDelegate:NSApp]; + } + if (![fp isVisible]) { + [fm orderFrontFontPanel:NSApp]; TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserVisibility"); } fontchooserInterp = interp; @@ -2188,8 +1487,9 @@ FontchooserHideCmd( int objc, Tcl_Obj *const objv[]) { - if (FPIsFontPanelVisible()) { - ChkErr(FPShowHideFontPanel); + NSFontPanel *fp = [[NSFontManager sharedFontManager] fontPanel:NO]; + if ([fp isVisible]) { + [fp orderOut:NSApp]; } return TCL_OK; } @@ -2222,9 +1522,7 @@ FontchooserParentEventHandler( Tk_DeleteEventHandler(fcdPtr->parent, StructureNotifyMask, FontchooserParentEventHandler, fcdPtr); fcdPtr->parent = None; - if (FPIsFontPanelVisible()) { - ChkErr(FPShowHideFontPanel); - } + FontchooserHideCmd(NULL, NULL, 0, NULL); } } @@ -2293,6 +1591,11 @@ TkInitFontchooser( bzero(fcdPtr, sizeof(FontchooserData)); Tcl_SetAssocData(interp, "::tk::fontchooser", DeleteFontchooserData, fcdPtr); + if (!fontPanelFontAttributes) { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + fontPanelFontAttributes = [NSMutableDictionary new]; + [pool drain]; + } return TCL_OK; } |