From 2f5c17efbcde76c70e226b03b9be5770f955be9b Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 27 Aug 2014 15:43:09 +0000 Subject: autoconf --- unix/configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/configure b/unix/configure index b1b5267..68f7bf8 100755 --- a/unix/configure +++ b/unix/configure @@ -4852,7 +4852,7 @@ fi LD_SEARCH_FLAGS="" TCL_NEEDS_EXP_FILE=1 TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.dll.a' - SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,$@.a" + TCL_SHLIB_LD_EXTRAS='-Wl,--out-implib,$@.a' TK_SHLIB_LD_EXTRAS='-Wl,--out-implib,$@.a' echo "$as_me:$LINENO: checking for Cygwin version of gcc" >&5 echo $ECHO_N "checking for Cygwin version of gcc... $ECHO_C" >&6 -- cgit v0.12 From 001aa2d54de8732d9d3eae6d92f640f393f19ebb Mon Sep 17 00:00:00 2001 From: ashok Date: Fri, 12 Sep 2014 03:23:54 +0000 Subject: Started on new Vista-style file dialogs. Refactored option processing. --- win/tkWinDialog.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index baebfc9..ef4f7f6 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -145,6 +145,29 @@ typedef struct { } ChooseDir; /* + * The following structure is used to gather options used by various + * file dialogs + */ +typedef struct OFNOpts { + Tk_Window tkwin; /* Owner window for dialog */ + char *extension; /* Default extension */ + char *title; /* Title for dialog */ + Tcl_Obj *filterObj; /* File type filter list */ + Tcl_Obj *typeVariableObj; /* Variable in which to store type selected */ + Tcl_Obj *initialTypeObj; /* Initial value of above, or NULL */ + Tcl_DString utfDirString; /* Initial dir */ + int multi; /* Multiple selection enabled */ + int confirmOverwrite; /* Multiple selection enabled */ + TCHAR file[TK_MULTI_MAX_PATH]; /* File name + XXX - fixed size because it was so + historically. Why not malloc'ed ? + XXX - also, TCHAR should really be WCHAR + because TkWinGetUnicodeEncoding is always + UCS2. + */ +} OFNOpts; + +/* * The following structure is used to pass information between GetFileName * function and OFN dialog hook procedures. [Bug 2896501, Patch 2898255] */ @@ -520,6 +543,178 @@ Tk_GetSaveFileObjCmd( /* *---------------------------------------------------------------------- * + * CleanupOFNOptions -- + * + * Cleans up any storage allocated by ParseOFNOptions + * + * Results: + * None. + * + * Side effects: + * Releases resources held by *optsPtr + *---------------------------------------------------------------------- + */ +static void CleanupOFNOptions(OFNOpts *optsPtr) +{ + Tcl_DStringFree(&optsPtr->utfDirString); +} + + + +/* + *---------------------------------------------------------------------- + * + * ParseOFNOptions -- + * + * Option parsing for tk_get{Open,Save}File + * + * Results: + * TCL_OK on success, TCL_ERROR otherwise + * + * Side effects: + * Returns option values in *optsPtr. Note these may include string + * pointers into objv[] + *---------------------------------------------------------------------- + */ + +static int +ParseOFNOptions( + ClientData clientData, /* Main window associated with interpreter. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[], /* Argument objects. */ + int open, /* 1 for Open, 0 for Save */ + OFNOpts *optsPtr) /* Output, uninitialized on entry */ +{ + int i; + Tcl_DString ds; + enum options { + FILE_DEFAULT, FILE_TYPES, FILE_INITDIR, FILE_INITFILE, FILE_PARENT, + FILE_TITLE, FILE_TYPEVARIABLE, FILE_MULTIPLE, FILE_CONFIRMOW + }; + struct Options { + const char *name; + enum options value; + }; + static const struct Options saveOptions[] = { + {"-confirmoverwrite", FILE_CONFIRMOW}, + {"-defaultextension", FILE_DEFAULT}, + {"-filetypes", FILE_TYPES}, + {"-initialdir", FILE_INITDIR}, + {"-initialfile", FILE_INITFILE}, + {"-parent", FILE_PARENT}, + {"-title", FILE_TITLE}, + {"-typevariable", FILE_TYPEVARIABLE}, + {NULL, FILE_DEFAULT/*ignored*/ } + }; + static const struct Options openOptions[] = { + {"-defaultextension", FILE_DEFAULT}, + {"-filetypes", FILE_TYPES}, + {"-initialdir", FILE_INITDIR}, + {"-initialfile", FILE_INITFILE}, + {"-multiple", FILE_MULTIPLE}, + {"-parent", FILE_PARENT}, + {"-title", FILE_TITLE}, + {"-typevariable", FILE_TYPEVARIABLE}, + {NULL, FILE_DEFAULT/*ignored*/ } + }; + const struct Options *const options = open ? openOptions : saveOptions; + + optsPtr->tkwin = clientData; + optsPtr->extension = NULL; + optsPtr->title = NULL; + optsPtr->filterObj = NULL; + optsPtr->typeVariableObj = NULL; + optsPtr->initialTypeObj = NULL; + optsPtr->multi = 0; + optsPtr->confirmOverwrite = 1; /* By default we ask for confirmation */ + Tcl_DStringInit(&optsPtr->utfDirString); + optsPtr->file[0] = 0; + + for (i = 1; i < objc; i += 2) { + int index; + const char *string; + Tcl_Obj *valuePtr = objv[i + 1]; + + if (Tcl_GetIndexFromObjStruct(interp, objv[i], options, + sizeof(struct Options), "option", 0, &index) != TCL_OK) { + goto end; + } else if (i + 1 == objc) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "value for \"%s\" missing", options[index].name)); + Tcl_SetErrorCode(interp, "TK", "FILEDIALOG", "VALUE", NULL); + goto end; + } + + string = Tcl_GetString(valuePtr); + switch (options[index].value) { + case FILE_DEFAULT: + if (string[0] == '.') { + string++; + } + optsPtr->extension = string; + break; + case FILE_TYPES: + optsPtr->filterObj = valuePtr; + break; + case FILE_INITDIR: + Tcl_DStringFree(&optsPtr->utfDirString); + if (Tcl_TranslateFileName(interp, string, + &optsPtr->utfDirString) == NULL) { + goto end; + } + break; + case FILE_INITFILE: + if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { + goto end; + } + Tcl_UtfToExternal(NULL, TkWinGetUnicodeEncoding(), + Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), 0, NULL, + (char *) &optsPtr->file[0], sizeof(optsPtr->file), + NULL, NULL, NULL); + Tcl_DStringFree(&ds); + break; + case FILE_PARENT: + /* XXX - check */ + optsPtr->tkwin = Tk_NameToWindow(interp, string, clientData); + if (optsPtr->tkwin == NULL) { + goto end; + } + break; + case FILE_TITLE: + optsPtr->title = string; + break; + case FILE_TYPEVARIABLE: + optsPtr->typeVariableObj = valuePtr; + optsPtr->initialTypeObj = Tcl_ObjGetVar2(interp, valuePtr, + NULL, TCL_GLOBAL_ONLY); + break; + case FILE_MULTIPLE: + if (Tcl_GetBooleanFromObj(interp, valuePtr, &optsPtr->multi) != TCL_OK) { + return TCL_ERROR; + } + break; + case FILE_CONFIRMOW: + if (Tcl_GetBooleanFromObj(interp, valuePtr, + &optsPtr->confirmOverwrite) != TCL_OK) { + return TCL_ERROR; + } + break; + } + } + + return TCL_OK; + +end: /* interp should already hold error */ + CleanupOFNOptions(optsPtr); + return TCL_ERROR; +} + + + +/* + *---------------------------------------------------------------------- + * * GetFileName -- * * Calls GetOpenFileName() or GetSaveFileName(). -- cgit v0.12 From 034144aa3bb40a60ddf23e96380f1bb2a478bbae Mon Sep 17 00:00:00 2001 From: ashok Date: Fri, 12 Sep 2014 13:11:16 +0000 Subject: Get basic new style dialogs working. --- win/tkWinDialog.c | 840 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 695 insertions(+), 145 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index ef4f7f6..241ae12 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -21,6 +21,8 @@ #include /* includes the common dialog error codes */ #include /* includes SHBrowseForFolder */ +#include + #ifdef _MSC_VER # pragma comment (lib, "shell32.lib") #endif @@ -57,6 +59,10 @@ typedef struct ThreadSpecificData { HHOOK hMsgBoxHook; /* Hook proc for tk_messageBox and the */ HICON hSmallIcon; /* icons used by a parent to be used in */ HICON hBigIcon; /* the message box */ + int useNewFileDialogs; +#define FDLG_STATE_INIT 0 /* Uninitialized */ +#define FDLG_STATE_USE_NEW 1 /* Use the new dialogs */ +#define FDLG_STATE_USE_OLD 2 /* Use the old dialogs */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; @@ -145,13 +151,27 @@ typedef struct { } ChooseDir; /* + * The following structure is used to pass information between GetFileName + * function and OFN dialog hook procedures. [Bug 2896501, Patch 2898255] + */ + +typedef struct OFNData { + Tcl_Interp *interp; /* Interp, used only if debug is turned on, + * for setting the "tk_dialog" variable. */ + int dynFileBufferSize; /* Dynamic filename buffer size, stored to + * avoid shrinking and expanding the buffer + * when selection changes */ + TCHAR *dynFileBuffer; /* Dynamic filename buffer */ +} OFNData; + +/* * The following structure is used to gather options used by various * file dialogs */ typedef struct OFNOpts { Tk_Window tkwin; /* Owner window for dialog */ - char *extension; /* Default extension */ - char *title; /* Title for dialog */ + const char *extension; /* Default extension */ + const char *title; /* Title for dialog */ Tcl_Obj *filterObj; /* File type filter list */ Tcl_Obj *typeVariableObj; /* Variable in which to store type selected */ Tcl_Obj *initialTypeObj; /* Initial value of above, or NULL */ @@ -168,18 +188,569 @@ typedef struct OFNOpts { } OFNOpts; /* - * The following structure is used to pass information between GetFileName - * function and OFN dialog hook procedures. [Bug 2896501, Patch 2898255] + * The following definitions are required when using older versions of + * Visual C++ (like 6.0) and possibly MingW. Those headers do not contain + * required definitions for interfaces new to Vista that we need for + * the new file dialogs. Duplicating definitions is OK because they + * should forever remain unchanged. + * + * XXX - is there a better/easier way to use new data definitions with + * older compilers? Should we prefix definitions with Tcl_ instead + * of using the same names as in the SDK? */ +#ifndef __IShellItemArray_INTERFACE_DEFINED__ +#define __IShellItemArray_INTERFACE_DEFINED__ + +typedef enum SIATTRIBFLAGS { + SIATTRIBFLAGS_AND = 0x1, + SIATTRIBFLAGS_OR = 0x2, + SIATTRIBFLAGS_APPCOMPAT = 0x3, + SIATTRIBFLAGS_MASK = 0x3, + SIATTRIBFLAGS_ALLITEMS = 0x4000 +} SIATTRIBFLAGS; +typedef struct IShellItemArray IShellItemArray; +typedef struct IShellItemArrayVtbl +{ + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IShellItemArray * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IShellItemArray * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IShellItemArray * This); + + HRESULT ( STDMETHODCALLTYPE *BindToHandler )( + IShellItemArray * This, + /* [unique][in] */ IBindCtx *pbc, + /* [in] */ REFGUID bhid, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void **ppvOut); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyStore )( + IShellItemArray * This, + /* Actually enum GETPROPERTYSTOREFLAGS, but we do not use this call */ + /* [in] */ int flags, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void **ppv); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyDescriptionList )( + IShellItemArray * This, + /* Actually REFPROPERTYKEY, but this call is not used */ + /* [in] */ void* keyType, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void **ppv); + + HRESULT ( STDMETHODCALLTYPE *GetAttributes )( + IShellItemArray * This, + /* [in] */ SIATTRIBFLAGS AttribFlags, + /* [in] */ SFGAOF sfgaoMask, + /* [out] */ SFGAOF *psfgaoAttribs); + + HRESULT ( STDMETHODCALLTYPE *GetCount )( + IShellItemArray * This, + /* [out] */ DWORD *pdwNumItems); + + HRESULT ( STDMETHODCALLTYPE *GetItemAt )( + IShellItemArray * This, + /* [in] */ DWORD dwIndex, + /* [out] */ IShellItem **ppsi); + + HRESULT ( STDMETHODCALLTYPE *EnumItems )( + IShellItemArray * This, + /* Actually IEnumShellItems **, but we do not use this call */ + /* [out] */ void **ppenumShellItems); + + END_INTERFACE +} IShellItemArrayVtbl; + +struct IShellItemArray +{ + CONST_VTBL struct IShellItemArrayVtbl *lpVtbl; +}; -typedef struct OFNData { - Tcl_Interp *interp; /* Interp, used only if debug is turned on, - * for setting the "tk_dialog" variable. */ - int dynFileBufferSize; /* Dynamic filename buffer size, stored to - * avoid shrinking and expanding the buffer - * when selection changes */ - TCHAR *dynFileBuffer; /* Dynamic filename buffer */ -} OFNData; +#endif /* __IShellItemArray_INTERFACE_DEFINED__ */ + +#ifndef __IFileDialog_INTERFACE_DEFINED__ + +/* Forward declarations for structs that are referenced but not used */ +typedef struct IPropertyStore IPropertyStore; +typedef struct IPropertyDescriptionList IPropertyDescriptionList; +typedef struct IFileOperationProgressSink IFileOperationProgressSink; +typedef enum FDAP { + FDAP_BOTTOM = 0, + FDAP_TOP = 1 +} FDAP; + +typedef struct _COMDLG_FILTERSPEC { + LPCWSTR pszName; + LPCWSTR pszSpec; +} COMDLG_FILTERSPEC; + +static CLSID CLSID_FileOpenDialog = { + 0xDC1C5A9C, 0xE88A, 0X4DDE, 0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7 +}; + +static IID IID_IFileOpenDialog = { + 0xD57C7288, 0xD4AD, 0x4768, 0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60 +}; + +static CLSID CLSID_FileSaveDialog = { + 0xC0B4E2F3, 0xBA21, 0x4773, 0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B +}; + +static IID IID_IFileSaveDialog = { + 0x84BCCD23, 0x5FDE, 0x4CDB, 0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB +}; + +enum _FILEOPENDIALOGOPTIONS { + FOS_OVERWRITEPROMPT = 0x2, + FOS_STRICTFILETYPES = 0x4, + FOS_NOCHANGEDIR = 0x8, + FOS_PICKFOLDERS = 0x20, + FOS_FORCEFILESYSTEM = 0x40, + FOS_ALLNONSTORAGEITEMS = 0x80, + FOS_NOVALIDATE = 0x100, + FOS_ALLOWMULTISELECT = 0x200, + FOS_PATHMUSTEXIST = 0x800, + FOS_FILEMUSTEXIST = 0x1000, + FOS_CREATEPROMPT = 0x2000, + FOS_SHAREAWARE = 0x4000, + FOS_NOREADONLYRETURN = 0x8000, + FOS_NOTESTFILECREATE = 0x10000, + FOS_HIDEMRUPLACES = 0x20000, + FOS_HIDEPINNEDPLACES = 0x40000, + FOS_NODEREFERENCELINKS = 0x100000, + FOS_DONTADDTORECENT = 0x2000000, + FOS_FORCESHOWHIDDEN = 0x10000000, + FOS_DEFAULTNOMINIMODE = 0x20000000, + FOS_FORCEPREVIEWPANEON = 0x40000000 +} ; +typedef DWORD FILEOPENDIALOGOPTIONS; + +typedef struct IFileDialog IFileDialog; +typedef struct IFileDialogVtbl +{ + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IFileDialog * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IFileDialog * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IFileDialog * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Show )( + IFileDialog * This, + /* [annotation][unique][in] */ + HWND hwndOwner); + + HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( + IFileDialog * This, + /* [in] */ UINT cFileTypes, + /* [size_is][in] */ const COMDLG_FILTERSPEC *rgFilterSpec); + + HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( + IFileDialog * This, + /* [in] */ UINT iFileType); + + HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( + IFileDialog * This, + /* [out] */ UINT *piFileType); + + HRESULT ( STDMETHODCALLTYPE *Advise )( + IFileDialog * This, + /* XXX - Actually pfde is IFileDialogEvents* but we do not use + this call and do not want to define IFileDialogEvents as that + pulls in a whole bunch of other stuff. */ + /* [in] */ void *pfde, + /* [out] */ DWORD *pdwCookie); + + HRESULT ( STDMETHODCALLTYPE *Unadvise )( + IFileDialog * This, + /* [in] */ DWORD dwCookie); + + HRESULT ( STDMETHODCALLTYPE *SetOptions )( + IFileDialog * This, + /* [in] */ FILEOPENDIALOGOPTIONS fos); + + HRESULT ( STDMETHODCALLTYPE *GetOptions )( + IFileDialog * This, + /* [out] */ FILEOPENDIALOGOPTIONS *pfos); + + HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( + IFileDialog * This, + /* [in] */ IShellItem *psi); + + HRESULT ( STDMETHODCALLTYPE *SetFolder )( + IFileDialog * This, + /* [in] */ IShellItem *psi); + + HRESULT ( STDMETHODCALLTYPE *GetFolder )( + IFileDialog * This, + /* [out] */ IShellItem **ppsi); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( + IFileDialog * This, + /* [out] */ IShellItem **ppsi); + + HRESULT ( STDMETHODCALLTYPE *SetFileName )( + IFileDialog * This, + /* [string][in] */ LPCWSTR pszName); + + HRESULT ( STDMETHODCALLTYPE *GetFileName )( + IFileDialog * This, + /* [string][out] */ LPWSTR *pszName); + + HRESULT ( STDMETHODCALLTYPE *SetTitle )( + IFileDialog * This, + /* [string][in] */ LPCWSTR pszTitle); + + HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( + IFileDialog * This, + /* [string][in] */ LPCWSTR pszText); + + HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( + IFileDialog * This, + /* [string][in] */ LPCWSTR pszLabel); + + HRESULT ( STDMETHODCALLTYPE *GetResult )( + IFileDialog * This, + /* [out] */ IShellItem **ppsi); + + HRESULT ( STDMETHODCALLTYPE *AddPlace )( + IFileDialog * This, + /* [in] */ IShellItem *psi, + /* [in] */ FDAP fdap); + + HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( + IFileDialog * This, + /* [string][in] */ LPCWSTR pszDefaultExtension); + + HRESULT ( STDMETHODCALLTYPE *Close )( + IFileDialog * This, + /* [in] */ HRESULT hr); + + HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( + IFileDialog * This, + /* [in] */ REFGUID guid); + + HRESULT ( STDMETHODCALLTYPE *ClearClientData )( + IFileDialog * This); + + HRESULT ( STDMETHODCALLTYPE *SetFilter )( + IFileDialog * This, + /* XXX - Actually IShellItemFilter. But deprecated in Win7 AND we do + not use it anyways. So define as void* */ + /* [in] */ void *pFilter); + + END_INTERFACE +} IFileDialogVtbl; + +struct IFileDialog { + CONST_VTBL struct IFileDialogVtbl *lpVtbl; +}; + + +typedef struct IFileSaveDialog IFileSaveDialog; +typedef struct IFileSaveDialogVtbl { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IFileSaveDialog * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IFileSaveDialog * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IFileSaveDialog * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Show )( + IFileSaveDialog * This, + /* [annotation][unique][in] */ + HWND hwndOwner); + + HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( + IFileSaveDialog * This, + /* [in] */ UINT cFileTypes, + /* [size_is][in] */ const COMDLG_FILTERSPEC *rgFilterSpec); + + HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( + IFileSaveDialog * This, + /* [in] */ UINT iFileType); + + HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( + IFileSaveDialog * This, + /* [out] */ UINT *piFileType); + + HRESULT ( STDMETHODCALLTYPE *Advise )( + IFileSaveDialog * This, + /* XXX - Actually pfde is IFileSaveDialogEvents* but we do not use + this call and do not want to define IFileSaveDialogEvents as that + pulls in a whole bunch of other stuff. */ + /* [in] */ void *pfde, + /* [out] */ DWORD *pdwCookie); + + HRESULT ( STDMETHODCALLTYPE *Unadvise )( + IFileSaveDialog * This, + /* [in] */ DWORD dwCookie); + + HRESULT ( STDMETHODCALLTYPE *SetOptions )( + IFileSaveDialog * This, + /* [in] */ FILEOPENDIALOGOPTIONS fos); + + HRESULT ( STDMETHODCALLTYPE *GetOptions )( + IFileSaveDialog * This, + /* [out] */ FILEOPENDIALOGOPTIONS *pfos); + + HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( + IFileSaveDialog * This, + /* [in] */ IShellItem *psi); + + HRESULT ( STDMETHODCALLTYPE *SetFolder )( + IFileSaveDialog * This, + /* [in] */ IShellItem *psi); + + HRESULT ( STDMETHODCALLTYPE *GetFolder )( + IFileSaveDialog * This, + /* [out] */ IShellItem **ppsi); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( + IFileSaveDialog * This, + /* [out] */ IShellItem **ppsi); + + HRESULT ( STDMETHODCALLTYPE *SetFileName )( + IFileSaveDialog * This, + /* [string][in] */ LPCWSTR pszName); + + HRESULT ( STDMETHODCALLTYPE *GetFileName )( + IFileSaveDialog * This, + /* [string][out] */ LPWSTR *pszName); + + HRESULT ( STDMETHODCALLTYPE *SetTitle )( + IFileSaveDialog * This, + /* [string][in] */ LPCWSTR pszTitle); + + HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( + IFileSaveDialog * This, + /* [string][in] */ LPCWSTR pszText); + + HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( + IFileSaveDialog * This, + /* [string][in] */ LPCWSTR pszLabel); + + HRESULT ( STDMETHODCALLTYPE *GetResult )( + IFileSaveDialog * This, + /* [out] */ IShellItem **ppsi); + + HRESULT ( STDMETHODCALLTYPE *AddPlace )( + IFileSaveDialog * This, + /* [in] */ IShellItem *psi, + /* [in] */ FDAP fdap); + + HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( + IFileSaveDialog * This, + /* [string][in] */ LPCWSTR pszDefaultExtension); + + HRESULT ( STDMETHODCALLTYPE *Close )( + IFileSaveDialog * This, + /* [in] */ HRESULT hr); + + HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( + IFileSaveDialog * This, + /* [in] */ REFGUID guid); + + HRESULT ( STDMETHODCALLTYPE *ClearClientData )( + IFileSaveDialog * This); + + HRESULT ( STDMETHODCALLTYPE *SetFilter )( + IFileSaveDialog * This, + /* XXX - Actually IShellItemFilter. But deprecated in Win7 AND we do + not use it anyways. So define as void* */ + /* [in] */ void *pFilter); + + HRESULT ( STDMETHODCALLTYPE *SetSaveAsItem )( + IFileSaveDialog * This, + /* [in] */ IShellItem *psi); + + HRESULT ( STDMETHODCALLTYPE *SetProperties )( + IFileSaveDialog * This, + /* [in] */ IPropertyStore *pStore); + + HRESULT ( STDMETHODCALLTYPE *SetCollectedProperties )( + IFileSaveDialog * This, + /* [in] */ IPropertyDescriptionList *pList, + /* [in] */ BOOL fAppendDefault); + + HRESULT ( STDMETHODCALLTYPE *GetProperties )( + IFileSaveDialog * This, + /* [out] */ IPropertyStore **ppStore); + + HRESULT ( STDMETHODCALLTYPE *ApplyProperties )( + IFileSaveDialog * This, + /* [in] */ IShellItem *psi, + /* [in] */ IPropertyStore *pStore, + /* [unique][in] */ HWND hwnd, + /* [unique][in] */ IFileOperationProgressSink *pSink); + + END_INTERFACE + +} IFileSaveDialogVtbl; + +struct IFileSaveDialog { + CONST_VTBL struct IFileSaveDialogVtbl *lpVtbl; +}; + +typedef struct IFileOpenDialog IFileOpenDialog; +typedef struct IFileOpenDialogVtbl { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IFileOpenDialog * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IFileOpenDialog * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IFileOpenDialog * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Show )( + IFileOpenDialog * This, + /* [annotation][unique][in] */ + HWND hwndOwner); + + HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( + IFileOpenDialog * This, + /* [in] */ UINT cFileTypes, + /* [size_is][in] */ const COMDLG_FILTERSPEC *rgFilterSpec); + + HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( + IFileOpenDialog * This, + /* [in] */ UINT iFileType); + + HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( + IFileOpenDialog * This, + /* [out] */ UINT *piFileType); + + HRESULT ( STDMETHODCALLTYPE *Advise )( + IFileOpenDialog * This, + /* XXX - Actually pfde is IFileDialogEvents* but we do not use + this call and do not want to define IFileDialogEvents as that + pulls in a whole bunch of other stuff. */ + /* [in] */ void *pfde, + /* [out] */ DWORD *pdwCookie); + + HRESULT ( STDMETHODCALLTYPE *Unadvise )( + IFileOpenDialog * This, + /* [in] */ DWORD dwCookie); + + HRESULT ( STDMETHODCALLTYPE *SetOptions )( + IFileOpenDialog * This, + /* [in] */ FILEOPENDIALOGOPTIONS fos); + + HRESULT ( STDMETHODCALLTYPE *GetOptions )( + IFileOpenDialog * This, + /* [out] */ FILEOPENDIALOGOPTIONS *pfos); + + HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( + IFileOpenDialog * This, + /* [in] */ IShellItem *psi); + + HRESULT ( STDMETHODCALLTYPE *SetFolder )( + IFileOpenDialog * This, + /* [in] */ IShellItem *psi); + + HRESULT ( STDMETHODCALLTYPE *GetFolder )( + IFileOpenDialog * This, + /* [out] */ IShellItem **ppsi); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( + IFileOpenDialog * This, + /* [out] */ IShellItem **ppsi); + + HRESULT ( STDMETHODCALLTYPE *SetFileName )( + IFileOpenDialog * This, + /* [string][in] */ LPCWSTR pszName); + + HRESULT ( STDMETHODCALLTYPE *GetFileName )( + IFileOpenDialog * This, + /* [string][out] */ LPWSTR *pszName); + + HRESULT ( STDMETHODCALLTYPE *SetTitle )( + IFileOpenDialog * This, + /* [string][in] */ LPCWSTR pszTitle); + + HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( + IFileOpenDialog * This, + /* [string][in] */ LPCWSTR pszText); + + HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( + IFileOpenDialog * This, + /* [string][in] */ LPCWSTR pszLabel); + + HRESULT ( STDMETHODCALLTYPE *GetResult )( + IFileOpenDialog * This, + /* [out] */ IShellItem **ppsi); + + HRESULT ( STDMETHODCALLTYPE *AddPlace )( + IFileOpenDialog * This, + /* [in] */ IShellItem *psi, + /* [in] */ FDAP fdap); + + HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( + IFileOpenDialog * This, + /* [string][in] */ LPCWSTR pszDefaultExtension); + + HRESULT ( STDMETHODCALLTYPE *Close )( + IFileOpenDialog * This, + /* [in] */ HRESULT hr); + + HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( + IFileOpenDialog * This, + /* [in] */ REFGUID guid); + + HRESULT ( STDMETHODCALLTYPE *ClearClientData )( + IFileOpenDialog * This); + + HRESULT ( STDMETHODCALLTYPE *SetFilter )( + IFileOpenDialog * This, + /* XXX - Actually IShellItemFilter. But deprecated in Win7 AND we do + not use it anyways. So define as void* */ + /* [in] */ void *pFilter); + + HRESULT ( STDMETHODCALLTYPE *GetResults )( + IFileOpenDialog * This, + /* [out] */ IShellItemArray **ppenum); + + HRESULT ( STDMETHODCALLTYPE *GetSelectedItems )( + IFileOpenDialog * This, + /* [out] */ IShellItemArray **ppsai); + + END_INTERFACE +} IFileOpenDialogVtbl; + +struct IFileOpenDialog +{ + CONST_VTBL struct IFileOpenDialogVtbl *lpVtbl; +}; + +#endif /* __IFileDialog_INTERFACE_DEFINED__ */ /* * Definitions of functions used only in this file. @@ -189,6 +760,10 @@ static UINT APIENTRY ChooseDirectoryValidateProc(HWND hdlg, UINT uMsg, LPARAM wParam, LPARAM lParam); static UINT CALLBACK ColorDlgHookProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +static void CleanupOFNOptions(OFNOpts *optsPtr); +static int ParseOFNOptions(ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[], int open, OFNOpts *optsPtr); static int GetFileName(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int isOpen); @@ -710,6 +1285,80 @@ end: /* interp should already hold error */ return TCL_ERROR; } + +/* + *---------------------------------------------------------------------- + * + * GetFileNameVista -- + * + * Displays the new file dialogs on Vista and later. + * + * Results: + * TCL_OK - if dialog was successfully displayed + * TCL_ERROR - error return + * TCL_CONTINUE - new dialogs not available. Caller should go + * on to display the old style dialogs. + * + * Side effects: + * Dialogs is displayed and results returned in interpreter on success. + * COM subsystem is initialized if not already done. + *---------------------------------------------------------------------- + */ +static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) +{ + HRESULT hr; + IFileDialog *fdlgPtr = NULL; + ThreadSpecificData *tsdPtr = + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + if (tsdPtr->useNewFileDialogs == FDLG_STATE_USE_OLD) + return TCL_CONTINUE; /* Not an error, go try old style dialogs */ + + if (tsdPtr->useNewFileDialogs == FDLG_STATE_INIT) { + tsdPtr->useNewFileDialogs = FDLG_STATE_USE_OLD; + + hr = CoInitialize(0); + /* On failures we do not error. Instead we fall back to old method */ + if (FAILED(hr)) + return TCL_CONTINUE; + + /* Verify interfaces are available */ + if (open) { + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, + CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgPtr); + } else { + hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, + CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, &fdlgPtr); + } + + if (FAILED(hr)) { + CoUninitialize(); + return TCL_CONTINUE; + } + + tsdPtr->useNewFileDialogs = FDLG_STATE_USE_NEW; + /* + * XXX - need to arrange for CoUninitialize to be called on thread + * exit if useNewFileDialogs is FDLG_STATE_USE_NEW. + */ + } else { + /* FDLG_STATE_USE_NEW */ + if (open) { + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, + CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgPtr); + } else { + hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, + CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, &fdlgPtr); + } + } + + /* At this point new interfaces are supposed to be available */ + fdlgPtr->lpVtbl->Show(fdlgPtr, NULL); + fdlgPtr->lpVtbl->Release(fdlgPtr); + return TCL_OK; +} + + /* @@ -738,143 +1387,44 @@ GetFileName( * GetSaveFileName(). */ { OPENFILENAME ofn; - TCHAR file[TK_MULTI_MAX_PATH]; OFNData ofnData; + OFNOpts ofnOpts; int cdlgerr; - int filterIndex = 0, result = TCL_ERROR, winCode, oldMode, i, multi = 0; - int confirmOverwrite = 1; - const char *extension = NULL, *title = NULL; - Tk_Window tkwin = clientData; + int filterIndex = 0, result = TCL_ERROR, winCode, oldMode; HWND hWnd; - Tcl_Obj *filterObj = NULL, *initialTypeObj = NULL, *typeVariableObj = NULL; - Tcl_DString utfFilterString, utfDirString, ds; + Tcl_DString utfFilterString, ds; Tcl_DString extString, filterString, dirString, titleString; ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - enum options { - FILE_DEFAULT, FILE_TYPES, FILE_INITDIR, FILE_INITFILE, FILE_PARENT, - FILE_TITLE, FILE_TYPEVARIABLE, FILE_MULTIPLE, FILE_CONFIRMOW - }; - struct Options { - const char *name; - enum options value; - }; - static const struct Options saveOptions[] = { - {"-confirmoverwrite", FILE_CONFIRMOW}, - {"-defaultextension", FILE_DEFAULT}, - {"-filetypes", FILE_TYPES}, - {"-initialdir", FILE_INITDIR}, - {"-initialfile", FILE_INITFILE}, - {"-parent", FILE_PARENT}, - {"-title", FILE_TITLE}, - {"-typevariable", FILE_TYPEVARIABLE}, - {NULL, FILE_DEFAULT/*ignored*/ } - }; - static const struct Options openOptions[] = { - {"-defaultextension", FILE_DEFAULT}, - {"-filetypes", FILE_TYPES}, - {"-initialdir", FILE_INITDIR}, - {"-initialfile", FILE_INITFILE}, - {"-multiple", FILE_MULTIPLE}, - {"-parent", FILE_PARENT}, - {"-title", FILE_TITLE}, - {"-typevariable", FILE_TYPEVARIABLE}, - {NULL, FILE_DEFAULT/*ignored*/ } - }; - const struct Options *const options = open ? openOptions : saveOptions; - file[0] = '\0'; ZeroMemory(&ofnData, sizeof(OFNData)); Tcl_DStringInit(&utfFilterString); - Tcl_DStringInit(&utfDirString); - /* - * Parse the arguments. - */ - - for (i = 1; i < objc; i += 2) { - int index; - const char *string; - Tcl_Obj *valuePtr = objv[i + 1]; + /* Parse the arguments. */ - if (Tcl_GetIndexFromObjStruct(interp, objv[i], options, - sizeof(struct Options), "option", 0, &index) != TCL_OK) { - goto end; - } else if (i + 1 == objc) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "value for \"%s\" missing", options[index].name)); - Tcl_SetErrorCode(interp, "TK", "FILEDIALOG", "VALUE", NULL); - goto end; - } + result = ParseOFNOptions(clientData, interp, objc, objv, open, &ofnOpts); + if (result != TCL_OK) + return result; - string = Tcl_GetString(valuePtr); - switch (options[index].value) { - case FILE_DEFAULT: - if (string[0] == '.') { - string++; - } - extension = string; - break; - case FILE_TYPES: - filterObj = valuePtr; - break; - case FILE_INITDIR: - Tcl_DStringFree(&utfDirString); - if (Tcl_TranslateFileName(interp, string, - &utfDirString) == NULL) { - goto end; - } - break; - case FILE_INITFILE: - if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { - goto end; - } - Tcl_UtfToExternal(NULL, TkWinGetUnicodeEncoding(), - Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), 0, NULL, - (char *) file, sizeof(file), NULL, NULL, NULL); - Tcl_DStringFree(&ds); - break; - case FILE_PARENT: - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - goto end; - } - break; - case FILE_TITLE: - title = string; - break; - case FILE_TYPEVARIABLE: - typeVariableObj = valuePtr; - initialTypeObj = Tcl_ObjGetVar2(interp, typeVariableObj, NULL, - TCL_GLOBAL_ONLY); - break; - case FILE_MULTIPLE: - if (Tcl_GetBooleanFromObj(interp, valuePtr, &multi) != TCL_OK) { - return TCL_ERROR; - } - break; - case FILE_CONFIRMOW: - if (Tcl_GetBooleanFromObj(interp, valuePtr, - &confirmOverwrite) != TCL_OK) { - return TCL_ERROR; - } - break; - } + result = GetFileNameVista(interp, &ofnOpts, open); + if (result != TCL_CONTINUE) { + CleanupOFNOptions(&ofnOpts); + return result; } - if (MakeFilter(interp, filterObj, &utfFilterString, initialTypeObj, - &filterIndex) != TCL_OK) { + if (MakeFilter(interp, ofnOpts.filterObj, &utfFilterString, + ofnOpts.initialTypeObj, &filterIndex) != TCL_OK) { goto end; } - Tk_MakeWindowExist(tkwin); - hWnd = Tk_GetHWND(Tk_WindowId(tkwin)); + Tk_MakeWindowExist(ofnOpts.tkwin); + hWnd = Tk_GetHWND(Tk_WindowId(ofnOpts.tkwin)); ZeroMemory(&ofn, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.hInstance = TkWinGetHInstance(ofn.hwndOwner); - ofn.lpstrFile = file; + ofn.lpstrFile = ofnOpts.file; ofn.nMaxFile = TK_MULTI_MAX_PATH; ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_ENABLEHOOK| OFN_ENABLESIZING; @@ -883,13 +1433,13 @@ GetFileName( if (open != 0) { ofn.Flags |= OFN_FILEMUSTEXIST; - } else if (confirmOverwrite) { + } else if (ofnOpts.confirmOverwrite) { ofn.Flags |= OFN_OVERWRITEPROMPT; } if (tsdPtr->debugFlag != 0) { ofnData.interp = interp; } - if (multi != 0) { + if (ofnOpts.multi != 0) { ofn.Flags |= OFN_ALLOWMULTISELECT; /* @@ -901,8 +1451,8 @@ GetFileName( ofnData.dynFileBuffer = ckalloc(512 * sizeof(TCHAR)); } - if (extension != NULL) { - Tcl_WinUtfToTChar(extension, -1, &extString); + if (ofnOpts.extension != NULL) { + Tcl_WinUtfToTChar(ofnOpts.extension, -1, &extString); ofn.lpstrDefExt = (TCHAR *) Tcl_DStringValue(&extString); } @@ -911,9 +1461,9 @@ GetFileName( ofn.lpstrFilter = (TCHAR *) Tcl_DStringValue(&filterString); ofn.nFilterIndex = filterIndex; - if (Tcl_DStringValue(&utfDirString)[0] != '\0') { - Tcl_WinUtfToTChar(Tcl_DStringValue(&utfDirString), - Tcl_DStringLength(&utfDirString), &dirString); + if (Tcl_DStringValue(&ofnOpts.utfDirString)[0] != '\0') { + Tcl_WinUtfToTChar(Tcl_DStringValue(&ofnOpts.utfDirString), + Tcl_DStringLength(&ofnOpts.utfDirString), &dirString); } else { /* * NT 5.0 changed the meaning of lpstrInitialDir, so we have to ensure @@ -922,10 +1472,10 @@ GetFileName( Tcl_DString cwd; - Tcl_DStringFree(&utfDirString); - if ((Tcl_GetCwd(interp, &utfDirString) == NULL) || + Tcl_DStringFree(&ofnOpts.utfDirString); + if ((Tcl_GetCwd(interp, &ofnOpts.utfDirString) == NULL) || (Tcl_TranslateFileName(interp, - Tcl_DStringValue(&utfDirString), &cwd) == NULL)) { + Tcl_DStringValue(&ofnOpts.utfDirString), &cwd) == NULL)) { Tcl_ResetResult(interp); } else { Tcl_WinUtfToTChar(Tcl_DStringValue(&cwd), @@ -935,8 +1485,8 @@ GetFileName( } ofn.lpstrInitialDir = (TCHAR *) Tcl_DStringValue(&dirString); - if (title != NULL) { - Tcl_WinUtfToTChar(title, -1, &titleString); + if (ofnOpts.title != NULL) { + Tcl_WinUtfToTChar(ofnOpts.title, -1, &titleString); ofn.lpstrTitle = (TCHAR *) Tcl_DStringValue(&titleString); } @@ -1054,21 +1604,21 @@ GetFileName( Tcl_DStringFree(&ds); } result = TCL_OK; - if ((ofn.nFilterIndex > 0) && gotFilename && typeVariableObj - && filterObj) { + if ((ofn.nFilterIndex > 0) && gotFilename && ofnOpts.typeVariableObj + && ofnOpts.filterObj) { int listObjc, count; Tcl_Obj **listObjv = NULL; Tcl_Obj **typeInfo = NULL; - if (Tcl_ListObjGetElements(interp, filterObj, + if (Tcl_ListObjGetElements(interp, ofnOpts.filterObj, &listObjc, &listObjv) != TCL_OK) { result = TCL_ERROR; } else if (Tcl_ListObjGetElements(interp, listObjv[ofn.nFilterIndex - 1], &count, &typeInfo) != TCL_OK) { result = TCL_ERROR; - } else if (Tcl_ObjSetVar2(interp, typeVariableObj, NULL, - typeInfo[0], TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { + } else if (Tcl_ObjSetVar2(interp, ofnOpts.typeVariableObj, NULL, + typeInfo[0], TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; } } @@ -1095,12 +1645,12 @@ GetFileName( } end: - Tcl_DStringFree(&utfDirString); Tcl_DStringFree(&utfFilterString); if (ofnData.dynFileBuffer != NULL) { ckfree(ofnData.dynFileBuffer); ofnData.dynFileBuffer = NULL; } + CleanupOFNOptions(&ofnOpts); return result; } -- cgit v0.12 From 93218ddaa94d9b9ce6319da38dba137a0c80912c Mon Sep 17 00:00:00 2001 From: ashok Date: Sat, 13 Sep 2014 14:23:33 +0000 Subject: Implemented more options for new tk_get{Open,Save} file dialogs Renamed Win32ErrorObj to TkWin32ErrorObj and moved it from tkWinSend.c to be generally available. --- win/tkWinDialog.c | 403 +++++++++++++++++++++++++++++++++++++++--------------- win/tkWinInit.c | 51 +++++++ win/tkWinInt.h | 6 + win/tkWinSend.c | 55 +------- 4 files changed, 349 insertions(+), 166 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 241ae12..d510654 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -59,7 +59,7 @@ typedef struct ThreadSpecificData { HHOOK hMsgBoxHook; /* Hook proc for tk_messageBox and the */ HICON hSmallIcon; /* icons used by a parent to be used in */ HICON hBigIcon; /* the message box */ - int useNewFileDialogs; + int newFileDialogsAvailable; #define FDLG_STATE_INIT 0 /* Uninitialized */ #define FDLG_STATE_USE_NEW 1 /* Use the new dialogs */ #define FDLG_STATE_USE_OLD 2 /* Use the old dialogs */ @@ -170,14 +170,15 @@ typedef struct OFNData { */ typedef struct OFNOpts { Tk_Window tkwin; /* Owner window for dialog */ - const char *extension; /* Default extension */ - const char *title; /* Title for dialog */ + Tcl_Obj *extObj; /* Default extension */ + Tcl_Obj *titleObj; /* Title for dialog */ Tcl_Obj *filterObj; /* File type filter list */ Tcl_Obj *typeVariableObj; /* Variable in which to store type selected */ Tcl_Obj *initialTypeObj; /* Initial value of above, or NULL */ Tcl_DString utfDirString; /* Initial dir */ int multi; /* Multiple selection enabled */ - int confirmOverwrite; /* Multiple selection enabled */ + int confirmOverwrite; /* Multiple selection enabled */ + int forceXPStyle; /* XXX - Force XP style even on newer systems */ TCHAR file[TK_MULTI_MAX_PATH]; /* File name XXX - fixed size because it was so historically. Why not malloc'ed ? @@ -776,6 +777,69 @@ static LRESULT CALLBACK MsgBoxCBTProc(int nCode, WPARAM wParam, LPARAM lParam); static void SetTkDialog(ClientData clientData); static const char *ConvertExternalFilename(TCHAR *filename, Tcl_DString *dsPtr); +static void LoadShellProcs(void); + + +/* Definitions of dynamically loaded Win32 calls */ +typedef HRESULT (STDAPICALLTYPE SHCreateItemFromParsingNameProc)( + PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv); +struct ShellProcPointers { + SHCreateItemFromParsingNameProc *SHCreateItemFromParsingName; +} ShellProcs; + + + + + +/* + *------------------------------------------------------------------------- + * + * LoadShellProcs -- + * + * Some shell functions are not available on older versions of + * Windows. This function dynamically loads them and stores pointers + * to them in ShellProcs. Any function that is not available has + * the corresponding pointer set to NULL. + * + * Note this call never fails. Unavailability of a function is not + * a reason for failure. Caller should check whether a particular + * function pointer is NULL or not. Once loaded a function stays + * forever loaded. + * + * XXX - we load the function pointers into global memory. This implies + * there is a potential (however small) for race conditions between + * threads. However, Tk is in any case meant to be loaded in exactly + * one thread so this should not be an issue and saves us from + * unnecessary bookkeeping. + * + * Return value: + * None. + * + * Side effects: + * ShellProcs is populated. + *------------------------------------------------------------------------- + */ +static void LoadShellProcs() +{ + static HMODULE shell32_handle = NULL; + + if (shell32_handle != NULL) + return; /* We have already been through here. */ + + /* + * XXX - Note we never call FreeLibrary. There is no point because + * shell32.dll is loaded at startup anyways and stays for the duration + * of the process so why bother with keeping track of when to unload + */ + shell32_handle = LoadLibrary(TEXT("shell32.dll")); + if (shell32_handle == NULL) /* Should never happen but check anyways. */ + return; + + ShellProcs.SHCreateItemFromParsingName = + (SHCreateItemFromParsingNameProc*) GetProcAddress(shell32_handle, + "SHCreateItemFromParsingName"); +} + /* *------------------------------------------------------------------------- @@ -1165,7 +1229,8 @@ ParseOFNOptions( Tcl_DString ds; enum options { FILE_DEFAULT, FILE_TYPES, FILE_INITDIR, FILE_INITFILE, FILE_PARENT, - FILE_TITLE, FILE_TYPEVARIABLE, FILE_MULTIPLE, FILE_CONFIRMOW + FILE_TITLE, FILE_TYPEVARIABLE, FILE_MULTIPLE, FILE_CONFIRMOW, + FILE_UNDOCUMENTED_XP_STYLE /* XXX - force XP - style dialogs */ }; struct Options { const char *name; @@ -1180,6 +1245,7 @@ ParseOFNOptions( {"-parent", FILE_PARENT}, {"-title", FILE_TITLE}, {"-typevariable", FILE_TYPEVARIABLE}, + {"-xpstyle", FILE_UNDOCUMENTED_XP_STYLE}, /* XXX */ {NULL, FILE_DEFAULT/*ignored*/ } }; static const struct Options openOptions[] = { @@ -1191,17 +1257,13 @@ ParseOFNOptions( {"-parent", FILE_PARENT}, {"-title", FILE_TITLE}, {"-typevariable", FILE_TYPEVARIABLE}, + {"-xpstyle", FILE_UNDOCUMENTED_XP_STYLE}, /* XXX */ {NULL, FILE_DEFAULT/*ignored*/ } }; const struct Options *const options = open ? openOptions : saveOptions; + ZeroMemory(optsPtr, sizeof(*optsPtr)); optsPtr->tkwin = clientData; - optsPtr->extension = NULL; - optsPtr->title = NULL; - optsPtr->filterObj = NULL; - optsPtr->typeVariableObj = NULL; - optsPtr->initialTypeObj = NULL; - optsPtr->multi = 0; optsPtr->confirmOverwrite = 1; /* By default we ask for confirmation */ Tcl_DStringInit(&optsPtr->utfDirString); optsPtr->file[0] = 0; @@ -1224,10 +1286,7 @@ ParseOFNOptions( string = Tcl_GetString(valuePtr); switch (options[index].value) { case FILE_DEFAULT: - if (string[0] == '.') { - string++; - } - optsPtr->extension = string; + optsPtr->extObj = valuePtr; break; case FILE_TYPES: optsPtr->filterObj = valuePtr; @@ -1257,7 +1316,7 @@ ParseOFNOptions( } break; case FILE_TITLE: - optsPtr->title = string; + optsPtr->titleObj = valuePtr; break; case FILE_TYPEVARIABLE: optsPtr->typeVariableObj = valuePtr; @@ -1275,6 +1334,12 @@ ParseOFNOptions( return TCL_ERROR; } break; + case FILE_UNDOCUMENTED_XP_STYLE: + if (Tcl_GetBooleanFromObj(interp, valuePtr, + &optsPtr->forceXPStyle) != TCL_OK) { + return TCL_ERROR; + } + break; } } @@ -1288,143 +1353,209 @@ end: /* interp should already hold error */ /* *---------------------------------------------------------------------- + * VistaFileDialogsAvailable + * + * Checks whether the new (Vista) file dialogs can be used on + * the system. + * + * Returns: + * 1 if new dialogs are available, 0 otherwise + * + * Side effects: + * Loads required procedures dynamically if available. + * If new dialogs are available, COM is also initialized. + *---------------------------------------------------------------------- + */ +static int VistaFileDialogsAvailable() +{ + HRESULT hr; + IFileDialog *fdlgPtr = NULL; + ThreadSpecificData *tsdPtr = + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + if (tsdPtr->newFileDialogsAvailable == FDLG_STATE_INIT) { + tsdPtr->newFileDialogsAvailable = FDLG_STATE_USE_OLD; + LoadShellProcs(); + if (ShellProcs.SHCreateItemFromParsingName != NULL) { + hr = CoInitialize(0); + /* XXX - need we schedule CoUninitialize at thread shutdown ? */ + + /* Ensure all COM interfaces we use are available */ + if (SUCCEEDED(hr)) { + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, + CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgPtr); + if (SUCCEEDED(hr)) { + fdlgPtr->lpVtbl->Release(fdlgPtr); + hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, + CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, + &fdlgPtr); + if (SUCCEEDED(hr)) { + fdlgPtr->lpVtbl->Release(fdlgPtr); + + /* Looks like we have all we need */ + tsdPtr->newFileDialogsAvailable = FDLG_STATE_USE_NEW; + } + } + } + } + } + + return (tsdPtr->newFileDialogsAvailable == FDLG_STATE_USE_NEW); +} + +/* + *---------------------------------------------------------------------- * * GetFileNameVista -- * * Displays the new file dialogs on Vista and later. * * Results: - * TCL_OK - if dialog was successfully displayed + * TCL_OK - dialog was successfully displayed, results returned in interp * TCL_ERROR - error return - * TCL_CONTINUE - new dialogs not available. Caller should go - * on to display the old style dialogs. * * Side effects: - * Dialogs is displayed and results returned in interpreter on success. - * COM subsystem is initialized if not already done. + * Dialogs is displayed *---------------------------------------------------------------------- */ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) { HRESULT hr; + HWND hWnd; + DWORD flags; IFileDialog *fdlgPtr = NULL; + LPWSTR wstr; ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - if (tsdPtr->useNewFileDialogs == FDLG_STATE_USE_OLD) - return TCL_CONTINUE; /* Not an error, go try old style dialogs */ - - if (tsdPtr->useNewFileDialogs == FDLG_STATE_INIT) { - tsdPtr->useNewFileDialogs = FDLG_STATE_USE_OLD; - - hr = CoInitialize(0); - /* On failures we do not error. Instead we fall back to old method */ + if (open) + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, + CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgPtr); + else + hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, + CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, &fdlgPtr); + + /* + * At this point new interfaces are supposed to be available. + * fdlgPtr is actually a IFileOpenDialog or IFileSaveDialog + * both of which inherit from IFileDialog. We use the common + * IFileDialog interface for the most part, casting only for + * type-specific calls. + */ + Tk_MakeWindowExist(optsPtr->tkwin); + hWnd = Tk_GetHWND(Tk_WindowId(optsPtr->tkwin)); + + /* + * Get current settings first because we want to preserve existing + * settings like whether to show hidden files etc. based on the + * user's existing preference + */ + hr = fdlgPtr->lpVtbl->GetOptions(fdlgPtr, &flags); + if (FAILED(hr)) + goto error_return; + + /* Flags are equivalent to those we used in the older API */ + + /* + * Following flags must be set irrespective of original setting + * XXX - should FOS_NOVALIDATE be there ? Note FOS_NOVALIDATE has different + * semantics than OFN_NOVALIDATE in the old API. + */ + flags |= + FOS_FORCEFILESYSTEM | /* Only want files, not other shell items */ + FOS_NOVALIDATE | /* Don't check for access denied etc. */ + FOS_PATHMUSTEXIST; /* The *directory* path must exist */ + + + if (optsPtr->multi) + flags |= FOS_ALLOWMULTISELECT; + else + flags &= ~FOS_ALLOWMULTISELECT; + + if (optsPtr->confirmOverwrite) + flags |= FOS_OVERWRITEPROMPT; + else + flags &= ~FOS_OVERWRITEPROMPT; + + if (optsPtr->extObj != NULL) { + wstr = Tcl_GetUnicode(optsPtr->extObj); + if (wstr[0] == L'.') + ++wstr; + hr = fdlgPtr->lpVtbl->SetDefaultExtension(fdlgPtr, wstr); if (FAILED(hr)) - return TCL_CONTINUE; - - /* Verify interfaces are available */ - if (open) { - hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgPtr); - } else { - hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, &fdlgPtr); - } - - if (FAILED(hr)) { - CoUninitialize(); - return TCL_CONTINUE; - } + goto error_return; + } - tsdPtr->useNewFileDialogs = FDLG_STATE_USE_NEW; - /* - * XXX - need to arrange for CoUninitialize to be called on thread - * exit if useNewFileDialogs is FDLG_STATE_USE_NEW. - */ - } else { - /* FDLG_STATE_USE_NEW */ - if (open) { - hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgPtr); - } else { - hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, &fdlgPtr); - } + if (optsPtr->titleObj != NULL) { + hr = fdlgPtr->lpVtbl->SetTitle(fdlgPtr, + Tcl_GetUnicode(optsPtr->titleObj)); + if (FAILED(hr)) + goto error_return; + } + + if (optsPtr->file[0]) { + hr = fdlgPtr->lpVtbl->SetFileName(fdlgPtr, optsPtr->file); + if (FAILED(hr)) + goto error_return; } - /* At this point new interfaces are supposed to be available */ - fdlgPtr->lpVtbl->Show(fdlgPtr, NULL); + + fdlgPtr->lpVtbl->Show(fdlgPtr, hWnd); fdlgPtr->lpVtbl->Release(fdlgPtr); return TCL_OK; -} - +error_return: + if (fdlgPtr) + fdlgPtr->lpVtbl->Release(fdlgPtr); + Tcl_SetObjResult(interp, TkWin32ErrorObj(hr)); + return TCL_ERROR; +} /* *---------------------------------------------------------------------- * - * GetFileName -- + * GetFileNameXP -- * - * Calls GetOpenFileName() or GetSaveFileName(). + * Displays the old pre-Vista file dialogs. * * Results: - * See user documentation. + * TCL_OK - if dialog was successfully displayed + * TCL_ERROR - error return * * Side effects: - * See user documentation. - * + * See user documentation. *---------------------------------------------------------------------- */ - -static int -GetFileName( - ClientData clientData, /* Main window associated with interpreter. */ - Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ - Tcl_Obj *const objv[], /* Argument objects. */ - int open) /* 1 to call GetOpenFileName(), 0 to call - * GetSaveFileName(). */ +static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, int open) { OPENFILENAME ofn; OFNData ofnData; - OFNOpts ofnOpts; int cdlgerr; int filterIndex = 0, result = TCL_ERROR, winCode, oldMode; HWND hWnd; Tcl_DString utfFilterString, ds; Tcl_DString extString, filterString, dirString, titleString; + const char *str; ThreadSpecificData *tsdPtr = - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); ZeroMemory(&ofnData, sizeof(OFNData)); Tcl_DStringInit(&utfFilterString); - /* Parse the arguments. */ - - result = ParseOFNOptions(clientData, interp, objc, objv, open, &ofnOpts); - if (result != TCL_OK) - return result; - - result = GetFileNameVista(interp, &ofnOpts, open); - if (result != TCL_CONTINUE) { - CleanupOFNOptions(&ofnOpts); - return result; - } - - if (MakeFilter(interp, ofnOpts.filterObj, &utfFilterString, - ofnOpts.initialTypeObj, &filterIndex) != TCL_OK) { + if (MakeFilter(interp, optsPtr->filterObj, &utfFilterString, + optsPtr->initialTypeObj, &filterIndex) != TCL_OK) { goto end; } - Tk_MakeWindowExist(ofnOpts.tkwin); - hWnd = Tk_GetHWND(Tk_WindowId(ofnOpts.tkwin)); + Tk_MakeWindowExist(optsPtr->tkwin); + hWnd = Tk_GetHWND(Tk_WindowId(optsPtr->tkwin)); ZeroMemory(&ofn, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.hInstance = TkWinGetHInstance(ofn.hwndOwner); - ofn.lpstrFile = ofnOpts.file; + ofn.lpstrFile = optsPtr->file; ofn.nMaxFile = TK_MULTI_MAX_PATH; ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_ENABLEHOOK| OFN_ENABLESIZING; @@ -1433,13 +1564,13 @@ GetFileName( if (open != 0) { ofn.Flags |= OFN_FILEMUSTEXIST; - } else if (ofnOpts.confirmOverwrite) { + } else if (optsPtr->confirmOverwrite) { ofn.Flags |= OFN_OVERWRITEPROMPT; } if (tsdPtr->debugFlag != 0) { ofnData.interp = interp; } - if (ofnOpts.multi != 0) { + if (optsPtr->multi != 0) { ofn.Flags |= OFN_ALLOWMULTISELECT; /* @@ -1451,8 +1582,11 @@ GetFileName( ofnData.dynFileBuffer = ckalloc(512 * sizeof(TCHAR)); } - if (ofnOpts.extension != NULL) { - Tcl_WinUtfToTChar(ofnOpts.extension, -1, &extString); + if (optsPtr->extObj != NULL) { + str = Tcl_GetString(optsPtr->extObj); + if (str[0] == '.') + ++str; + Tcl_WinUtfToTChar(str, -1, &extString); ofn.lpstrDefExt = (TCHAR *) Tcl_DStringValue(&extString); } @@ -1461,9 +1595,9 @@ GetFileName( ofn.lpstrFilter = (TCHAR *) Tcl_DStringValue(&filterString); ofn.nFilterIndex = filterIndex; - if (Tcl_DStringValue(&ofnOpts.utfDirString)[0] != '\0') { - Tcl_WinUtfToTChar(Tcl_DStringValue(&ofnOpts.utfDirString), - Tcl_DStringLength(&ofnOpts.utfDirString), &dirString); + if (Tcl_DStringValue(&optsPtr->utfDirString)[0] != '\0') { + Tcl_WinUtfToTChar(Tcl_DStringValue(&optsPtr->utfDirString), + Tcl_DStringLength(&optsPtr->utfDirString), &dirString); } else { /* * NT 5.0 changed the meaning of lpstrInitialDir, so we have to ensure @@ -1472,10 +1606,10 @@ GetFileName( Tcl_DString cwd; - Tcl_DStringFree(&ofnOpts.utfDirString); - if ((Tcl_GetCwd(interp, &ofnOpts.utfDirString) == NULL) || + Tcl_DStringFree(&optsPtr->utfDirString); + if ((Tcl_GetCwd(interp, &optsPtr->utfDirString) == NULL) || (Tcl_TranslateFileName(interp, - Tcl_DStringValue(&ofnOpts.utfDirString), &cwd) == NULL)) { + Tcl_DStringValue(&optsPtr->utfDirString), &cwd) == NULL)) { Tcl_ResetResult(interp); } else { Tcl_WinUtfToTChar(Tcl_DStringValue(&cwd), @@ -1485,8 +1619,8 @@ GetFileName( } ofn.lpstrInitialDir = (TCHAR *) Tcl_DStringValue(&dirString); - if (ofnOpts.title != NULL) { - Tcl_WinUtfToTChar(ofnOpts.title, -1, &titleString); + if (optsPtr->titleObj != NULL) { + Tcl_WinUtfToTChar(Tcl_GetString(optsPtr->titleObj), -1, &titleString); ofn.lpstrTitle = (TCHAR *) Tcl_DStringValue(&titleString); } @@ -1604,20 +1738,20 @@ GetFileName( Tcl_DStringFree(&ds); } result = TCL_OK; - if ((ofn.nFilterIndex > 0) && gotFilename && ofnOpts.typeVariableObj - && ofnOpts.filterObj) { + if ((ofn.nFilterIndex > 0) && gotFilename && optsPtr->typeVariableObj + && optsPtr->filterObj) { int listObjc, count; Tcl_Obj **listObjv = NULL; Tcl_Obj **typeInfo = NULL; - if (Tcl_ListObjGetElements(interp, ofnOpts.filterObj, + if (Tcl_ListObjGetElements(interp, optsPtr->filterObj, &listObjc, &listObjv) != TCL_OK) { result = TCL_ERROR; } else if (Tcl_ListObjGetElements(interp, listObjv[ofn.nFilterIndex - 1], &count, &typeInfo) != TCL_OK) { result = TCL_ERROR; - } else if (Tcl_ObjSetVar2(interp, ofnOpts.typeVariableObj, NULL, + } else if (Tcl_ObjSetVar2(interp, optsPtr->typeVariableObj, NULL, typeInfo[0], TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; } @@ -1644,16 +1778,59 @@ GetFileName( Tcl_DStringFree(&extString); } - end: +end: Tcl_DStringFree(&utfFilterString); if (ofnData.dynFileBuffer != NULL) { ckfree(ofnData.dynFileBuffer); ofnData.dynFileBuffer = NULL; } - CleanupOFNOptions(&ofnOpts); return result; } + + +/* + *---------------------------------------------------------------------- + * + * GetFileName -- + * + * Calls GetOpenFileName() or GetSaveFileName(). + * + * Results: + * See user documentation. + * + * Side effects: + * See user documentation. + * + *---------------------------------------------------------------------- + */ + +static int +GetFileName( + ClientData clientData, /* Main window associated with interpreter. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[], /* Argument objects. */ + int open) /* 1 to call GetOpenFileName(), 0 to call + * GetSaveFileName(). */ +{ + OFNOpts ofnOpts; + int result; + + /* Parse the arguments. */ + result = ParseOFNOptions(clientData, interp, objc, objv, open, &ofnOpts); + if (result != TCL_OK) + return result; + + if (VistaFileDialogsAvailable() && ! ofnOpts.forceXPStyle) + result = GetFileNameVista(interp, &ofnOpts, open); + else + result = GetFileNameXP(interp, &ofnOpts, open); + + CleanupOFNOptions(&ofnOpts); + return result; +} + /* *------------------------------------------------------------------------- diff --git a/win/tkWinInit.c b/win/tkWinInit.c index 4a327a2..b1b2d6b 100644 --- a/win/tkWinInit.c +++ b/win/tkWinInit.c @@ -159,6 +159,57 @@ TkpDisplayWarning( } /* + * ---------------------------------------------------------------------- + * + * Win32ErrorObj -- + * + * Returns a string object containing text from a COM or Win32 error code + * + * Results: + * A Tcl_Obj containing the Win32 error message. + * + * Side effects: + * Removed the error message from the COM threads error object. + * + * ---------------------------------------------------------------------- + */ + +Tcl_Obj* +TkWin32ErrorObj( + HRESULT hrError) +{ + LPTSTR lpBuffer = NULL, p = NULL; + TCHAR sBuffer[30]; + Tcl_Obj* errPtr = NULL; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD)hrError, + LANG_NEUTRAL, (LPTSTR)&lpBuffer, 0, NULL); + + if (lpBuffer == NULL) { + lpBuffer = sBuffer; + wsprintf(sBuffer, TEXT("Error Code: %08lX"), hrError); + } + + if ((p = _tcsrchr(lpBuffer, TEXT('\r'))) != NULL) { + *p = TEXT('\0'); + } + +#ifdef _UNICODE + errPtr = Tcl_NewUnicodeObj(lpBuffer, (int)wcslen(lpBuffer)); +#else + errPtr = Tcl_NewStringObj(lpBuffer, (int)strlen(lpBuffer)); +#endif /* _UNICODE */ + + if (lpBuffer != sBuffer) { + LocalFree((HLOCAL)lpBuffer); + } + + return errPtr; +} + + +/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/win/tkWinInt.h b/win/tkWinInt.h index 6a3978f..0e2c844 100644 --- a/win/tkWinInt.h +++ b/win/tkWinInt.h @@ -201,6 +201,12 @@ MODULE_SCOPE void TkpWinToplevelDetachWindow(TkWindow *winPtr); MODULE_SCOPE int TkpWmGetState(TkWindow *winPtr); /* + * Common routines used in Windows implementation + */ +MODULE_SCOPE Tcl_Obj * TkWin32ErrorObj(HRESULT hrError); + + +/* * The following functions are not present in old versions of Windows * API headers but are used in the Tk source to ensure 64bit * compatibility. diff --git a/win/tkWinSend.c b/win/tkWinSend.c index 7fde655..6c4731a 100644 --- a/win/tkWinSend.c +++ b/win/tkWinSend.c @@ -77,7 +77,6 @@ static int FindInterpreterObject(Tcl_Interp *interp, static int Send(LPDISPATCH pdispInterp, Tcl_Interp *interp, int async, ClientData clientData, int objc, Tcl_Obj *const objv[]); -static Tcl_Obj * Win32ErrorObj(HRESULT hrError); static void SendTrace(const char *format, ...); static Tcl_EventProc SendEventProc; @@ -281,7 +280,7 @@ TkGetInterpNames( if (objList != NULL) { Tcl_DecrRefCount(objList); } - Tcl_SetObjResult(interp, Win32ErrorObj(hr)); + Tcl_SetObjResult(interp, TkWin32ErrorObj(hr)); result = TCL_ERROR; } @@ -451,7 +450,7 @@ FindInterpreterObject( pROT->lpVtbl->Release(pROT); } if (FAILED(hr) && result == TCL_OK) { - Tcl_SetObjResult(interp, Win32ErrorObj(hr)); + Tcl_SetObjResult(interp, TkWin32ErrorObj(hr)); result = TCL_ERROR; } return result; @@ -809,56 +808,6 @@ Send( /* * ---------------------------------------------------------------------- * - * Win32ErrorObj -- - * - * Returns a string object containing text from a COM or Win32 error code - * - * Results: - * A Tcl_Obj containing the Win32 error message. - * - * Side effects: - * Removed the error message from the COM threads error object. - * - * ---------------------------------------------------------------------- - */ - -static Tcl_Obj* -Win32ErrorObj( - HRESULT hrError) -{ - LPTSTR lpBuffer = NULL, p = NULL; - TCHAR sBuffer[30]; - Tcl_Obj* errPtr = NULL; - - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD)hrError, - LANG_NEUTRAL, (LPTSTR)&lpBuffer, 0, NULL); - - if (lpBuffer == NULL) { - lpBuffer = sBuffer; - wsprintf(sBuffer, TEXT("Error Code: %08lX"), hrError); - } - - if ((p = _tcsrchr(lpBuffer, TEXT('\r'))) != NULL) { - *p = TEXT('\0'); - } - -#ifdef _UNICODE - errPtr = Tcl_NewUnicodeObj(lpBuffer, (int)wcslen(lpBuffer)); -#else - errPtr = Tcl_NewStringObj(lpBuffer, (int)strlen(lpBuffer)); -#endif /* _UNICODE */ - - if (lpBuffer != sBuffer) { - LocalFree((HLOCAL)lpBuffer); - } - - return errPtr; -} - -/* - * ---------------------------------------------------------------------- - * * TkWinSend_SetExcepInfo -- * * Convert the error information from a Tcl interpreter into a COM -- cgit v0.12 From e8166f021c14670eed922b9f413059d3d5f729f0 Mon Sep 17 00:00:00 2001 From: ashok Date: Sun, 14 Sep 2014 09:43:57 +0000 Subject: Implemented multiselect in new file dialogs. --- win/tkWinDialog.c | 144 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 116 insertions(+), 28 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index d510654..0b77469 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -28,6 +28,7 @@ #endif /* These needed for compilation with VC++ 5.2 */ +/* XXX - remove these since need at least VC 6 */ #ifndef BIF_EDITBOX #define BIF_EDITBOX 0x10 #endif @@ -36,6 +37,7 @@ #define BIF_VALIDATE 0x0020 #endif +/* This "new" dialog style is now actually the "old" dialog style post-Vista */ #ifndef BIF_NEWDIALOGSTYLE #define BIF_NEWDIALOGSTYLE 0x0040 #endif @@ -59,7 +61,7 @@ typedef struct ThreadSpecificData { HHOOK hMsgBoxHook; /* Hook proc for tk_messageBox and the */ HICON hSmallIcon; /* icons used by a parent to be used in */ HICON hBigIcon; /* the message box */ - int newFileDialogsAvailable; + int newFileDialogsState; #define FDLG_STATE_INIT 0 /* Uninitialized */ #define FDLG_STATE_USE_NEW 1 /* Use the new dialogs */ #define FDLG_STATE_USE_OLD 2 /* Use the old dialogs */ @@ -778,7 +780,8 @@ static void SetTkDialog(ClientData clientData); static const char *ConvertExternalFilename(TCHAR *filename, Tcl_DString *dsPtr); static void LoadShellProcs(void); - +static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, int open); +static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open); /* Definitions of dynamically loaded Win32 calls */ typedef HRESULT (STDAPICALLTYPE SHCreateItemFromParsingNameProc)( @@ -1373,8 +1376,8 @@ static int VistaFileDialogsAvailable() ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - if (tsdPtr->newFileDialogsAvailable == FDLG_STATE_INIT) { - tsdPtr->newFileDialogsAvailable = FDLG_STATE_USE_OLD; + if (tsdPtr->newFileDialogsState == FDLG_STATE_INIT) { + tsdPtr->newFileDialogsState = FDLG_STATE_USE_OLD; LoadShellProcs(); if (ShellProcs.SHCreateItemFromParsingName != NULL) { hr = CoInitialize(0); @@ -1393,14 +1396,14 @@ static int VistaFileDialogsAvailable() fdlgPtr->lpVtbl->Release(fdlgPtr); /* Looks like we have all we need */ - tsdPtr->newFileDialogsAvailable = FDLG_STATE_USE_NEW; + tsdPtr->newFileDialogsState = FDLG_STATE_USE_NEW; } } } } } - return (tsdPtr->newFileDialogsAvailable == FDLG_STATE_USE_NEW); + return (tsdPtr->newFileDialogsState == FDLG_STATE_USE_NEW); } /* @@ -1409,6 +1412,9 @@ static int VistaFileDialogsAvailable() * GetFileNameVista -- * * Displays the new file dialogs on Vista and later. + * This function must generally not be called unless the + * tsdPtr->newFileDialogsState is FDLG_STATE_USE_NEW but if + * it is, it will just pass the call to the older GetFileNameXP * * Results: * TCL_OK - dialog was successfully displayed, results returned in interp @@ -1423,21 +1429,27 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) HRESULT hr; HWND hWnd; DWORD flags; - IFileDialog *fdlgPtr = NULL; + IFileDialog *fdlgIf = NULL; + IShellItem *dirIf = NULL; LPWSTR wstr; ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + if (tsdPtr->newFileDialogsState != FDLG_STATE_USE_NEW) { + /* Should not be called in this condition but be nice about it */ + return GetFileNameXP(interp, optsPtr, open); + } + if (open) hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgPtr); + CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgIf); else hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, &fdlgPtr); + CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, &fdlgIf); /* * At this point new interfaces are supposed to be available. - * fdlgPtr is actually a IFileOpenDialog or IFileSaveDialog + * fdlgIf is actually a IFileOpenDialog or IFileSaveDialog * both of which inherit from IFileDialog. We use the common * IFileDialog interface for the most part, casting only for * type-specific calls. @@ -1450,9 +1462,9 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) * settings like whether to show hidden files etc. based on the * user's existing preference */ - hr = fdlgPtr->lpVtbl->GetOptions(fdlgPtr, &flags); + hr = fdlgIf->lpVtbl->GetOptions(fdlgIf, &flags); if (FAILED(hr)) - goto error_return; + goto vamoose; /* Flags are equivalent to those we used in the older API */ @@ -1477,38 +1489,109 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) else flags &= ~FOS_OVERWRITEPROMPT; + hr = fdlgIf->lpVtbl->SetOptions(fdlgIf, flags); + if (FAILED(hr)) + goto vamoose; + if (optsPtr->extObj != NULL) { wstr = Tcl_GetUnicode(optsPtr->extObj); if (wstr[0] == L'.') ++wstr; - hr = fdlgPtr->lpVtbl->SetDefaultExtension(fdlgPtr, wstr); + hr = fdlgIf->lpVtbl->SetDefaultExtension(fdlgIf, wstr); if (FAILED(hr)) - goto error_return; + goto vamoose; } if (optsPtr->titleObj != NULL) { - hr = fdlgPtr->lpVtbl->SetTitle(fdlgPtr, + hr = fdlgIf->lpVtbl->SetTitle(fdlgIf, Tcl_GetUnicode(optsPtr->titleObj)); if (FAILED(hr)) - goto error_return; + goto vamoose; } if (optsPtr->file[0]) { - hr = fdlgPtr->lpVtbl->SetFileName(fdlgPtr, optsPtr->file); + hr = fdlgIf->lpVtbl->SetFileName(fdlgIf, optsPtr->file); if (FAILED(hr)) - goto error_return; + goto vamoose; } + if (Tcl_DStringValue(&optsPtr->utfDirString)[0] != '\0') { + Tcl_DString dirString; + Tcl_WinUtfToTChar(Tcl_DStringValue(&optsPtr->utfDirString), + Tcl_DStringLength(&optsPtr->utfDirString), &dirString); + hr = ShellProcs.SHCreateItemFromParsingName( + (TCHAR *) Tcl_DStringValue(&dirString), NULL, + &IID_IShellItem, &dirIf); + /* XXX - Note on failure we do not raise error, simply ignore ini dir */ + if (SUCCEEDED(hr)) { + /* Note we use SetFolder, not SetDefaultFolder - see MSDN docs */ + fdlgIf->lpVtbl->SetFolder(fdlgIf, dirIf); /* Ignore errors */ + } + Tcl_DStringFree(&dirString); + } + + hr = fdlgIf->lpVtbl->Show(fdlgIf, hWnd); + if (SUCCEEDED(hr)) { + if (open && optsPtr->multi) { + IShellItemArray *multiIf; + DWORD dw, count; + IFileOpenDialog *fodIf = (IFileOpenDialog *) fdlgIf; + hr = fodIf->lpVtbl->GetResults(fodIf, &multiIf); + if (SUCCEEDED(hr)) { + Tcl_Obj *multiObj = Tcl_NewListObj(count, NULL); + hr = multiIf->lpVtbl->GetCount(multiIf, &count); + if (SUCCEEDED(hr)) { + IShellItem *itemIf; + for (dw = 0; dw < count; ++dw) { + hr = multiIf->lpVtbl->GetItemAt(multiIf, dw, &itemIf); + if (FAILED(hr)) + break; + hr = itemIf->lpVtbl->GetDisplayName(itemIf, + SIGDN_FILESYSPATH, &wstr); + if (SUCCEEDED(hr)) { + Tcl_ListObjAppendElement(interp, multiObj, + Tcl_NewUnicodeObj(wstr, -1)); + } + itemIf->lpVtbl->Release(itemIf); + if (FAILED(hr)) + break; + } + } + multiIf->lpVtbl->Release(multiIf); + if (SUCCEEDED(hr)) + Tcl_SetObjResult(interp, multiObj); + else + Tcl_DecrRefCount(multiObj); + } + } else { + IShellItem *resultIf; + hr = fdlgIf->lpVtbl->GetResult(fdlgIf, &resultIf); + if (SUCCEEDED(hr)) { + hr = resultIf->lpVtbl->GetDisplayName(resultIf, SIGDN_FILESYSPATH, + &wstr); + if (SUCCEEDED(hr)) { + Tcl_SetObjResult(interp, Tcl_NewUnicodeObj(wstr, -1)); + CoTaskMemFree(wstr); + } + resultIf->lpVtbl->Release(resultIf); + } + } + } else { + if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) + hr = 0; /* User cancelled, return empty string */ + } - fdlgPtr->lpVtbl->Show(fdlgPtr, hWnd); - fdlgPtr->lpVtbl->Release(fdlgPtr); - return TCL_OK; - -error_return: - if (fdlgPtr) - fdlgPtr->lpVtbl->Release(fdlgPtr); - Tcl_SetObjResult(interp, TkWin32ErrorObj(hr)); - return TCL_ERROR; +vamoose: /* (hr != 0) => error */ + if (dirIf) + dirIf->lpVtbl->Release(dirIf); + if (fdlgIf) + fdlgIf->lpVtbl->Release(fdlgIf); + if (hr == 0) + return TCL_OK; + else { + Tcl_SetObjResult(interp, TkWin32ErrorObj(hr)); + return TCL_ERROR; + } } @@ -1542,6 +1625,9 @@ static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, int open) ZeroMemory(&ofnData, sizeof(OFNData)); Tcl_DStringInit(&utfFilterString); + Tcl_DStringInit(&dirString); /* XXX - original code was missing this + leaving dirString uninitialized for + the unlikely code path where cwd failed */ if (MakeFilter(interp, optsPtr->filterObj, &utfFilterString, optsPtr->initialTypeObj, &filterIndex) != TCL_OK) { @@ -1558,7 +1644,7 @@ static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, int open) ofn.lpstrFile = optsPtr->file; ofn.nMaxFile = TK_MULTI_MAX_PATH; ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR - | OFN_EXPLORER | OFN_ENABLEHOOK| OFN_ENABLESIZING; + | OFN_EXPLORER| OFN_ENABLEHOOK| OFN_ENABLESIZING; ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProc; ofn.lCustData = (LPARAM) &ofnData; @@ -1771,6 +1857,8 @@ static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, int open) Tcl_DStringFree(&titleString); } if (ofn.lpstrInitialDir != NULL) { + /* XXX - huh? lpstrInitialDir is set from Tcl_DStringValue which + can never return NULL */ Tcl_DStringFree(&dirString); } Tcl_DStringFree(&filterString); -- cgit v0.12 From 012193adf627e66fafc0ef0e18e8e90feddfce89 Mon Sep 17 00:00:00 2001 From: ashok Date: Sun, 14 Sep 2014 17:32:49 +0000 Subject: Implemented -filetypes and -typevariable for new Vista file dialogs. --- win/tkWinDialog.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 207 insertions(+), 13 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 0b77469..485b9ff 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -780,8 +780,13 @@ static void SetTkDialog(ClientData clientData); static const char *ConvertExternalFilename(TCHAR *filename, Tcl_DString *dsPtr); static void LoadShellProcs(void); + static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, int open); static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open); +static int MakeFilterVista(Tcl_Interp *interp, OFNOpts *optsPtr, + DWORD *countPtr, COMDLG_FILTERSPEC **dlgFilterPtrPtr, + DWORD *defaultFilterIndexPtr); +static void FreeFilterVista(DWORD count, COMDLG_FILTERSPEC *dlgFilterPtr); /* Definitions of dynamically loaded Win32 calls */ typedef HRESULT (STDAPICALLTYPE SHCreateItemFromParsingNameProc)( @@ -1428,10 +1433,12 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) { HRESULT hr; HWND hWnd; - DWORD flags; + DWORD flags, nfilters, defaultFilterIndex; + COMDLG_FILTERSPEC *filterPtr = NULL; IFileDialog *fdlgIf = NULL; IShellItem *dirIf = NULL; LPWSTR wstr; + Tcl_Obj *resultObj = NULL; ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); @@ -1440,13 +1447,6 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) return GetFileNameXP(interp, optsPtr, open); } - if (open) - hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgIf); - else - hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, &fdlgIf); - /* * At this point new interfaces are supposed to be available. * fdlgIf is actually a IFileOpenDialog or IFileSaveDialog @@ -1458,6 +1458,38 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) hWnd = Tk_GetHWND(Tk_WindowId(optsPtr->tkwin)); /* + * The only validation we need to do w.r.t caller supplied data + * is the filter specification so do that before creating + */ + if (MakeFilterVista(interp, optsPtr, &nfilters, &filterPtr, + &defaultFilterIndex) != TCL_OK) + return TCL_ERROR; + + /* + * Beyond this point, do not just return on error as there will be + * resources that need to be released/freed. + */ + + if (open) + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, + CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgIf); + else + hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, + CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, &fdlgIf); + + if (FAILED(hr)) + goto vamoose; + + if (filterPtr) { + hr = fdlgIf->lpVtbl->SetFileTypes(fdlgIf, nfilters, filterPtr); + if (FAILED(hr)) + goto vamoose; + hr = fdlgIf->lpVtbl->SetFileTypeIndex(fdlgIf, defaultFilterIndex); + if (FAILED(hr)) + goto vamoose; + } + + /* * Get current settings first because we want to preserve existing * settings like whether to show hidden files etc. based on the * user's existing preference @@ -1538,8 +1570,9 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) IFileOpenDialog *fodIf = (IFileOpenDialog *) fdlgIf; hr = fodIf->lpVtbl->GetResults(fodIf, &multiIf); if (SUCCEEDED(hr)) { - Tcl_Obj *multiObj = Tcl_NewListObj(count, NULL); + Tcl_Obj *multiObj; hr = multiIf->lpVtbl->GetCount(multiIf, &count); + multiObj = Tcl_NewListObj(count, NULL); if (SUCCEEDED(hr)) { IShellItem *itemIf; for (dw = 0; dw < count; ++dw) { @@ -1559,7 +1592,7 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) } multiIf->lpVtbl->Release(multiIf); if (SUCCEEDED(hr)) - Tcl_SetObjResult(interp, multiObj); + resultObj = multiObj; else Tcl_DecrRefCount(multiObj); } @@ -1570,12 +1603,26 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) hr = resultIf->lpVtbl->GetDisplayName(resultIf, SIGDN_FILESYSPATH, &wstr); if (SUCCEEDED(hr)) { - Tcl_SetObjResult(interp, Tcl_NewUnicodeObj(wstr, -1)); + resultObj = Tcl_NewUnicodeObj(wstr, -1); CoTaskMemFree(wstr); } resultIf->lpVtbl->Release(resultIf); } } + if (SUCCEEDED(hr)) { + if (filterPtr && optsPtr->typeVariableObj) { + UINT ftix; + hr = fdlgIf->lpVtbl->GetFileTypeIndex(fdlgIf, &ftix); + if (SUCCEEDED(hr)) { + /* Note ftix is a 1-based index */ + if (ftix > 0 && ftix <= nfilters) { + Tcl_ObjSetVar2(interp, optsPtr->typeVariableObj, NULL, + Tcl_NewUnicodeObj(filterPtr[ftix-1].pszName, -1), + TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG); + } + } + } + } } else { if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) hr = 0; /* User cancelled, return empty string */ @@ -1586,9 +1633,17 @@ vamoose: /* (hr != 0) => error */ dirIf->lpVtbl->Release(dirIf); if (fdlgIf) fdlgIf->lpVtbl->Release(fdlgIf); - if (hr == 0) + + if (filterPtr) + FreeFilterVista(nfilters, filterPtr); + + if (hr == 0) { + if (resultObj) /* May be NULL if user cancelled */ + Tcl_SetObjResult(interp, resultObj); return TCL_OK; - else { + } else { + if (resultObj) + Tcl_DecrRefCount(resultObj); Tcl_SetObjResult(interp, TkWin32ErrorObj(hr)); return TCL_ERROR; } @@ -2242,6 +2297,145 @@ MakeFilter( /* *---------------------------------------------------------------------- * + * FreeFilterVista + * + * Frees storage previously allocated by MakeFilterVista. + * count is the number of elements in dlgFilterPtr[] + */ +static void FreeFilterVista(DWORD count, COMDLG_FILTERSPEC *dlgFilterPtr) +{ + if (dlgFilterPtr != NULL) { + DWORD dw; + for (dw = 0; dw < count; ++dw) { + if (dlgFilterPtr[dw].pszName != NULL) + ckfree(dlgFilterPtr[dw].pszName); + if (dlgFilterPtr[dw].pszSpec != NULL) + ckfree(dlgFilterPtr[dw].pszSpec); + } + ckfree(dlgFilterPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * MakeFilterVista -- + * + * Returns file type filters in a format required + * by the Vista file dialogs. + * + * Results: + * A standard TCL return value. + * + * Side effects: + * Various values are returned through the parameters as + * described in the comments below. + *---------------------------------------------------------------------- + */ +static int MakeFilterVista( + Tcl_Interp *interp, /* Current interpreter. */ + OFNOpts *optsPtr, /* Caller specified options */ + DWORD *countPtr, /* Will hold number of filters */ + COMDLG_FILTERSPEC **dlgFilterPtrPtr, /* Will hold pointer to filter array. + Set to NULL if no filters specified. + Must be freed by calling + FreeFilterVista */ + DWORD *initialIndexPtr) /* Will hold index of default type */ +{ + COMDLG_FILTERSPEC *dlgFilterPtr; + const char *initial = NULL; + FileFilterList flist; + FileFilter *filterPtr; + DWORD initialIndex = 0; + Tcl_DString ds, patterns; + int i; + + if (optsPtr->filterObj == NULL) { + *dlgFilterPtrPtr = NULL; + *countPtr = 0; + return TCL_OK; + } + + if (optsPtr->initialTypeObj) + initial = Tcl_GetString(optsPtr->initialTypeObj); + + TkInitFileFilters(&flist); + if (TkGetFileFilters(interp, &flist, optsPtr->filterObj, 1) != TCL_OK) + return TCL_ERROR; + + if (flist.filters == NULL) { + *dlgFilterPtrPtr = NULL; + *countPtr = 0; + return TCL_OK; + } + + Tcl_DStringInit(&ds); + Tcl_DStringInit(&patterns); + dlgFilterPtr = ckalloc(flist.numFilters * sizeof(*dlgFilterPtr)); + + for (i = 0, filterPtr = flist.filters; + filterPtr; + filterPtr = filterPtr->next, ++i) { + const char *sep; + FileFilterClause *clausePtr; + int nbytes; + + /* Check if this entry should be shown as the default */ + if (initial && strcmp(initial, filterPtr->name) == 0) + initialIndex = i+1; /* Windows filter indices are 1-based */ + + /* First stash away the text description of the pattern */ + Tcl_WinUtfToTChar(filterPtr->name, -1, &ds); + nbytes = Tcl_DStringLength(&ds); /* # bytes, not Unicode chars */ + nbytes += sizeof(WCHAR); /* Terminating \0 */ + dlgFilterPtr[i].pszName = ckalloc(nbytes); + memmove(dlgFilterPtr[i].pszName, Tcl_DStringValue(&ds), nbytes); + Tcl_DStringFree(&ds); + + /* + * Loop through and join patterns with a ";" Each "clause" + * corresponds to a single textual description (called typename) + * in the tk_getOpenFile docs. Each such typename may occur + * multiple times and all these form a single filter entry + * with one clause per occurence. Further each clause may specify + * multiple patterns. Hence the nested loop here. + */ + sep = ""; + for (clausePtr=filterPtr->clauses ; clausePtr; + clausePtr=clausePtr->next) { + GlobPattern *globPtr; + for (globPtr = clausePtr->patterns; globPtr; + globPtr = globPtr->next) { + Tcl_DStringAppend(&patterns, sep, -1); + Tcl_DStringAppend(&patterns, globPtr->pattern, -1); + sep = ";"; + } + } + + /* Again we need a Unicode form of the string */ + Tcl_WinUtfToTChar(Tcl_DStringValue(&patterns), -1, &ds); + nbytes = Tcl_DStringLength(&ds); /* # bytes, not Unicode chars */ + nbytes += sizeof(WCHAR); /* Terminating \0 */ + dlgFilterPtr[i].pszSpec = ckalloc(nbytes); + memmove(dlgFilterPtr[i].pszSpec, Tcl_DStringValue(&ds), nbytes); + Tcl_DStringFree(&ds); + Tcl_DStringFree(&patterns); + } + + if (initialIndex == 0) + initialIndex = 1; /* If no default, show first entry */ + *initialIndexPtr = initialIndex; + *dlgFilterPtrPtr = dlgFilterPtr; + *countPtr = flist.numFilters; + + TkFreeFileFilters(&flist); + return TCL_OK; +} + + +/* + *---------------------------------------------------------------------- + * * Tk_ChooseDirectoryObjCmd -- * * This function implements the "tk_chooseDirectory" dialog box for the -- cgit v0.12 From ac7bfc0e538bc33acfb017888c77a458b586c160 Mon Sep 17 00:00:00 2001 From: ashok Date: Wed, 17 Sep 2014 17:18:53 +0000 Subject: Implemented Vista+ tk_chooseDirectory dialogs --- win/tkWinDialog.c | 717 ++++++++++++++++++------------------------------------ 1 file changed, 239 insertions(+), 478 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 485b9ff..6b7035d 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -179,7 +179,8 @@ typedef struct OFNOpts { Tcl_Obj *initialTypeObj; /* Initial value of above, or NULL */ Tcl_DString utfDirString; /* Initial dir */ int multi; /* Multiple selection enabled */ - int confirmOverwrite; /* Multiple selection enabled */ + int confirmOverwrite; /* Confirm before overwriting */ + int mustExist; /* Used only for */ int forceXPStyle; /* XXX - Force XP style even on newer systems */ TCHAR file[TK_MULTI_MAX_PATH]; /* File name XXX - fixed size because it was so @@ -190,6 +191,14 @@ typedef struct OFNOpts { */ } OFNOpts; +/* Define the operation for which option parsing is to be done. */ +enum OFNOper { + OFN_FILE_SAVE, /* tk_getOpenFile */ + OFN_FILE_OPEN, /* tk_getSaveFile */ + OFN_DIR_CHOOSE /* tk_chooseDirectory */ +}; + + /* * The following definitions are required when using older versions of * Visual C++ (like 6.0) and possibly MingW. Those headers do not contain @@ -217,63 +226,31 @@ typedef struct IShellItemArrayVtbl BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( - IShellItemArray * This, - /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( - IShellItemArray * This); - - ULONG ( STDMETHODCALLTYPE *Release )( - IShellItemArray * This); - - HRESULT ( STDMETHODCALLTYPE *BindToHandler )( - IShellItemArray * This, - /* [unique][in] */ IBindCtx *pbc, - /* [in] */ REFGUID bhid, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void **ppvOut); - - HRESULT ( STDMETHODCALLTYPE *GetPropertyStore )( - IShellItemArray * This, - /* Actually enum GETPROPERTYSTOREFLAGS, but we do not use this call */ - /* [in] */ int flags, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void **ppv); - + IShellItemArray * this, REFIID riid,void **ppvObject); + ULONG ( STDMETHODCALLTYPE *AddRef )(IShellItemArray * this); + ULONG ( STDMETHODCALLTYPE *Release )(IShellItemArray * this); + HRESULT ( STDMETHODCALLTYPE *BindToHandler )(IShellItemArray * this, + IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppvOut); + /* flags is actually is enum GETPROPERTYSTOREFLAGS */ + HRESULT ( STDMETHODCALLTYPE *GetPropertyStore )( + IShellItemArray * this, int flags, REFIID riid, void **ppv); + /* keyType actually REFPROPERTYKEY */ HRESULT ( STDMETHODCALLTYPE *GetPropertyDescriptionList )( - IShellItemArray * This, - /* Actually REFPROPERTYKEY, but this call is not used */ - /* [in] */ void* keyType, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void **ppv); - - HRESULT ( STDMETHODCALLTYPE *GetAttributes )( - IShellItemArray * This, - /* [in] */ SIATTRIBFLAGS AttribFlags, - /* [in] */ SFGAOF sfgaoMask, - /* [out] */ SFGAOF *psfgaoAttribs); - - HRESULT ( STDMETHODCALLTYPE *GetCount )( - IShellItemArray * This, - /* [out] */ DWORD *pdwNumItems); - + IShellItemArray * this, void* keyType, REFIID riid, void **ppv); + HRESULT ( STDMETHODCALLTYPE *GetAttributes )(IShellItemArray * this, + SIATTRIBFLAGS AttribFlags, SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs); + HRESULT ( STDMETHODCALLTYPE *GetCount )( + IShellItemArray * this, DWORD *pdwNumItems); HRESULT ( STDMETHODCALLTYPE *GetItemAt )( - IShellItemArray * This, - /* [in] */ DWORD dwIndex, - /* [out] */ IShellItem **ppsi); - - HRESULT ( STDMETHODCALLTYPE *EnumItems )( - IShellItemArray * This, - /* Actually IEnumShellItems **, but we do not use this call */ - /* [out] */ void **ppenumShellItems); + IShellItemArray * this, DWORD dwIndex, IShellItem **ppsi); + /* ppenumShellItems actually (IEnumShellItems **) */ + HRESULT ( STDMETHODCALLTYPE *EnumItems )( + IShellItemArray * this, void **ppenumShellItems); END_INTERFACE } IShellItemArrayVtbl; -struct IShellItemArray -{ +struct IShellItemArray { CONST_VTBL struct IShellItemArrayVtbl *lpVtbl; }; @@ -342,120 +319,56 @@ typedef struct IFileDialogVtbl BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( - IFileDialog * This, - /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( - IFileDialog * This); - - ULONG ( STDMETHODCALLTYPE *Release )( - IFileDialog * This); - - /* [local] */ HRESULT ( STDMETHODCALLTYPE *Show )( - IFileDialog * This, - /* [annotation][unique][in] */ - HWND hwndOwner); - - HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( - IFileDialog * This, - /* [in] */ UINT cFileTypes, - /* [size_is][in] */ const COMDLG_FILTERSPEC *rgFilterSpec); - - HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( - IFileDialog * This, - /* [in] */ UINT iFileType); - - HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( - IFileDialog * This, - /* [out] */ UINT *piFileType); - + IFileDialog * this, REFIID riid, void **ppvObject); + ULONG ( STDMETHODCALLTYPE *AddRef )( IFileDialog * this); + ULONG ( STDMETHODCALLTYPE *Release )( IFileDialog * this); + HRESULT ( STDMETHODCALLTYPE *Show )( IFileDialog * this, HWND hwndOwner); + HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( IFileDialog * this, + UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec); + HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )(IFileDialog * this, UINT); + HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )(IFileDialog * this, UINT *); + /* XXX - Actually pfde is IFileDialogEvents* but we do not use + this call and do not want to define IFileDialogEvents as that + pulls in a whole bunch of other stuff. */ HRESULT ( STDMETHODCALLTYPE *Advise )( - IFileDialog * This, - /* XXX - Actually pfde is IFileDialogEvents* but we do not use - this call and do not want to define IFileDialogEvents as that - pulls in a whole bunch of other stuff. */ - /* [in] */ void *pfde, - /* [out] */ DWORD *pdwCookie); - - HRESULT ( STDMETHODCALLTYPE *Unadvise )( - IFileDialog * This, - /* [in] */ DWORD dwCookie); - + IFileDialog * this, void *pfde, DWORD *pdwCookie); + HRESULT ( STDMETHODCALLTYPE *Unadvise )(IFileDialog * this, DWORD dwCookie); HRESULT ( STDMETHODCALLTYPE *SetOptions )( - IFileDialog * This, - /* [in] */ FILEOPENDIALOGOPTIONS fos); - + IFileDialog * this, FILEOPENDIALOGOPTIONS fos); HRESULT ( STDMETHODCALLTYPE *GetOptions )( - IFileDialog * This, - /* [out] */ FILEOPENDIALOGOPTIONS *pfos); - - HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( - IFileDialog * This, - /* [in] */ IShellItem *psi); - - HRESULT ( STDMETHODCALLTYPE *SetFolder )( - IFileDialog * This, - /* [in] */ IShellItem *psi); - + IFileDialog * this, FILEOPENDIALOGOPTIONS *pfos); + HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( + IFileDialog * this, IShellItem *psi); + HRESULT ( STDMETHODCALLTYPE *SetFolder )( + IFileDialog * this, IShellItem *psi); HRESULT ( STDMETHODCALLTYPE *GetFolder )( - IFileDialog * This, - /* [out] */ IShellItem **ppsi); - + IFileDialog * this, IShellItem **ppsi); HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( - IFileDialog * This, - /* [out] */ IShellItem **ppsi); - + IFileDialog * this, IShellItem **ppsi); HRESULT ( STDMETHODCALLTYPE *SetFileName )( - IFileDialog * This, - /* [string][in] */ LPCWSTR pszName); - + IFileDialog * this, LPCWSTR pszName); HRESULT ( STDMETHODCALLTYPE *GetFileName )( - IFileDialog * This, - /* [string][out] */ LPWSTR *pszName); - - HRESULT ( STDMETHODCALLTYPE *SetTitle )( - IFileDialog * This, - /* [string][in] */ LPCWSTR pszTitle); - + IFileDialog * this, LPWSTR *pszName); + HRESULT ( STDMETHODCALLTYPE *SetTitle )( + IFileDialog * this, LPCWSTR pszTitle); HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( - IFileDialog * This, - /* [string][in] */ LPCWSTR pszText); - + IFileDialog * this, LPCWSTR pszText); HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( - IFileDialog * This, - /* [string][in] */ LPCWSTR pszLabel); - - HRESULT ( STDMETHODCALLTYPE *GetResult )( - IFileDialog * This, - /* [out] */ IShellItem **ppsi); - + IFileDialog * this, LPCWSTR pszLabel); + HRESULT ( STDMETHODCALLTYPE *GetResult )( + IFileDialog * this, IShellItem **ppsi); HRESULT ( STDMETHODCALLTYPE *AddPlace )( - IFileDialog * This, - /* [in] */ IShellItem *psi, - /* [in] */ FDAP fdap); - + IFileDialog * this, IShellItem *psi, FDAP fdap); HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( - IFileDialog * This, - /* [string][in] */ LPCWSTR pszDefaultExtension); - - HRESULT ( STDMETHODCALLTYPE *Close )( - IFileDialog * This, - /* [in] */ HRESULT hr); - - HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( - IFileDialog * This, - /* [in] */ REFGUID guid); - - HRESULT ( STDMETHODCALLTYPE *ClearClientData )( - IFileDialog * This); - + IFileDialog * this, LPCWSTR pszDefaultExtension); + HRESULT ( STDMETHODCALLTYPE *Close )( IFileDialog * this, HRESULT hr); + HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( + IFileDialog * this, REFGUID guid); + HRESULT ( STDMETHODCALLTYPE *ClearClientData )( IFileDialog * this); + /* pFilter actually IShellItemFilter. But deprecated in Win7 AND we do + not use it anyways. So define as void* */ HRESULT ( STDMETHODCALLTYPE *SetFilter )( - IFileDialog * This, - /* XXX - Actually IShellItemFilter. But deprecated in Win7 AND we do - not use it anyways. So define as void* */ - /* [in] */ void *pFilter); + IFileDialog * this, void *pFilter); END_INTERFACE } IFileDialogVtbl; @@ -470,144 +383,68 @@ typedef struct IFileSaveDialogVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( - IFileSaveDialog * This, - /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( - IFileSaveDialog * This); - - ULONG ( STDMETHODCALLTYPE *Release )( - IFileSaveDialog * This); - - /* [local] */ HRESULT ( STDMETHODCALLTYPE *Show )( - IFileSaveDialog * This, - /* [annotation][unique][in] */ - HWND hwndOwner); - - HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( - IFileSaveDialog * This, - /* [in] */ UINT cFileTypes, - /* [size_is][in] */ const COMDLG_FILTERSPEC *rgFilterSpec); - - HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( - IFileSaveDialog * This, - /* [in] */ UINT iFileType); - + IFileSaveDialog * this, REFIID riid, void **ppvObject); + ULONG ( STDMETHODCALLTYPE *AddRef )( IFileSaveDialog * this); + ULONG ( STDMETHODCALLTYPE *Release )( IFileSaveDialog * this); + HRESULT ( STDMETHODCALLTYPE *Show )( + IFileSaveDialog * this, HWND hwndOwner); + HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( IFileSaveDialog * this, + UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec); + HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( + IFileSaveDialog * this, UINT iFileType); HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( - IFileSaveDialog * This, - /* [out] */ UINT *piFileType); - + IFileSaveDialog * this, UINT *piFileType); + /* Actually pfde is IFileSaveDialogEvents* */ HRESULT ( STDMETHODCALLTYPE *Advise )( - IFileSaveDialog * This, - /* XXX - Actually pfde is IFileSaveDialogEvents* but we do not use - this call and do not want to define IFileSaveDialogEvents as that - pulls in a whole bunch of other stuff. */ - /* [in] */ void *pfde, - /* [out] */ DWORD *pdwCookie); - - HRESULT ( STDMETHODCALLTYPE *Unadvise )( - IFileSaveDialog * This, - /* [in] */ DWORD dwCookie); - + IFileSaveDialog * this, void *pfde, DWORD *pdwCookie); + HRESULT ( STDMETHODCALLTYPE *Unadvise )( IFileSaveDialog * this, DWORD); HRESULT ( STDMETHODCALLTYPE *SetOptions )( - IFileSaveDialog * This, - /* [in] */ FILEOPENDIALOGOPTIONS fos); - + IFileSaveDialog * this, FILEOPENDIALOGOPTIONS fos); HRESULT ( STDMETHODCALLTYPE *GetOptions )( - IFileSaveDialog * This, - /* [out] */ FILEOPENDIALOGOPTIONS *pfos); - + IFileSaveDialog * this, FILEOPENDIALOGOPTIONS *pfos); HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( - IFileSaveDialog * This, - /* [in] */ IShellItem *psi); - - HRESULT ( STDMETHODCALLTYPE *SetFolder )( - IFileSaveDialog * This, - /* [in] */ IShellItem *psi); - + IFileSaveDialog * this, IShellItem *psi); + HRESULT ( STDMETHODCALLTYPE *SetFolder )( + IFileSaveDialog * this, IShellItem *psi); HRESULT ( STDMETHODCALLTYPE *GetFolder )( - IFileSaveDialog * This, - /* [out] */ IShellItem **ppsi); - + IFileSaveDialog * this, IShellItem **ppsi); HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( - IFileSaveDialog * This, - /* [out] */ IShellItem **ppsi); - + IFileSaveDialog * this, IShellItem **ppsi); HRESULT ( STDMETHODCALLTYPE *SetFileName )( - IFileSaveDialog * This, - /* [string][in] */ LPCWSTR pszName); - + IFileSaveDialog * this, LPCWSTR pszName); HRESULT ( STDMETHODCALLTYPE *GetFileName )( - IFileSaveDialog * This, - /* [string][out] */ LPWSTR *pszName); - + IFileSaveDialog * this, LPWSTR *pszName); HRESULT ( STDMETHODCALLTYPE *SetTitle )( - IFileSaveDialog * This, - /* [string][in] */ LPCWSTR pszTitle); - + IFileSaveDialog * this, LPCWSTR pszTitle); HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( - IFileSaveDialog * This, - /* [string][in] */ LPCWSTR pszText); - + IFileSaveDialog * this, LPCWSTR pszText); HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( - IFileSaveDialog * This, - /* [string][in] */ LPCWSTR pszLabel); - + IFileSaveDialog * this, LPCWSTR pszLabel); HRESULT ( STDMETHODCALLTYPE *GetResult )( - IFileSaveDialog * This, - /* [out] */ IShellItem **ppsi); - + IFileSaveDialog * this, IShellItem **ppsi); HRESULT ( STDMETHODCALLTYPE *AddPlace )( - IFileSaveDialog * This, - /* [in] */ IShellItem *psi, - /* [in] */ FDAP fdap); - + IFileSaveDialog * this, IShellItem *psi, FDAP fdap); HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( - IFileSaveDialog * This, - /* [string][in] */ LPCWSTR pszDefaultExtension); - - HRESULT ( STDMETHODCALLTYPE *Close )( - IFileSaveDialog * This, - /* [in] */ HRESULT hr); - - HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( - IFileSaveDialog * This, - /* [in] */ REFGUID guid); - - HRESULT ( STDMETHODCALLTYPE *ClearClientData )( - IFileSaveDialog * This); - + IFileSaveDialog * this, LPCWSTR pszDefaultExtension); + HRESULT ( STDMETHODCALLTYPE *Close )( IFileSaveDialog * this, HRESULT hr); + HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( + IFileSaveDialog * this, REFGUID guid); + HRESULT ( STDMETHODCALLTYPE *ClearClientData )( IFileSaveDialog * this); + /* pFilter Actually IShellItemFilter* */ HRESULT ( STDMETHODCALLTYPE *SetFilter )( - IFileSaveDialog * This, - /* XXX - Actually IShellItemFilter. But deprecated in Win7 AND we do - not use it anyways. So define as void* */ - /* [in] */ void *pFilter); - + IFileSaveDialog * this, void *pFilter); HRESULT ( STDMETHODCALLTYPE *SetSaveAsItem )( - IFileSaveDialog * This, - /* [in] */ IShellItem *psi); - + IFileSaveDialog * this, IShellItem *psi); HRESULT ( STDMETHODCALLTYPE *SetProperties )( - IFileSaveDialog * This, - /* [in] */ IPropertyStore *pStore); - + IFileSaveDialog * this, IPropertyStore *pStore); HRESULT ( STDMETHODCALLTYPE *SetCollectedProperties )( - IFileSaveDialog * This, - /* [in] */ IPropertyDescriptionList *pList, - /* [in] */ BOOL fAppendDefault); - + IFileSaveDialog * this, IPropertyDescriptionList *pList, + BOOL fAppendDefault); HRESULT ( STDMETHODCALLTYPE *GetProperties )( - IFileSaveDialog * This, - /* [out] */ IPropertyStore **ppStore); - + IFileSaveDialog * this, IPropertyStore **ppStore); HRESULT ( STDMETHODCALLTYPE *ApplyProperties )( - IFileSaveDialog * This, - /* [in] */ IShellItem *psi, - /* [in] */ IPropertyStore *pStore, - /* [unique][in] */ HWND hwnd, - /* [unique][in] */ IFileOperationProgressSink *pSink); + IFileSaveDialog * this, IShellItem *psi, IPropertyStore *pStore, + HWND hwnd, IFileOperationProgressSink *pSink); END_INTERFACE @@ -622,128 +459,61 @@ typedef struct IFileOpenDialogVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( - IFileOpenDialog * This, - /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - void **ppvObject); - - ULONG ( STDMETHODCALLTYPE *AddRef )( - IFileOpenDialog * This); - - ULONG ( STDMETHODCALLTYPE *Release )( - IFileOpenDialog * This); - - /* [local] */ HRESULT ( STDMETHODCALLTYPE *Show )( - IFileOpenDialog * This, - /* [annotation][unique][in] */ - HWND hwndOwner); - - HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( - IFileOpenDialog * This, - /* [in] */ UINT cFileTypes, - /* [size_is][in] */ const COMDLG_FILTERSPEC *rgFilterSpec); - + IFileOpenDialog * this, REFIID riid, void **ppvObject); + ULONG ( STDMETHODCALLTYPE *AddRef )( IFileOpenDialog * this); + ULONG ( STDMETHODCALLTYPE *Release )( IFileOpenDialog * this); + HRESULT ( STDMETHODCALLTYPE *Show )( IFileOpenDialog * this, HWND); + HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( IFileOpenDialog * this, + UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec); HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( - IFileOpenDialog * This, - /* [in] */ UINT iFileType); - + IFileOpenDialog * this, UINT iFileType); HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( - IFileOpenDialog * This, - /* [out] */ UINT *piFileType); - + IFileOpenDialog * this, UINT *piFileType); + /* Actually pfde is IFileDialogEvents* */ HRESULT ( STDMETHODCALLTYPE *Advise )( - IFileOpenDialog * This, - /* XXX - Actually pfde is IFileDialogEvents* but we do not use - this call and do not want to define IFileDialogEvents as that - pulls in a whole bunch of other stuff. */ - /* [in] */ void *pfde, - /* [out] */ DWORD *pdwCookie); - - HRESULT ( STDMETHODCALLTYPE *Unadvise )( - IFileOpenDialog * This, - /* [in] */ DWORD dwCookie); - + IFileOpenDialog * this, void *pfde, DWORD *pdwCookie); + HRESULT ( STDMETHODCALLTYPE *Unadvise )( IFileOpenDialog * this, DWORD); HRESULT ( STDMETHODCALLTYPE *SetOptions )( - IFileOpenDialog * This, - /* [in] */ FILEOPENDIALOGOPTIONS fos); - + IFileOpenDialog * this, FILEOPENDIALOGOPTIONS fos); HRESULT ( STDMETHODCALLTYPE *GetOptions )( - IFileOpenDialog * This, - /* [out] */ FILEOPENDIALOGOPTIONS *pfos); - + IFileOpenDialog * this, FILEOPENDIALOGOPTIONS *pfos); HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( - IFileOpenDialog * This, - /* [in] */ IShellItem *psi); - + IFileOpenDialog * this, IShellItem *psi); HRESULT ( STDMETHODCALLTYPE *SetFolder )( - IFileOpenDialog * This, - /* [in] */ IShellItem *psi); - + IFileOpenDialog * this, IShellItem *psi); HRESULT ( STDMETHODCALLTYPE *GetFolder )( - IFileOpenDialog * This, - /* [out] */ IShellItem **ppsi); - + IFileOpenDialog * this, IShellItem **ppsi); HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( - IFileOpenDialog * This, - /* [out] */ IShellItem **ppsi); - + IFileOpenDialog * this, IShellItem **ppsi); HRESULT ( STDMETHODCALLTYPE *SetFileName )( - IFileOpenDialog * This, - /* [string][in] */ LPCWSTR pszName); - + IFileOpenDialog * this, LPCWSTR pszName); HRESULT ( STDMETHODCALLTYPE *GetFileName )( - IFileOpenDialog * This, - /* [string][out] */ LPWSTR *pszName); - + IFileOpenDialog * this, LPWSTR *pszName); HRESULT ( STDMETHODCALLTYPE *SetTitle )( - IFileOpenDialog * This, - /* [string][in] */ LPCWSTR pszTitle); - + IFileOpenDialog * this, LPCWSTR pszTitle); HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( - IFileOpenDialog * This, - /* [string][in] */ LPCWSTR pszText); - + IFileOpenDialog * this, LPCWSTR pszText); HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( - IFileOpenDialog * This, - /* [string][in] */ LPCWSTR pszLabel); - + IFileOpenDialog * this, LPCWSTR pszLabel); HRESULT ( STDMETHODCALLTYPE *GetResult )( - IFileOpenDialog * This, - /* [out] */ IShellItem **ppsi); - + IFileOpenDialog * this, IShellItem **ppsi); HRESULT ( STDMETHODCALLTYPE *AddPlace )( - IFileOpenDialog * This, - /* [in] */ IShellItem *psi, - /* [in] */ FDAP fdap); - + IFileOpenDialog * this, IShellItem *psi, FDAP fdap); HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( - IFileOpenDialog * This, - /* [string][in] */ LPCWSTR pszDefaultExtension); - - HRESULT ( STDMETHODCALLTYPE *Close )( - IFileOpenDialog * This, - /* [in] */ HRESULT hr); - + IFileOpenDialog * this, LPCWSTR pszDefaultExtension); + HRESULT ( STDMETHODCALLTYPE *Close )( IFileOpenDialog * this, HRESULT hr); HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( - IFileOpenDialog * This, - /* [in] */ REFGUID guid); - + IFileOpenDialog * this, REFGUID guid); HRESULT ( STDMETHODCALLTYPE *ClearClientData )( - IFileOpenDialog * This); - + IFileOpenDialog * this); HRESULT ( STDMETHODCALLTYPE *SetFilter )( - IFileOpenDialog * This, - /* XXX - Actually IShellItemFilter. But deprecated in Win7 AND we do - not use it anyways. So define as void* */ - /* [in] */ void *pFilter); - + IFileOpenDialog * this, + /* pFilter is actually IShellItemFilter */ + void *pFilter); HRESULT ( STDMETHODCALLTYPE *GetResults )( - IFileOpenDialog * This, - /* [out] */ IShellItemArray **ppenum); - + IFileOpenDialog * this, IShellItemArray **ppenum); HRESULT ( STDMETHODCALLTYPE *GetSelectedItems )( - IFileOpenDialog * This, - /* [out] */ IShellItemArray **ppsai); + IFileOpenDialog * this, IShellItemArray **ppsai); END_INTERFACE } IFileOpenDialogVtbl; @@ -1157,7 +927,7 @@ Tk_GetOpenFileObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - return GetFileName(clientData, interp, objc, objv, 1); + return GetFileName(clientData, interp, objc, objv, OFN_FILE_OPEN); } /* @@ -1184,7 +954,7 @@ Tk_GetSaveFileObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - return GetFileName(clientData, interp, objc, objv, 0); + return GetFileName(clientData, interp, objc, objv, OFN_FILE_SAVE); } /* @@ -1230,7 +1000,7 @@ ParseOFNOptions( Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[], /* Argument objects. */ - int open, /* 1 for Open, 0 for Save */ + enum OFNOper oper, /* 1 for Open, 0 for Save */ OFNOpts *optsPtr) /* Output, uninitialized on entry */ { int i; @@ -1238,6 +1008,7 @@ ParseOFNOptions( enum options { FILE_DEFAULT, FILE_TYPES, FILE_INITDIR, FILE_INITFILE, FILE_PARENT, FILE_TITLE, FILE_TYPEVARIABLE, FILE_MULTIPLE, FILE_CONFIRMOW, + FILE_MUSTEXIST, FILE_UNDOCUMENTED_XP_STYLE /* XXX - force XP - style dialogs */ }; struct Options { @@ -1268,8 +1039,23 @@ ParseOFNOptions( {"-xpstyle", FILE_UNDOCUMENTED_XP_STYLE}, /* XXX */ {NULL, FILE_DEFAULT/*ignored*/ } }; - const struct Options *const options = open ? openOptions : saveOptions; + static const struct Options dirOptions[] = { + {"-initialdir", FILE_INITDIR}, + {"-mustexist", FILE_MUSTEXIST}, + {"-parent", FILE_PARENT}, + {"-title", FILE_TITLE}, + {"-xpstyle", FILE_UNDOCUMENTED_XP_STYLE}, /* XXX */ + {NULL, FILE_DEFAULT/*ignored*/ } + }; + + const struct Options *options = NULL; + switch (oper) { + case OFN_FILE_SAVE: options = saveOptions; break; + case OFN_DIR_CHOOSE: options = dirOptions; break; + case OFN_FILE_OPEN: options = openOptions; break; + } + ZeroMemory(optsPtr, sizeof(*optsPtr)); optsPtr->tkwin = clientData; optsPtr->confirmOverwrite = 1; /* By default we ask for confirmation */ @@ -1342,6 +1128,12 @@ ParseOFNOptions( return TCL_ERROR; } break; + case FILE_MUSTEXIST: + if (Tcl_GetBooleanFromObj(interp, valuePtr, + &optsPtr->mustExist) != TCL_OK) { + return TCL_ERROR; + } + break; case FILE_UNDOCUMENTED_XP_STYLE: if (Tcl_GetBooleanFromObj(interp, valuePtr, &optsPtr->forceXPStyle) != TCL_OK) { @@ -1429,7 +1221,8 @@ static int VistaFileDialogsAvailable() * Dialogs is displayed *---------------------------------------------------------------------- */ -static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) +static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, + enum OFNOper oper) { HRESULT hr; HWND hWnd; @@ -1441,10 +1234,12 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) Tcl_Obj *resultObj = NULL; ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + int oldMode; if (tsdPtr->newFileDialogsState != FDLG_STATE_USE_NEW) { - /* Should not be called in this condition but be nice about it */ - return GetFileNameXP(interp, optsPtr, open); + /* XXX - should be an assert but Tcl does not seem to have one? */ + Tcl_SetResult(interp, "Internal error: GetFileNameVista: IFileDialog API not available", TCL_STATIC); + return TCL_ERROR; } /* @@ -1470,7 +1265,7 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) * resources that need to be released/freed. */ - if (open) + if (oper == OFN_FILE_OPEN || oper == OFN_DIR_CHOOSE) hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgIf); else @@ -1480,15 +1275,6 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) if (FAILED(hr)) goto vamoose; - if (filterPtr) { - hr = fdlgIf->lpVtbl->SetFileTypes(fdlgIf, nfilters, filterPtr); - if (FAILED(hr)) - goto vamoose; - hr = fdlgIf->lpVtbl->SetFileTypeIndex(fdlgIf, defaultFilterIndex); - if (FAILED(hr)) - goto vamoose; - } - /* * Get current settings first because we want to preserve existing * settings like whether to show hidden files etc. based on the @@ -1498,6 +1284,16 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) if (FAILED(hr)) goto vamoose; + if (filterPtr) { + flags |= FOS_STRICTFILETYPES; /* XXX - does this match old behaviour? */ + hr = fdlgIf->lpVtbl->SetFileTypes(fdlgIf, nfilters, filterPtr); + if (FAILED(hr)) + goto vamoose; + hr = fdlgIf->lpVtbl->SetFileTypeIndex(fdlgIf, defaultFilterIndex); + if (FAILED(hr)) + goto vamoose; + } + /* Flags are equivalent to those we used in the older API */ /* @@ -1511,6 +1307,13 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) FOS_PATHMUSTEXIST; /* The *directory* path must exist */ + if (oper == OFN_DIR_CHOOSE) { + flags |= FOS_PICKFOLDERS; + if (optsPtr->mustExist) + flags |= FOS_FILEMUSTEXIST; /* XXX - check working */ + } else + flags &= ~ FOS_PICKFOLDERS; + if (optsPtr->multi) flags |= FOS_ALLOWMULTISELECT; else @@ -1562,9 +1365,12 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open) Tcl_DStringFree(&dirString); } + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); hr = fdlgIf->lpVtbl->Show(fdlgIf, hWnd); + Tcl_SetServiceMode(oldMode); + if (SUCCEEDED(hr)) { - if (open && optsPtr->multi) { + if ((oper == OFN_FILE_OPEN) && optsPtr->multi) { IShellItemArray *multiIf; DWORD dw, count; IFileOpenDialog *fodIf = (IFileOpenDialog *) fdlgIf; @@ -1665,7 +1471,7 @@ vamoose: /* (hr != 0) => error */ * See user documentation. *---------------------------------------------------------------------- */ -static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, int open) +static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, enum OFNOper oper) { OPENFILENAME ofn; OFNData ofnData; @@ -1703,7 +1509,7 @@ static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, int open) ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProc; ofn.lCustData = (LPARAM) &ofnData; - if (open != 0) { + if (oper != OFN_FILE_SAVE) { ofn.Flags |= OFN_FILEMUSTEXIST; } else if (optsPtr->confirmOverwrite) { ofn.Flags |= OFN_OVERWRITEPROMPT; @@ -1770,7 +1576,7 @@ static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, int open) */ oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); - if (open != 0) { + if (oper != OFN_FILE_SAVE) { winCode = GetOpenFileName(&ofn); } else { winCode = GetSaveFileName(&ofn); @@ -1954,21 +1760,20 @@ GetFileName( Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[], /* Argument objects. */ - int open) /* 1 to call GetOpenFileName(), 0 to call + enum OFNOper oper) /* 1 to call GetOpenFileName(), 0 to call * GetSaveFileName(). */ { OFNOpts ofnOpts; int result; - /* Parse the arguments. */ - result = ParseOFNOptions(clientData, interp, objc, objv, open, &ofnOpts); + result = ParseOFNOptions(clientData, interp, objc, objv, oper, &ofnOpts); if (result != TCL_OK) return result; if (VistaFileDialogsAvailable() && ! ofnOpts.forceXPStyle) - result = GetFileNameVista(interp, &ofnOpts, open); + result = GetFileNameVista(interp, &ofnOpts, oper); else - result = GetFileNameXP(interp, &ofnOpts, open); + result = GetFileNameXP(interp, &ofnOpts, oper); CleanupOFNOptions(&ofnOpts); return result; @@ -2511,102 +2316,60 @@ Tk_ChooseDirectoryObjCmd( Tcl_Obj *const objv[]) /* Argument objects. */ { TCHAR path[MAX_PATH]; - int oldMode, result = TCL_ERROR, i; + int oldMode, result; LPCITEMIDLIST pidl; /* Returned by browser */ BROWSEINFO bInfo; /* Used by browser */ ChooseDir cdCBData; /* Structure to pass back and forth */ LPMALLOC pMalloc; /* Used by shell */ - Tk_Window tkwin = clientData; HWND hWnd; - const char *utfTitle = NULL;/* Title for window */ TCHAR saveDir[MAX_PATH]; Tcl_DString titleString; /* Title */ - Tcl_DString initDirString; /* Initial directory */ Tcl_DString tempString; /* temporary */ Tcl_Obj *objPtr; - static const char *const optionStrings[] = { - "-initialdir", "-mustexist", "-parent", "-title", NULL - }; - enum options { - DIR_INITIAL, DIR_EXIST, DIR_PARENT, FILE_TITLE - }; + OFNOpts ofnOpts; + const char *utfDir; - /* - * Initialize - */ + result = ParseOFNOptions(clientData, interp, objc, objv, + OFN_DIR_CHOOSE, &ofnOpts); + if (result != TCL_OK) + return result; + + /* Use new dialogs if available */ + if (VistaFileDialogsAvailable() && ! ofnOpts.forceXPStyle) { + result = GetFileNameVista(interp, &ofnOpts, OFN_DIR_CHOOSE); + CleanupOFNOptions(&ofnOpts); + return result; + } + + /* Older dialogs */ path[0] = '\0'; ZeroMemory(&cdCBData, sizeof(ChooseDir)); cdCBData.interp = interp; + cdCBData.mustExist = ofnOpts.mustExist; - /* - * Process the command line options - */ - - for (i = 1; i < objc; i += 2) { - int index; - const char *string; + utfDir = Tcl_DStringValue(&ofnOpts.utfDirString); + if (utfDir[0] != '\0') { const TCHAR *uniStr; - Tcl_Obj *optionPtr, *valuePtr; - optionPtr = objv[i]; - valuePtr = objv[i + 1]; + Tcl_WinUtfToTChar(Tcl_DStringValue(&ofnOpts.utfDirString), -1, + &tempString); + uniStr = (TCHAR *) Tcl_DStringValue(&tempString); - if (Tcl_GetIndexFromObjStruct(interp, optionPtr, optionStrings, - sizeof(char *), "option", 0, &index) != TCL_OK) { - goto cleanup; - } - if (i + 1 == objc) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "value for \"%s\" missing", Tcl_GetString(optionPtr))); - Tcl_SetErrorCode(interp, "TK", "DIRDIALOG", "VALUE", NULL); - goto cleanup; - } + /* Convert possible relative path to full path to keep dialog happy. */ - string = Tcl_GetString(valuePtr); - switch ((enum options) index) { - case DIR_INITIAL: - if (Tcl_TranslateFileName(interp,string,&initDirString) == NULL) { - goto cleanup; - } - Tcl_WinUtfToTChar(Tcl_DStringValue(&initDirString), -1, - &tempString); - uniStr = (TCHAR *) Tcl_DStringValue(&tempString); - - /* - * Convert possible relative path to full path to keep dialog - * happy. - */ - - GetFullPathName(uniStr, MAX_PATH, saveDir, NULL); - _tcsncpy(cdCBData.initDir, saveDir, MAX_PATH); - Tcl_DStringFree(&initDirString); - Tcl_DStringFree(&tempString); - break; - case DIR_EXIST: - if (Tcl_GetBooleanFromObj(interp, valuePtr, - &cdCBData.mustExist) != TCL_OK) { - goto cleanup; - } - break; - case DIR_PARENT: - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - goto cleanup; - } - break; - case FILE_TITLE: - utfTitle = string; - break; - } + GetFullPathName(uniStr, MAX_PATH, saveDir, NULL); + _tcsncpy(cdCBData.initDir, saveDir, MAX_PATH); } + /* XXX - rest of this (original) code has no error checks at all. */ + /* * Get ready to call the browser */ - Tk_MakeWindowExist(tkwin); - hWnd = Tk_GetHWND(Tk_WindowId(tkwin)); + Tk_MakeWindowExist(ofnOpts.tkwin); + hWnd = Tk_GetHWND(Tk_WindowId(ofnOpts.tkwin)); /* * Setup the parameters used by SHBrowseForFolder @@ -2620,8 +2383,8 @@ Tk_ChooseDirectoryObjCmd( } bInfo.lParam = (LPARAM) &cdCBData; - if (utfTitle != NULL) { - Tcl_WinUtfToTChar(utfTitle, -1, &titleString); + if (ofnOpts.titleObj != NULL) { + Tcl_WinUtfToTChar(Tcl_GetString(ofnOpts.titleObj), -1, &titleString); bInfo.lpszTitle = (LPTSTR) Tcl_DStringValue(&titleString); } else { bInfo.lpszTitle = TEXT("Please choose a directory, then select OK."); @@ -2659,6 +2422,10 @@ Tk_ChooseDirectoryObjCmd( oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); GetCurrentDirectory(MAX_PATH, saveDir); if (SHGetMalloc(&pMalloc) == NOERROR) { + /* + * XXX - MSDN says CoInitialize must have been called before + * SHBrowseForFolder can be used but don't see that called anywhere. + */ pidl = SHBrowseForFolder(&bInfo); /* @@ -2710,14 +2477,8 @@ Tk_ChooseDirectoryObjCmd( Tcl_DStringFree(&ds); } - result = TCL_OK; - - if (utfTitle != NULL) { - Tcl_DStringFree(&titleString); - } - - cleanup: - return result; + CleanupOFNOptions(&ofnOpts); + return TCL_OK; } /* -- cgit v0.12 From defa6162f12bf44d8df24a341dd4727e3a23e3d0 Mon Sep 17 00:00:00 2001 From: ashok Date: Sat, 20 Sep 2014 02:56:06 +0000 Subject: Make -xpstyle a hidden option --- win/tkWinDialog.c | 59 +++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 6b7035d..3130cf2 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -1024,7 +1024,6 @@ ParseOFNOptions( {"-parent", FILE_PARENT}, {"-title", FILE_TITLE}, {"-typevariable", FILE_TYPEVARIABLE}, - {"-xpstyle", FILE_UNDOCUMENTED_XP_STYLE}, /* XXX */ {NULL, FILE_DEFAULT/*ignored*/ } }; static const struct Options openOptions[] = { @@ -1036,7 +1035,6 @@ ParseOFNOptions( {"-parent", FILE_PARENT}, {"-title", FILE_TITLE}, {"-typevariable", FILE_TYPEVARIABLE}, - {"-xpstyle", FILE_UNDOCUMENTED_XP_STYLE}, /* XXX */ {NULL, FILE_DEFAULT/*ignored*/ } }; static const struct Options dirOptions[] = { @@ -1044,7 +1042,6 @@ ParseOFNOptions( {"-mustexist", FILE_MUSTEXIST}, {"-parent", FILE_PARENT}, {"-title", FILE_TITLE}, - {"-xpstyle", FILE_UNDOCUMENTED_XP_STYLE}, /* XXX */ {NULL, FILE_DEFAULT/*ignored*/ } }; @@ -1057,6 +1054,7 @@ ParseOFNOptions( } ZeroMemory(optsPtr, sizeof(*optsPtr)); + // optsPtr->forceXPStyle = 1; optsPtr->tkwin = clientData; optsPtr->confirmOverwrite = 1; /* By default we ask for confirmation */ Tcl_DStringInit(&optsPtr->utfDirString); @@ -1069,12 +1067,23 @@ ParseOFNOptions( if (Tcl_GetIndexFromObjStruct(interp, objv[i], options, sizeof(struct Options), "option", 0, &index) != TCL_OK) { - goto end; + /* + * XXX -xpstyle is explicitly checked for as it is undocumented + * and we do not want it to show in option error messages. + */ + if (strcmp(Tcl_GetString(objv[i]), "-xpstyle")) + goto error_return; + if (Tcl_GetBooleanFromObj(interp, valuePtr, + &optsPtr->forceXPStyle) != TCL_OK) + goto error_return; + + continue; + } else if (i + 1 == objc) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "value for \"%s\" missing", options[index].name)); Tcl_SetErrorCode(interp, "TK", "FILEDIALOG", "VALUE", NULL); - goto end; + goto error_return; } string = Tcl_GetString(valuePtr); @@ -1088,14 +1097,12 @@ ParseOFNOptions( case FILE_INITDIR: Tcl_DStringFree(&optsPtr->utfDirString); if (Tcl_TranslateFileName(interp, string, - &optsPtr->utfDirString) == NULL) { - goto end; - } + &optsPtr->utfDirString) == NULL) + goto error_return; break; case FILE_INITFILE: - if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { - goto end; - } + if (Tcl_TranslateFileName(interp, string, &ds) == NULL) + goto error_return; Tcl_UtfToExternal(NULL, TkWinGetUnicodeEncoding(), Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), 0, NULL, (char *) &optsPtr->file[0], sizeof(optsPtr->file), @@ -1105,9 +1112,8 @@ ParseOFNOptions( case FILE_PARENT: /* XXX - check */ optsPtr->tkwin = Tk_NameToWindow(interp, string, clientData); - if (optsPtr->tkwin == NULL) { - goto end; - } + if (optsPtr->tkwin == NULL) + goto error_return; break; case FILE_TITLE: optsPtr->titleObj = valuePtr; @@ -1118,34 +1124,27 @@ ParseOFNOptions( NULL, TCL_GLOBAL_ONLY); break; case FILE_MULTIPLE: - if (Tcl_GetBooleanFromObj(interp, valuePtr, &optsPtr->multi) != TCL_OK) { - return TCL_ERROR; - } + if (Tcl_GetBooleanFromObj(interp, valuePtr, + &optsPtr->multi) != TCL_OK) + goto error_return; break; case FILE_CONFIRMOW: if (Tcl_GetBooleanFromObj(interp, valuePtr, - &optsPtr->confirmOverwrite) != TCL_OK) { - return TCL_ERROR; - } + &optsPtr->confirmOverwrite) != TCL_OK) + goto error_return; break; case FILE_MUSTEXIST: if (Tcl_GetBooleanFromObj(interp, valuePtr, - &optsPtr->mustExist) != TCL_OK) { - return TCL_ERROR; - } - break; - case FILE_UNDOCUMENTED_XP_STYLE: - if (Tcl_GetBooleanFromObj(interp, valuePtr, - &optsPtr->forceXPStyle) != TCL_OK) { - return TCL_ERROR; - } + &optsPtr->mustExist) != TCL_OK) + goto error_return; break; } } return TCL_OK; -end: /* interp should already hold error */ +error_return: /* interp should already hold error */ + /* On error, we need to clean up anything we might have allocated */ CleanupOFNOptions(optsPtr); return TCL_ERROR; } -- cgit v0.12 From a0426df76aa736ba2d618441232d72e4ba38a380 Mon Sep 17 00:00:00 2001 From: ashok Date: Sat, 20 Sep 2014 03:17:35 +0000 Subject: Convert native paths returned from file dialogs to Tcl canonical paths. --- tests/winDialog.test | 56 ++++++++++++++++++++++++++++++++--------- win/tkWinDialog.c | 14 ++++++++--- win/tkWinTest.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 119 insertions(+), 21 deletions(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index 8aa9ac3..357349e 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -22,11 +22,30 @@ testConstraint english [expr { && (([testwinlocale] & 0xff) == 9) }] -proc start {arg} { +proc start {widgetcommand args} { set ::tk_dialog 0 set ::iter_after 0 - after 1 $arg + # On newer versions of Windows, we need to find the dialog window + # based on the title + if {[llength $args]} { + set ::dialogtitle [lindex $args 0] + set ::dialogclass "#32770" + if {$::dialogtitle eq ""} { + switch $widgetcommand { + tk_getOpenFile { + set ::dialogtitle Open + } + tk_getSaveFile { + set ::dialogtitle "Save As" + } + tk_chooseDirectory { + set ::dialogtitle "Select Folder" + } + } + } + } + after 1 $widgetcommand } proc then {cmd} { @@ -34,19 +53,32 @@ proc then {cmd} { set ::dialogresult {} set ::testfont {} - afterbody + after 100 afterbody vwait ::dialogresult return $::dialogresult } proc afterbody {} { - if {$::tk_dialog == 0} { - if {[incr ::iter_after] > 30} { - set ::dialogresult ">30 iterations waiting on tk_dialog" + # On Vista and later, using the new file dialogs we have to find + # the window using its title as tk_dialog will not be set at the C level + if {$::dialogtitle ne "" && [string match 6.* $::tcl_platform(osVersion)]} { + if {[catch {testfindwindow "" $::dialogclass} ::tk_dialog]} { + if {[incr ::iter_after] > 10} { + set ::dialogresult ">30 iterations waiting on tk_dialog" + return + } + after 150 {afterbody} + return + } + } else { + if {$::tk_dialog == 0} { + if {[incr ::iter_after] > 30} { + set ::dialogresult ">30 iterations waiting on tk_dialog" + return + } + after 150 {afterbody} return } - after 150 {afterbody} - return } uplevel #0 {set dialogresult [eval $command]} } @@ -205,7 +237,7 @@ test winDialog-5.2 {GetFileName: one argument} -constraints { test winDialog-5.3 {GetFileName: many arguments} -constraints { nt testwinevent } -body { - start {tk_getOpenFile -initialdir c:/ -parent . -title test -initialfile foo} + start {tk_getOpenFile -initialdir c:/ -parent . -title test -initialfile foo} test then { Click cancel } @@ -218,7 +250,7 @@ test winDialog-5.4 {GetFileName: Tcl_GetIndexFromObj() != TCL_OK} -constraints { test winDialog-5.5 {GetFileName: Tcl_GetIndexFromObj() == TCL_OK} -constraints { nt testwinevent } -body { - start {tk_getOpenFile -title bar} + start {tk_getOpenFile -title bar} bar then { Click cancel } @@ -235,10 +267,10 @@ test winDialog-5.7 {GetFileName: extension begins with .} -constraints { # string++; # } - start {set x [tk_getSaveFile -defaultextension .foo -title Save]} + start {set x [tk_getSaveFile -defaultextension .foo -title Save]} Save set msg {} then { - if {[catch {SetText 0x47C bar} msg]} { + if {[catch {SetText 0x3e9 bar} msg]} { Click cancel } else { Click ok diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 3130cf2..67f0df4 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -1387,8 +1387,13 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, hr = itemIf->lpVtbl->GetDisplayName(itemIf, SIGDN_FILESYSPATH, &wstr); if (SUCCEEDED(hr)) { - Tcl_ListObjAppendElement(interp, multiObj, - Tcl_NewUnicodeObj(wstr, -1)); + Tcl_DString fnds; + ConvertExternalFilename(wstr, &fnds); + CoTaskMemFree(wstr); + Tcl_ListObjAppendElement( + interp, multiObj, + Tcl_NewStringObj(Tcl_DStringValue(&fnds), + Tcl_DStringLength(&fnds))); } itemIf->lpVtbl->Release(itemIf); if (FAILED(hr)) @@ -1408,7 +1413,10 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, hr = resultIf->lpVtbl->GetDisplayName(resultIf, SIGDN_FILESYSPATH, &wstr); if (SUCCEEDED(hr)) { - resultObj = Tcl_NewUnicodeObj(wstr, -1); + Tcl_DString fnds; + ConvertExternalFilename(wstr, &fnds); + resultObj = Tcl_NewStringObj(Tcl_DStringValue(&fnds), + Tcl_DStringLength(&fnds)); CoTaskMemFree(wstr); } resultIf->lpVtbl->Release(resultIf); diff --git a/win/tkWinTest.c b/win/tkWinTest.c index 9fa956c..2c38d71 100644 --- a/win/tkWinTest.c +++ b/win/tkWinTest.c @@ -79,6 +79,42 @@ TkplatformtestInit( return TCL_OK; } +struct TestFindControlState { + int id; + HWND control; +}; + +/* Callback for window enumeration - used for TestFindControl */ +BOOL CALLBACK TestFindControlCallback( + HWND hwnd, + LPARAM lParam +) +{ + struct TestFindControlState *fcsPtr = (struct TestFindControlState *)lParam; + fcsPtr->control = GetDlgItem(hwnd, fcsPtr->id); + /* If we have found the control, return FALSE to stop the enumeration */ + return fcsPtr->control == NULL ? TRUE : FALSE; +} + +/* + * Finds the descendent control window with the specified ID and returns + * its HWND. + */ +HWND TestFindControl(HWND root, int id) +{ + struct TestFindControlState fcs; + + fcs.control = GetDlgItem(root, id); + if (fcs.control == NULL) { + /* Control is not a direct child. Look in descendents */ + fcs.id = id; + fcs.control = NULL; + EnumChildWindows(root, TestFindControlCallback, (LPARAM) &fcs); + } + return fcs.control; +} + + /* *---------------------------------------------------------------------- * @@ -244,11 +280,13 @@ TestwineventObjCmd( { HWND hwnd = 0; HWND child = 0; + HWND control; int id; char *rest; UINT message; WPARAM wParam; LPARAM lParam; + LRESULT result; static const TkStateMap messageMap[] = { {WM_LBUTTONDOWN, "WM_LBUTTONDOWN"}, {WM_LBUTTONUP, "WM_LBUTTONUP"}, @@ -302,6 +340,7 @@ TestwineventObjCmd( return TCL_ERROR; } } + message = TkFindStateNum(NULL, NULL, messageMap, Tcl_GetString(objv[3])); wParam = 0; lParam = 0; @@ -318,7 +357,19 @@ TestwineventObjCmd( Tcl_DString ds; char buf[256]; +#if 0 GetDlgItemTextA(hwnd, id, buf, 256); +#else + control = TestFindControl(hwnd, id); + if (control == NULL) { + Tcl_SetObjResult(interp, + Tcl_ObjPrintf("Could not find control with id %d", id)); + return TCL_ERROR; + } + buf[0] = 0; + SendMessageA(control, WM_GETTEXT, (WPARAM)sizeof(buf), + (LPARAM) buf); +#endif Tcl_ExternalToUtfDString(NULL, buf, -1, &ds); Tcl_AppendResult(interp, Tcl_DStringValue(&ds), NULL); Tcl_DStringFree(&ds); @@ -326,15 +377,21 @@ TestwineventObjCmd( } case WM_SETTEXT: { Tcl_DString ds; - BOOL result; + control = TestFindControl(hwnd, id); + if (control == NULL) { + Tcl_SetObjResult(interp, + Tcl_ObjPrintf("Could not find control with id %d", id)); + return TCL_ERROR; + } Tcl_UtfToExternalDString(NULL, Tcl_GetString(objv[4]), -1, &ds); - result = SetDlgItemTextA(hwnd, id, Tcl_DStringValue(&ds)); + result = SendMessageA(control, WM_SETTEXT, 0, + (LPARAM) Tcl_DStringValue(&ds)); Tcl_DStringFree(&ds); if (result == 0) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("failed to send text to dialog: ", -1)); - AppendSystemError(interp, GetLastError()); - return TCL_ERROR; + Tcl_SetObjResult(interp, Tcl_NewStringObj("failed to send text to dialog: ", -1)); + AppendSystemError(interp, GetLastError()); + return TCL_ERROR; } break; } @@ -395,7 +452,8 @@ TestfindwindowObjCmd( if (objc == 3) { class = Tcl_WinUtfToTChar(Tcl_GetString(objv[2]), -1, &classString); } - + if (title[0] == 0) + title = NULL; hwnd = FindWindow(class, title); if (hwnd == NULL) { -- cgit v0.12 From c274f24adf15e98a9fbf65571984e7b0c30c40da Mon Sep 17 00:00:00 2001 From: ashok Date: Sat, 20 Sep 2014 12:30:12 +0000 Subject: Make findwindow more robust by ensuring it is a window belonging to the same process. --- win/tkWinTest.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/win/tkWinTest.c b/win/tkWinTest.c index 2c38d71..8a92f5a 100644 --- a/win/tkWinTest.c +++ b/win/tkWinTest.c @@ -439,6 +439,7 @@ TestfindwindowObjCmd( Tcl_DString titleString, classString; HWND hwnd = NULL; int r = TCL_OK; + DWORD myPid; Tcl_DStringInit(&classString); Tcl_DStringInit(&titleString); @@ -454,7 +455,28 @@ TestfindwindowObjCmd( } if (title[0] == 0) title = NULL; +#if 0 hwnd = FindWindow(class, title); +#else + /* We want find a window the belongs to us and not some other process */ + hwnd = NULL; + myPid = GetCurrentProcessId(); + while (1) { + DWORD pid, tid; + hwnd = FindWindowEx(NULL, hwnd, class, title); + if (hwnd == NULL) + break; + tid = GetWindowThreadProcessId(hwnd, &pid); + if (tid == 0) { + /* Window has gone */ + hwnd = NULL; + break; + } + if (pid == myPid) + break; /* Found it */ + } + +#endif if (hwnd == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("failed to find window: ", -1)); -- cgit v0.12 From be417f72bc54b109f4c8d70e4935478b6e410fab Mon Sep 17 00:00:00 2001 From: ashok Date: Sat, 20 Sep 2014 12:31:24 +0000 Subject: Update test suite for compatibility with new Vista file dialogs. Some tests still fail pending what we decide about behaviour when -initialdir is not specified. --- tests/winDialog.test | 151 ++++++++++++++++++++++++++++----------------------- 1 file changed, 83 insertions(+), 68 deletions(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index 357349e..f21fa18 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -22,30 +22,17 @@ testConstraint english [expr { && (([testwinlocale] & 0xff) == 9) }] -proc start {widgetcommand args} { +proc vista? {{prevista 0} {postvista 1}} { + lassign [split $::tcl_platform(osVersion) .] major + return [expr {$major >= 6 ? $postvista : $prevista}] +} + +proc start {arg} { set ::tk_dialog 0 set ::iter_after 0 + set ::dialogclass "#32770" - # On newer versions of Windows, we need to find the dialog window - # based on the title - if {[llength $args]} { - set ::dialogtitle [lindex $args 0] - set ::dialogclass "#32770" - if {$::dialogtitle eq ""} { - switch $widgetcommand { - tk_getOpenFile { - set ::dialogtitle Open - } - tk_getSaveFile { - set ::dialogtitle "Save As" - } - tk_chooseDirectory { - set ::dialogtitle "Select Folder" - } - } - } - } - after 1 $widgetcommand + after 1 $arg } proc then {cmd} { @@ -53,7 +40,10 @@ proc then {cmd} { set ::dialogresult {} set ::testfont {} - after 100 afterbody + # Do not make the delay too short. The newer Vista dialogs take + # time to come up. Even if the testforwindow returns true, the + # controls are not ready to accept messages + after 500 afterbody vwait ::dialogresult return $::dialogresult } @@ -61,9 +51,9 @@ proc then {cmd} { proc afterbody {} { # On Vista and later, using the new file dialogs we have to find # the window using its title as tk_dialog will not be set at the C level - if {$::dialogtitle ne "" && [string match 6.* $::tcl_platform(osVersion)]} { + if {[vista?]} { if {[catch {testfindwindow "" $::dialogclass} ::tk_dialog]} { - if {[incr ::iter_after] > 10} { + if {[incr ::iter_after] > 30} { set ::dialogresult ">30 iterations waiting on tk_dialog" return } @@ -237,7 +227,7 @@ test winDialog-5.2 {GetFileName: one argument} -constraints { test winDialog-5.3 {GetFileName: many arguments} -constraints { nt testwinevent } -body { - start {tk_getOpenFile -initialdir c:/ -parent . -title test -initialfile foo} test + start {tk_getOpenFile -initialdir c:/ -parent . -title test -initialfile foo} then { Click cancel } @@ -250,7 +240,7 @@ test winDialog-5.4 {GetFileName: Tcl_GetIndexFromObj() != TCL_OK} -constraints { test winDialog-5.5 {GetFileName: Tcl_GetIndexFromObj() == TCL_OK} -constraints { nt testwinevent } -body { - start {tk_getOpenFile -title bar} bar + start {tk_getOpenFile -title bar} then { Click cancel } @@ -267,10 +257,10 @@ test winDialog-5.7 {GetFileName: extension begins with .} -constraints { # string++; # } - start {set x [tk_getSaveFile -defaultextension .foo -title Save]} Save + start {set x [tk_getSaveFile -defaultextension .foo -title Save]} set msg {} then { - if {[catch {SetText 0x3e9 bar} msg]} { + if {[catch {SetText [vista? 0x47C 0x3e9] bar} msg]} { Click cancel } else { Click ok @@ -286,7 +276,7 @@ test winDialog-5.8 {GetFileName: extension doesn't begin with .} -constraints { start {set x [tk_getSaveFile -defaultextension foo -title Save]} set msg {} then { - if {[catch {SetText 0x47C bar} msg]} { + if {[catch {SetText [vista? 0x47C 0x3e9] bar} msg]} { Click cancel } else { Click ok @@ -296,18 +286,23 @@ test winDialog-5.8 {GetFileName: extension doesn't begin with .} -constraints { } -cleanup { unset msg } -result [string totitle [file join [pwd] bar.foo]] -test winDialog-5.9 {GetFileName: file types} -constraints { - nt testwinevent -} -body { -# case FILE_TYPES: - - start {tk_getSaveFile -filetypes {{"foo files" .foo FOOF}} -title Foo} - then { - set x [GetText 0x470] - Click cancel - } - return $x -} -result {foo files (*.foo)} +if {![vista?]} { + # XXX - currently disabled for vista style dialogs because the file + # types control has no control ID and we don't have a mechanism to + # locate it. + test winDialog-5.9 {GetFileName: file types} -constraints { + nt testwinevent + } -body { + # case FILE_TYPES: + + start {tk_getSaveFile -filetypes {{"foo files" .foo FOOF}} -title Foo} + then { + set x [GetText 0x470] + Click cancel + } + return $x + } -result {foo files (*.foo)} +} test winDialog-5.10 {GetFileName: file types: MakeFilter() fails} -constraints { nt } -body { @@ -320,7 +315,7 @@ test winDialog-5.11 {GetFileName: initial directory} -constraints { nt testwinevent } -body { # case FILE_INITDIR: - + unset -nocomplain x start {set x [tk_getSaveFile \ -initialdir [file normalize $::env(TEMP)] \ -initialfile "12x 455" -title Foo]} @@ -354,19 +349,23 @@ test winDialog-5.14 {GetFileName: initial file: Tcl_TranslateFileName()} -constr # if (Tcl_TranslateFileName(interp, string, &ds) == NULL) tk_getOpenFile -initialfile ~12x/455 } -returnCodes error -result {user "12x" doesn't exist} -test winDialog-5.15 {GetFileName: initial file: long name} -constraints { - nt testwinevent -} -body { - start { - set dialogresult [catch { - tk_getSaveFile -initialfile [string repeat a 1024] -title Long - } x] - } - then { - Click ok - } - list $dialogresult [string match "invalid filename *" $x] -} -result {1 1} +if {![vista?]} { + # XXX - disabled for Vista because the new dialogs allow long file + # names to be specified but force the user to change it. + test winDialog-5.15 {GetFileName: initial file: long name} -constraints { + nt testwinevent + } -body { + start { + set dialogresult [catch { + tk_getSaveFile -initialfile [string repeat a 1024] -title Long + } x] + } + then { + Click ok + } + list $dialogresult [string match "invalid filename *" $x] + } -result {1 1} +} test winDialog-5.16 {GetFileName: parent} -constraints { nt } -body { @@ -390,18 +389,34 @@ test winDialog-5.17 {GetFileName: title} -constraints { Click cancel } } -result {0} -test winDialog-5.18 {GetFileName: no filter specified} -constraints { - nt testwinevent -} -body { -# if (ofn.lpstrFilter == NULL) - - start {tk_getOpenFile -title Filter} - then { - set x [GetText 0x470] - Click cancel - } - return $x -} -result {All Files (*.*)} +if {[vista?]} { + # In the newer file dialogs, the file type widget does not even exist + # if no file types specified + test winDialog-5.18 {GetFileName: no filter specified} -constraints { + nt testwinevent + } -body { + # if (ofn.lpstrFilter == NULL) + start {tk_getOpenFile -title Filter} + then { + catch {set x [GetText 0x470]} y + Click cancel + } + return $y + } -result {Could not find control with id 1136} +} else { + test winDialog-5.18 {GetFileName: no filter specified} -constraints { + nt testwinevent + } -body { + # if (ofn.lpstrFilter == NULL) + + start {tk_getOpenFile -title Filter} + then { + set x [GetText 0x470] + Click cancel + } + return $x + } -result {All Files (*.*)} +} test winDialog-5.19 {GetFileName: parent HWND doesn't yet exist} -constraints { nt } -setup { @@ -458,7 +473,7 @@ test winDialog-5.23 {GetFileName: convert \ to /} -constraints { set msg {} start {set x [tk_getSaveFile -title Back]} then { - if {[catch {SetText 0x47C [file nativename \ + if {[catch {SetText [vista? 0x47C 0x3e9] [file nativename \ [file join [file normalize $::env(TEMP)] "12x 457"]]} msg]} { Click cancel } else { -- cgit v0.12 From 0fd4f089bdedc31d5f442b5434cd69083dbe9484 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Tue, 23 Sep 2014 13:08:21 +0000 Subject: Fix display of scrollbars when their window is not mapped in Tk-Cocoa --- macosx/tkMacOSXScrlbr.c | 124 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 113 insertions(+), 11 deletions(-) diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index 67d79c9..ebb99f3 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -21,13 +21,74 @@ #endif */ +NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); + +/* + * A subclass of NSScroller with sanity checking: + * + * NSScrollers created by Tk will have their tag set to a pointer to the + * TkScrollbar which manages the NSScroller. This allows an NSScroller to be + * aware of the state of its Tk parent. This subclass overrides the drawRect + * method so that it will not draw itself if the widget is completely outside + * of its container. + */ + +@interface TkNSScroller: NSScroller +-(void) drawRect:(NSRect)dirtyRect; + +@end + +@implementation TkNSScroller + + - (void)drawRect:(NSRect)dirtyRect + { + NSInteger tag = [self tag]; + if ( tag != -1) { + TkScrollbar *scrollPtr = (TkScrollbar *)tag; + MacDrawable* macWin = (MacDrawable *)scrollPtr; + Tk_Window tkwin = scrollPtr->tkwin; + NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); + /* Do not draw if the widget is misplaced or unmapped. */ + if ( NSIsEmptyRect(Tkframe) || + ! macWin->winPtr->flags & TK_MAPPED || + ! NSEqualRects(Tkframe, [self frame]) + ) { + return; + } + + /* + * Do not draw if the widget is completely outside of its parent. + */ + if (tkwin) { + int parent_height = Tk_Height(Tk_Parent(tkwin)); + int widget_height = Tk_Height(tkwin); + int y = Tk_Y(tkwin); + if ( y > parent_height || y + widget_height < 0 ) { + return; + } + + int parent_width = Tk_Width(Tk_Parent(tkwin)); + int widget_width = Tk_Width(tkwin); + int x = Tk_X(tkwin); + if (x > parent_width || x + widget_width < 0) { + return; + } + } + } + [super drawRect:dirtyRect]; + } + +@end + + + /* * Declaration of Mac specific scrollbar structure. */ typedef struct MacScrollbar { TkScrollbar info; - NSScroller *scroller; + TkNSScroller *scroller; int variant; } MacScrollbar; @@ -50,6 +111,7 @@ static void UpdateScrollbarMetrics(void); static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr); + /* * The class procedure table for the scrollbar widget. */ @@ -66,7 +128,7 @@ const Tk_ClassProcs tkpScrollbarProcs = { #define NSAppleAquaScrollBarVariantChanged @"AppleAquaScrollBarVariantChanged" @implementation TKApplication(TKScrlbr) -- (void) tkScroller: (NSScroller *) scroller +- (void) tkScroller: (TkNSScroller *) scroller { NSScrollerPart hitPart = [scroller hitPart]; TkScrollbar *scrollPtr = (TkScrollbar *)[scroller tag]; @@ -254,8 +316,8 @@ TkpDestroyScrollbar( TkScrollbar *scrollPtr) { MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; - NSScroller *scroller = macScrollPtr->scroller; - [scroller setTag:(NSInteger)0]; + TkNSScroller *scroller = macScrollPtr->scroller; + [scroller setTag:(NSInteger)-1]; TkMacOSXMakeCollectableAndRelease(macScrollPtr->scroller); } @@ -284,7 +346,7 @@ TkpDisplayScrollbar( { TkScrollbar *scrollPtr = clientData; MacScrollbar *macScrollPtr = clientData; - NSScroller *scroller = macScrollPtr->scroller; + TkNSScroller *scroller = macScrollPtr->scroller; Tk_Window tkwin = scrollPtr->tkwin; TkWindow *winPtr = (TkWindow *) tkwin; MacDrawable *macWin = (MacDrawable *) winPtr->window; @@ -357,15 +419,16 @@ TkpDisplayScrollbar( [scroller setEnabled:(knobProportion < 1.0 && (scrollPtr->vertical ? frame.size.height : frame.size.width) > metrics[macScrollPtr->variant].minHeight)]; + // [scroller setEnabled: YES]; [scroller setDoubleValue:scrollPtr->firstFraction / (1.0 - knobProportion)]; [scroller setKnobProportion:knobProportion]; [scroller displayRectIgnoringOpacity:[scroller bounds]]; TkMacOSXRestoreDrawingContext(&dc); -#ifdef TK_MAC_DEBUG_SCROLLBAR + #ifdef TK_MAC_DEBUG_SCROLLBAR TKLog(@"scroller %s frame %@ width %d height %d", ((TkWindow *)scrollPtr->tkwin)->pathName, NSStringFromRect(frame), Tk_Width(tkwin), Tk_Height(tkwin)); -#endif + #endif } /* @@ -393,7 +456,7 @@ TkpComputeScrollbarGeometry( * changed. */ { MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; - NSScroller *scroller = macScrollPtr->scroller; + TkNSScroller *scroller = macScrollPtr->scroller; int width, height, variant, fieldLength; if (scrollPtr->highlightWidth < 0) { @@ -421,7 +484,7 @@ TkpComputeScrollbarGeometry( } if (!scroller) { if ((width > height) ^ !scrollPtr->vertical) { - /* -[NSScroller initWithFrame:] determines horizonalness for the + /* -[NSScroller initWithFrame:] determines horizontalness for the * lifetime of the scroller via isHoriz = (width > height) */ if (scrollPtr->vertical) { width = height; @@ -432,7 +495,7 @@ TkpComputeScrollbarGeometry( width = 2; } } - scroller = [[NSScroller alloc] initWithFrame: + scroller = [[TkNSScroller alloc] initWithFrame: NSMakeRect(0, 0, width, height)]; macScrollPtr->scroller = TkMacOSXMakeUncollectable(scroller); [scroller setAction:@selector(tkScroller:)]; @@ -553,7 +616,7 @@ TkpScrollbarPosition( /* Scrollbar widget record. */ int x, int y) /* Coordinates within scrollPtr's window. */ { - NSScroller *scroller = ((MacScrollbar *) scrollPtr)->scroller; + TkNSScroller *scroller = ((MacScrollbar *) scrollPtr)->scroller; MacDrawable *macWin = (MacDrawable *) ((TkWindow *) scrollPtr->tkwin)->window; NSView *view = TkMacOSXDrawableView(macWin); @@ -614,6 +677,45 @@ ScrollbarEventProc( TkScrollbarEventProc(clientData, eventPtr); } } + + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXGetScrollFrame -- + * + * Computes a frame for an NSScroller that will correspond to where + * Tk thinks the scroller is located. + * + * Results: + * Returns an NSRect describing a frame for an NSScrollbar. + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ +NSRect TkMacOSXGetScrollFrame( + TkScrollbar *scrlPtr) +{ + MacScrollbar *macscrlPtr = (MacScrollbar *) scrlPtr; + Tk_Window tkwin = scrlPtr->tkwin; + TkWindow *winPtr = (TkWindow *) tkwin; + if (tkwin) { + MacDrawable *macWin = (MacDrawable *) winPtr->window; + NSView *view = TkMacOSXDrawableView(macWin); + CGFloat viewHeight = [view bounds].size.height; + NSRect frame = NSMakeRect(macWin->xOff, macWin->yOff, + Tk_Width(tkwin), Tk_Height(tkwin)); + + frame.origin.y = viewHeight - (frame.origin.y + frame.size.height); + return frame; + } else { + return NSZeroRect; + } +} + + /* * Local Variables: -- cgit v0.12 From 4e98f2a1eacfe29f773b342d942cdf1e531f492b Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Tue, 23 Sep 2014 14:25:48 +0000 Subject: Fine-tune display of buttons on Tk/Cocoa on horizontal scroll --- macosx/tkMacOSXButton.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 9858f88..f3405d7 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -66,6 +66,13 @@ static NSRect TkMacOSXGetButtonFrame(TkButton *butPtr); if ( y > parent_height - 20 || y + widget_height < 0 ) { return; } + + int parent_width = Tk_Width(Tk_Parent(tkwin)); + int widget_width = Tk_Width(tkwin); + int x = Tk_X(tkwin); + if (x > parent_width - 30 || x + widget_width < 0) { + return; + } } [super drawRect:dirtyRect]; } -- cgit v0.12 From 8c3d9368c19f90f3705404a0eccc310819f67c76 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Wed, 24 Sep 2014 23:34:38 +0000 Subject: Fixes to tkMacOSXWindowEvent.c to improve drawing performance after removal of private NSView API's --- macosx/tkMacOSXWindowEvent.c | 94 ++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 30 deletions(-) diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 0bd6398..d016790 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -356,11 +356,12 @@ GenerateUpdates( event.xexpose.width = damageBounds.size.width; event.xexpose.height = damageBounds.size.height; event.xexpose.count = 0; - Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); -#ifdef TK_MAC_DEBUG_DRAWING - TKLog(@"Expose %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x, + Tk_HandleEvent(&event); + + #ifdef TK_MAC_DEBUG_DRAWING + NSLog(@"Expose %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height); -#endif + #endif /* * Generate updates for the children of this window @@ -387,7 +388,7 @@ GenerateUpdates( /* * TODO: Here we should handle out of process embedding. */ - } + } return 1; } @@ -768,6 +769,8 @@ Tk_MacOSXIsAppInFront(void) @interface TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect; - (void) generateExposeEvents: (HIMutableShapeRef) shape; +- (void) viewDidEndLiveResize; +- (void) viewWillDraw; - (BOOL) isOpaque; - (BOOL) wantsDefaultClipping; - (BOOL) acceptsFirstResponder; @@ -777,6 +780,17 @@ Tk_MacOSXIsAppInFront(void) @implementation TKContentView @end +double drawTime; + +/* + * Set a minimum time for drawing to render. With removal of private NSView API's, default drawing + * is slower and less responsive. This number, which seems feasible after some experimentatation, skips + * some drawing to avoid lag. + */ + +#define MAX_DYNAMIC_TIME .000000001 + +/*Restrict event processing to Expose events.*/ static Tk_RestrictAction ExposeRestrictProc( ClientData arg, @@ -786,6 +800,7 @@ ExposeRestrictProc( ? TK_PROCESS_EVENT : TK_DEFER_EVENT); } + @implementation TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect @@ -801,6 +816,11 @@ ExposeRestrictProc( NSCompositeSourceOver); #endif + NSDate *beginTime=[NSDate date]; + + /*Skip drawing during live resize if redraw is too slow.*/ + if([self inLiveResize] && drawTime>MAX_DYNAMIC_TIME) return; + CGFloat height = [self bounds].size.height; HIMutableShapeRef drawShape = HIShapeCreateMutable(); @@ -820,44 +840,64 @@ ExposeRestrictProc( nil]]; } CFRelease(drawShape); + drawTime=-[beginTime timeIntervalSinceNow]; +} + +/*At conclusion of resize event, send notification and set view for redraw if earlier drawing was skipped because of lagginess.*/ +- (void)viewDidEndLiveResize +{ + if(drawTime>MAX_DYNAMIC_TIME) { + [self setNeedsDisplay:YES]; + [super viewDidEndLiveResize]; + } } +-(void) viewWillDraw { + [self setNeedsDisplay:YES]; + } + - (void) generateExposeEvents: (HIMutableShapeRef) shape { + TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); unsigned long serial; CGRect updateBounds; if (!winPtr) { - return; + return; } + HIShapeGetBounds(shape, &updateBounds); serial = LastKnownRequestProcessed(Tk_Display(winPtr)); if (GenerateUpdates(shape, &updateBounds, winPtr) && - ![[NSRunLoop currentRunLoop] currentMode] && - Tcl_GetServiceMode() != TCL_SERVICE_NONE) { - /* - * Ensure there are no pending idle-time redraws that could prevent the - * just posted Expose events from generating new redraws. - */ + ![[NSRunLoop currentRunLoop] currentMode] && + Tcl_GetServiceMode() != TCL_SERVICE_NONE) { + /* + * Ensure there are no pending idle-time redraws that could prevent the + * just posted Expose events from generating new redraws. + */ - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} - /* - * For smoother drawing, process Expose events and resulting redraws - * immediately instead of at idle time. - */ + /* + * For smoother drawing, process Expose events and resulting redraws + * immediately instead of at idle time. + */ - ClientData oldArg; - Tk_RestrictProc *oldProc = Tk_RestrictEvents(ExposeRestrictProc, - UINT2PTR(serial), &oldArg); + ClientData oldArg; + Tk_RestrictProc *oldProc = Tk_RestrictEvents(ExposeRestrictProc, + UINT2PTR(serial), &oldArg); - while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} - Tk_RestrictEvents(oldProc, oldArg, &oldArg); - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} - } + while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} + + Tk_RestrictEvents(oldProc, oldArg, &oldArg); + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} + + } + } +/*This is no-op on 10.7 and up because Apple has removed this widget, but leaving here for backwards compatibility.*/ - (void) tkToolbarButton: (id) sender { #ifdef TK_MAC_DEBUG_EVENTS @@ -885,21 +925,15 @@ ExposeRestrictProc( Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL); } -#ifdef TK_MAC_DEBUG_DRAWING - (void) setFrameSize: (NSSize) newSize { - TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, - NSStringFromSize(newSize)); [super setFrameSize:newSize]; } - (void) setNeedsDisplayInRect: (NSRect) invalidRect { - TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, - NSStringFromRect(invalidRect)); [super setNeedsDisplayInRect:invalidRect]; } -#endif - (BOOL) isOpaque { -- cgit v0.12 From 5f9d479977aa792fa0658db83a02dbf29b16ad62 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 12 Oct 2014 19:20:49 +0000 Subject: Fixed failing text-19.16 - Bug [280089486e] --- tests/font.test | 89 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 36 deletions(-) diff --git a/tests/font.test b/tests/font.test index a07e391..abe6ebf 100644 --- a/tests/font.test +++ b/tests/font.test @@ -12,7 +12,25 @@ eval tcltest::configure $argv tcltest::loadTestedCommands -catch {eval font delete [font names]} +set defaultfontlist [font names] + +proc getnondefaultfonts {} { + global defaultfontlist + set nondeffonts [list ] + foreach afont [font names] { + if {$afont ni $defaultfontlist} { + lappend nondeffonts $afont + } + } + set nondeffonts +} + +proc clearnondefaultfonts {} { + foreach afont [getnondefaultfonts] { + font delete $afont + } +} + deleteWindows # Toplevel used (in some tests) of the whole file toplevel .t @@ -161,12 +179,12 @@ test font-5.4 {font command: configure: get all options} -setup { font delete xyz } -result xyz test font-5.5 {font command: configure: get one option} -setup { - catch {eval font delete [font names]} + clearnondefaultfonts } -body { # (objc == 4) so objPtr = objv[3] font create xyz -family xyz font configure xyz -family - font names + getnondefaultfonts } -cleanup { font delete xyz } -result xyz @@ -192,34 +210,33 @@ test font-5.7 {font command: configure: bad option} -setup { test font-6.1 {font command: create: make up name} -setup { - catch {eval font delete [font names]} + clearnondefaultfonts } -body { # (objc < 3) so name = NULL font create - font names + getnondefaultfonts } -cleanup { font delete font1 } -result {font1} test font-6.2 {font command: create: name specified} -setup { - catch {eval font delete [font names]} + clearnondefaultfonts } -body { # not (objc < 3) font create xyz - font names + getnondefaultfonts } -cleanup { font delete xyz } -result {xyz} test font-6.3 {font command: create: name not really specified} -setup { - catch {eval font delete [font names]} + clearnondefaultfonts } -body { # (name[0] == '-') so name = NULL font create -family xyz - font names + getnondefaultfonts } -cleanup { font delete font1 } -result {font1} test font-6.4 {font command: create: generate name} -setup { - catch {eval font delete [font names]} } -body { # (name == NULL) font create -family one @@ -229,7 +246,7 @@ test font-6.4 {font command: create: generate name} -setup { font create -family four font configure font2 -family } -cleanup { - catch {eval font delete [font names]} + font delete font1 font2 font3 } -result {four} test font-6.5 {font command: create: bad option creating new font} -setup { catch {font delete xyz} @@ -238,7 +255,7 @@ test font-6.5 {font command: create: bad option creating new font} -setup { font create xyz -xyz times } -returnCodes error -result {bad option "-xyz": must be -family, -size, -weight, -slant, -underline, or -overstrike} test font-6.6 {font command: create: bad option creating new font} -setup { - catch {eval font delete [font names]} + clearnondefaultfonts } -body { # name was not specified so skip = 2 font create -xyz times @@ -258,7 +275,7 @@ test font-7.1 {font command: delete: arguments} -body { font delete } -returnCodes error -result {wrong # args: should be "font delete fontname ?fontname ...?"} test font-7.2 {font command: delete: loop test} -setup { - catch {eval font delete [font names]} + clearnondefaultfonts set x {} } -body { # for (i = 2; i < objc; i++) @@ -267,14 +284,14 @@ test font-7.2 {font command: delete: loop test} -setup { font create c -underline 1 font create d -underline 1 font create e -underline 1 - lappend x [lsort [font names]] + lappend x [lsort [getnondefaultfonts]] font delete a e c b - lappend x [lsort [font names]] + lappend x [lsort [getnondefaultfonts]] } -cleanup { - catch {eval font delete [font names]} + getnondefaultfonts } -result {{a b c d e} d} test font-7.3 {font command: delete: loop test} -setup { - catch {eval font delete [font names]} + clearnondefaultfonts set x {} } -body { # (namedHashPtr == NULL) in middle of loop @@ -283,11 +300,11 @@ test font-7.3 {font command: delete: loop test} -setup { font create c -underline 1 font create d -underline 1 font create e -underline 1 - lappend x [lsort [font names]] + lappend x [lsort [getnondefaultfonts]] catch {font delete a d q c e b} - lappend x [lsort [font names]] + lappend x [lsort [getnondefaultfonts]] } -cleanup { - catch {eval font delete [font names]} + clearnondefaultfonts } -result {{a b c d e} {b c e}} test font-7.4 {font command: delete: non-existent} -setup { catch {font delete xyz} @@ -434,29 +451,29 @@ test font-11.1 {font command: names: arguments} -body { font names xyz } -returnCodes error -result {wrong # args: should be "font names"} test font-11.2 {font command: names: loop test: no passes} -setup { - catch {eval font delete [font names]} + clearnondefaultfonts } -body { - font names + getnondefaultfonts } -result {} test font-11.3 {font command: names: loop test: one pass} -setup { - catch {eval font delete [font names]} + clearnondefaultfonts } -body { font create - font names + getnondefaultfonts } -result {font1} test font-11.4 {font command: names: loop test: multiple passes} -setup { - catch {eval font delete [font names]} + clearnondefaultfonts } -body { font create xyz font create abc font create def - lsort [font names] + lsort [getnondefaultfonts] } -cleanup { - catch {eval font delete [font names]} + clearnondefaultfonts } -result {abc def xyz} test font-11.5 {font command: names: skip deletePending fonts} -setup { destroy .t.f - catch {eval font delete [font names]} + clearnondefaultfonts pack [label .t.f] update set x {} @@ -464,12 +481,12 @@ test font-11.5 {font command: names: skip deletePending fonts} -setup { # (nfPtr->deletePending == 0) font create xyz font create abc - lappend x [lsort [font names]] + lappend x [lsort [getnondefaultfonts]] .t.f config -font xyz font delete xyz - lappend x [font names] + lappend x [getnondefaultfonts] } -cleanup { - catch {eval font delete [font names]} + clearnondefaultfonts } -result {{abc xyz} abc} @@ -509,9 +526,9 @@ test font-13.1 {CreateNamedFont: new named font} -setup { set x {} } -body { # not (new == 0) - lappend x [font names] + lappend x [getnondefaultfonts] font create xyz - lappend x [font names] + lappend x [getnondefaultfonts] } -cleanup { font delete xyz } -result {{} xyz} @@ -646,7 +663,7 @@ test font-15.8 {Tk_AllocFontFromObj procedure: get native font} -constraints { win } -setup { destroy .t.f - catch {eval font delete [font names]} + clearnondefaultfonts pack [label .t.f] update } -body { @@ -752,7 +769,7 @@ test font-17.3 {Tk_FreeFont procedure: multiple ref} -setup { } -result {-family fixed} test font-17.4 {Tk_FreeFont procedure: named font} -setup { destroy .t.f - catch {eval font delete [font names]} + clearnondefaultfonts pack [label .t.f] update } -body { @@ -760,7 +777,7 @@ test font-17.4 {Tk_FreeFont procedure: named font} -setup { font create xyz .t.f config -font xyz destroy .t.f - font names + getnondefaultfonts } -result {xyz} test font-17.5 {Tk_FreeFont procedure: named font} -setup { destroy .t.f -- cgit v0.12 From 903b5884e342c291c62798cbe62c8a0ea32ef9d0 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Tue, 14 Oct 2014 02:28:36 +0000 Subject: Fix for bug fb35eb59dd, thanks to Paul Walton for the report and Marc Culler for the patch --- macosx/tkMacOSXDraw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index ce8bf9b..0f8e051 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -463,7 +463,7 @@ CreateCGImageWithXImage( * Color image */ - CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); bitsPerComponent = 8; bitsPerPixel = 32; -- cgit v0.12 From 31bab1c712c72533326e72b5c324a6c996d26a84 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 14 Oct 2014 15:54:00 +0000 Subject: remove sandbox litter --- tests/menu.test | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/menu.test b/tests/menu.test index ab41a52..595a21b 100644 --- a/tests/menu.test +++ b/tests/menu.test @@ -3327,11 +3327,8 @@ test menu-22.3 {GetIndexFromCoords: mapped window, y only} -setup { menu .m1 .m1 add command -label "test" .m1 configure -tearoff 0 -puts A tk_popup .m1 0 0 -puts B tkwait visibility .m1 -puts C .m1 index @5 } -cleanup { deleteWindows -- cgit v0.12 From 53786cb2e6076f626a6be76f42b581950e4ddc24 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 14 Oct 2014 19:08:43 +0000 Subject: Bump to Tk 8.6.3; update changes file --- changes | 12 ++++++++++++ generic/tk.h | 4 ++-- library/tk.tcl | 2 +- unix/configure | 2 +- unix/configure.in | 2 +- unix/tk.spec | 2 +- win/configure | 2 +- win/configure.in | 2 +- 8 files changed, 20 insertions(+), 8 deletions(-) diff --git a/changes b/changes index d1b40e0..8fecb2e 100644 --- a/changes +++ b/changes @@ -7121,3 +7121,15 @@ Many revisions to better support a Cygwin environment (nijtmans) 2014-08-01 (bug fix) OSX font config crash (rob@bitkeeper) --- Released 8.6.2, August 27, 2014 --- http://core.tcl.tk/tk/ for details + +2014-08-27 (bug) Cocoa: Crash after [$button destroy] (walzer) + +2014-09-23 (bug) Cocoa: button and scroll display fixes (walzer) + +2014-09-24 (bug) Cocoa: improved drawing performance (walzer) + +2014-10-11 (bug)[9e487e] Phony button clicks from browsers to plugin (nijtmans) + +2014-10-11 (bug)[810c43] [text] elide changes advance epoch (vogel) + +--- Released 8.6.3, October 25, 2014 --- http://core.tcl.tk/tk/ for details diff --git a/generic/tk.h b/generic/tk.h index 0e00ca2..bd3c4f1 100644 --- a/generic/tk.h +++ b/generic/tk.h @@ -75,10 +75,10 @@ extern "C" { #define TK_MAJOR_VERSION 8 #define TK_MINOR_VERSION 6 #define TK_RELEASE_LEVEL TCL_FINAL_RELEASE -#define TK_RELEASE_SERIAL 2 +#define TK_RELEASE_SERIAL 3 #define TK_VERSION "8.6" -#define TK_PATCH_LEVEL "8.6.2" +#define TK_PATCH_LEVEL "8.6.3" /* * A special definition used to allow this header file to be included from diff --git a/library/tk.tcl b/library/tk.tcl index 5f7a74e..b7d85c4 100644 --- a/library/tk.tcl +++ b/library/tk.tcl @@ -13,7 +13,7 @@ # Insist on running with compatible version of Tcl package require Tcl 8.6 # Verify that we have Tk binary and script components from the same release -package require -exact Tk 8.6.2 +package require -exact Tk 8.6.3 # Create a ::tk namespace namespace eval ::tk { diff --git a/unix/configure b/unix/configure index 741ab74..7d4a3e4 100755 --- a/unix/configure +++ b/unix/configure @@ -1338,7 +1338,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu TK_VERSION=8.6 TK_MAJOR_VERSION=8 TK_MINOR_VERSION=6 -TK_PATCH_LEVEL=".2" +TK_PATCH_LEVEL=".3" VERSION=${TK_VERSION} LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv" diff --git a/unix/configure.in b/unix/configure.in index 9b0180f..ba1f077 100644 --- a/unix/configure.in +++ b/unix/configure.in @@ -25,7 +25,7 @@ m4_ifdef([SC_USE_CONFIG_HEADERS], [ TK_VERSION=8.6 TK_MAJOR_VERSION=8 TK_MINOR_VERSION=6 -TK_PATCH_LEVEL=".2" +TK_PATCH_LEVEL=".3" VERSION=${TK_VERSION} LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv" diff --git a/unix/tk.spec b/unix/tk.spec index d2ca9d9..3b40820 100644 --- a/unix/tk.spec +++ b/unix/tk.spec @@ -4,7 +4,7 @@ Name: tk Summary: Tk graphical toolkit for the Tcl scripting language. -Version: 8.6.2 +Version: 8.6.3 Release: 2 License: BSD Group: Development/Languages diff --git a/win/configure b/win/configure index 7eba14e..0504f70 100755 --- a/win/configure +++ b/win/configure @@ -1312,7 +1312,7 @@ SHELL=/bin/sh TK_VERSION=8.6 TK_MAJOR_VERSION=8 TK_MINOR_VERSION=6 -TK_PATCH_LEVEL=".2" +TK_PATCH_LEVEL=".3" VER=$TK_MAJOR_VERSION$TK_MINOR_VERSION #------------------------------------------------------------------------ diff --git a/win/configure.in b/win/configure.in index 3fedbf6..ce49151 100644 --- a/win/configure.in +++ b/win/configure.in @@ -14,7 +14,7 @@ SHELL=/bin/sh TK_VERSION=8.6 TK_MAJOR_VERSION=8 TK_MINOR_VERSION=6 -TK_PATCH_LEVEL=".2" +TK_PATCH_LEVEL=".3" VER=$TK_MAJOR_VERSION$TK_MINOR_VERSION #------------------------------------------------------------------------ -- cgit v0.12 From 07b9a8ea4f38e01171560970fccd6b8e30a636df Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 14 Oct 2014 19:13:50 +0000 Subject: update changes --- changes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changes b/changes index 8fecb2e..199c4c2 100644 --- a/changes +++ b/changes @@ -7132,4 +7132,6 @@ Many revisions to better support a Cygwin environment (nijtmans) 2014-10-11 (bug)[810c43] [text] elide changes advance epoch (vogel) +2014-10-14 (bug)[fb35eb] fix PNG transparency appearance (walton,culler) + --- Released 8.6.3, October 25, 2014 --- http://core.tcl.tk/tk/ for details -- cgit v0.12 From 5511931d970d4ff124e84f8875949010793f52ce Mon Sep 17 00:00:00 2001 From: ashok Date: Wed, 15 Oct 2014 15:28:41 +0000 Subject: Updated documentation for tk_getOpen/SaveFile -initialdir option --- doc/getOpenFile.n | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/getOpenFile.n b/doc/getOpenFile.n index 95884bb..30e7cd5 100644 --- a/doc/getOpenFile.n +++ b/doc/getOpenFile.n @@ -65,8 +65,12 @@ discussion on the contents of \fIfilePatternList\fR. \fB\-initialdir\fR \fIdirectory\fR . Specifies that the files in \fIdirectory\fR should be displayed -when the dialog pops up. If this parameter is not specified, then -the files in the current working directory are displayed. If the +when the dialog pops up. If this parameter is not specified, +the initial directory defaults to the current working directory +on non-Windows systems and on Windows systems prior to Vista. +On Vista and later systems, the initial directory defaults to the last +user-selected directory for the application. +If the parameter specifies a relative path, the return value will convert the relative path to an absolute path. .TP -- cgit v0.12 From 10acb72b597836cabb2913980aae7df88ab2af4a Mon Sep 17 00:00:00 2001 From: ashok Date: Thu, 16 Oct 2014 02:45:40 +0000 Subject: Updated chooseDirectory docs for Vista --- doc/chooseDirectory.n | 7 +++++-- doc/getOpenFile.n | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/chooseDirectory.n b/doc/chooseDirectory.n index 295c75b..86c593d 100644 --- a/doc/chooseDirectory.n +++ b/doc/chooseDirectory.n @@ -19,8 +19,11 @@ possible as command line arguments: .TP \fB\-initialdir\fR \fIdirname\fR Specifies that the directories in \fIdirectory\fR should be displayed -when the dialog pops up. If this parameter is not specified, then -the directories in the current working directory are displayed. If the +when the dialog pops up. If this parameter is not specified, +the initial directory defaults to the current working directory +on non-Windows systems and on Windows systems prior to Vista. +On Vista and later systems, the initial directory defaults to the last +user-selected directory for the application. If the parameter specifies a relative path, the return value will convert the relative path to an absolute path. .TP diff --git a/doc/getOpenFile.n b/doc/getOpenFile.n index 30e7cd5..f5e92ff 100644 --- a/doc/getOpenFile.n +++ b/doc/getOpenFile.n @@ -69,8 +69,7 @@ when the dialog pops up. If this parameter is not specified, the initial directory defaults to the current working directory on non-Windows systems and on Windows systems prior to Vista. On Vista and later systems, the initial directory defaults to the last -user-selected directory for the application. -If the +user-selected directory for the application. If the parameter specifies a relative path, the return value will convert the relative path to an absolute path. .TP -- cgit v0.12 From 7ce8f8785fa58840a3a8cc90c6b3dab49b4f06bd Mon Sep 17 00:00:00 2001 From: ashok Date: Thu, 16 Oct 2014 02:46:56 +0000 Subject: Fixes to compile with newer Visual Studio versions --- win/tkWinDialog.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 67f0df4..036f9a9 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -272,19 +272,21 @@ typedef struct _COMDLG_FILTERSPEC { LPCWSTR pszSpec; } COMDLG_FILTERSPEC; -static CLSID CLSID_FileOpenDialog = { +/* + * Older compilers do not define these CLSIDs so we do so here under + * a slightly different name so as to not clash with the definitions + * in new compilers + */ +static const CLSID ClsidFileOpenDialog = { 0xDC1C5A9C, 0xE88A, 0X4DDE, 0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7 }; - -static IID IID_IFileOpenDialog = { - 0xD57C7288, 0xD4AD, 0x4768, 0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60 -}; - -static CLSID CLSID_FileSaveDialog = { +static const CLSID ClsidFileSaveDialog = { 0xC0B4E2F3, 0xBA21, 0x4773, 0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B }; - -static IID IID_IFileSaveDialog = { +static const IID IIDIFileOpenDialog = { + 0xD57C7288, 0xD4AD, 0x4768, 0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60 +}; +static const IID IIDIFileSaveDialog = { 0x84BCCD23, 0x5FDE, 0x4CDB, 0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB }; @@ -1110,7 +1112,6 @@ ParseOFNOptions( Tcl_DStringFree(&ds); break; case FILE_PARENT: - /* XXX - check */ optsPtr->tkwin = Tk_NameToWindow(interp, string, clientData); if (optsPtr->tkwin == NULL) goto error_return; @@ -1181,12 +1182,12 @@ static int VistaFileDialogsAvailable() /* Ensure all COM interfaces we use are available */ if (SUCCEEDED(hr)) { - hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgPtr); + hr = CoCreateInstance(&ClsidFileOpenDialog, NULL, + CLSCTX_INPROC_SERVER, &IIDIFileOpenDialog, &fdlgPtr); if (SUCCEEDED(hr)) { fdlgPtr->lpVtbl->Release(fdlgPtr); - hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, + hr = CoCreateInstance(&ClsidFileSaveDialog, NULL, + CLSCTX_INPROC_SERVER, &IIDIFileSaveDialog, &fdlgPtr); if (SUCCEEDED(hr)) { fdlgPtr->lpVtbl->Release(fdlgPtr); @@ -1265,11 +1266,11 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, */ if (oper == OFN_FILE_OPEN || oper == OFN_DIR_CHOOSE) - hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileOpenDialog, &fdlgIf); + hr = CoCreateInstance(&ClsidFileOpenDialog, NULL, + CLSCTX_INPROC_SERVER, &IIDIFileOpenDialog, &fdlgIf); else - hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, - CLSCTX_INPROC_SERVER, &IID_IFileSaveDialog, &fdlgIf); + hr = CoCreateInstance(&ClsidFileSaveDialog, NULL, + CLSCTX_INPROC_SERVER, &IIDIFileSaveDialog, &fdlgIf); if (FAILED(hr)) goto vamoose; @@ -1284,7 +1285,7 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, goto vamoose; if (filterPtr) { - flags |= FOS_STRICTFILETYPES; /* XXX - does this match old behaviour? */ + flags |= FOS_STRICTFILETYPES; hr = fdlgIf->lpVtbl->SetFileTypes(fdlgIf, nfilters, filterPtr); if (FAILED(hr)) goto vamoose; -- cgit v0.12 From c92b7c501167ca465f16ca7a00d876719a781e07 Mon Sep 17 00:00:00 2001 From: ashok Date: Thu, 16 Oct 2014 02:48:20 +0000 Subject: Changed to not use c:/ as initialdir --- tests/winDialog.test | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index f21fa18..fc1114a 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -27,6 +27,16 @@ proc vista? {{prevista 0} {postvista 1}} { return [expr {$major >= 6 ? $postvista : $prevista}] } +# What directory to use in initialdir tests. Old code used to use +# c:/. However, on Vista/later that is a protected directory if you +# are not running privileged. Moreover, not everyone has a drive c: +# but not having a TEMP would break a lot Windows programs +proc initialdir {} { + # file join to return in Tcl canonical format (/ separator, not \) + return [file join $::env(TEMP)] +} + + proc start {arg} { set ::tk_dialog 0 set ::iter_after 0 @@ -227,7 +237,7 @@ test winDialog-5.2 {GetFileName: one argument} -constraints { test winDialog-5.3 {GetFileName: many arguments} -constraints { nt testwinevent } -body { - start {tk_getOpenFile -initialdir c:/ -parent . -title test -initialfile foo} + start {tk_getOpenFile -initialdir [initialdir] -parent . -title test -initialfile foo} then { Click cancel } @@ -539,7 +549,7 @@ test winDialog-9.3 {Tk_ChooseDirectoryObjCmd: many arguments} -constraints { nt testwinevent } -body { start { - tk_chooseDirectory -initialdir c:/ -mustexist 1 -parent . -title test + tk_chooseDirectory -initialdir [initialdir] -mustexist 1 -parent . -title test } then { Click cancel @@ -568,12 +578,12 @@ test winDialog-9.7 {Tk_ChooseDirectoryObjCmd: -initialdir} -constraints { } -body { # case DIR_INITIAL: - start {set x [tk_chooseDirectory -initialdir c:/ -title Foo]} + start {set x [tk_chooseDirectory -initialdir [initialdir] -title Foo]} then { Click ok } string tolower [set x] -} -result {c:/} +} -result [initialdir] test winDialog-9.8 {Tk_ChooseDirectoryObjCmd: initial directory: Tcl_TranslateFilename()} -constraints { nt } -body { -- cgit v0.12 From 77374e15178cdd57ecc3c37945eb1532474f61b9 Mon Sep 17 00:00:00 2001 From: ashok Date: Thu, 16 Oct 2014 16:36:58 +0000 Subject: Make tkWinDialog.c buildable with gcc 4.8.1, vc6, vs2012. Passes all tests --- win/tkWinDialog.c | 78 +++++++++++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 036f9a9..51e98f9 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -256,6 +256,24 @@ struct IShellItemArray { #endif /* __IShellItemArray_INTERFACE_DEFINED__ */ +/* + * Older compilers do not define these CLSIDs so we do so here under + * a slightly different name so as to not clash with the definitions + * in new compilers + */ +static const CLSID ClsidFileOpenDialog = { + 0xDC1C5A9C, 0xE88A, 0X4DDE, {0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7} +}; +static const CLSID ClsidFileSaveDialog = { + 0xC0B4E2F3, 0xBA21, 0x4773, {0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B} +}; +static const IID IIDIFileOpenDialog = { + 0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60} +}; +static const IID IIDIFileSaveDialog = { + 0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB} +}; + #ifndef __IFileDialog_INTERFACE_DEFINED__ /* Forward declarations for structs that are referenced but not used */ @@ -272,24 +290,6 @@ typedef struct _COMDLG_FILTERSPEC { LPCWSTR pszSpec; } COMDLG_FILTERSPEC; -/* - * Older compilers do not define these CLSIDs so we do so here under - * a slightly different name so as to not clash with the definitions - * in new compilers - */ -static const CLSID ClsidFileOpenDialog = { - 0xDC1C5A9C, 0xE88A, 0X4DDE, 0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7 -}; -static const CLSID ClsidFileSaveDialog = { - 0xC0B4E2F3, 0xBA21, 0x4773, 0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B -}; -static const IID IIDIFileOpenDialog = { - 0xD57C7288, 0xD4AD, 0x4768, 0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60 -}; -static const IID IIDIFileSaveDialog = { - 0x84BCCD23, 0x5FDE, 0x4CDB, 0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB -}; - enum _FILEOPENDIALOGOPTIONS { FOS_OVERWRITEPROMPT = 0x2, FOS_STRICTFILETYPES = 0x4, @@ -538,10 +538,18 @@ static UINT CALLBACK ColorDlgHookProc(HWND hDlg, UINT uMsg, WPARAM wParam, static void CleanupOFNOptions(OFNOpts *optsPtr); static int ParseOFNOptions(ClientData clientData, Tcl_Interp *interp, int objc, - Tcl_Obj *const objv[], int open, OFNOpts *optsPtr); + Tcl_Obj *const objv[], enum OFNOper oper, OFNOpts *optsPtr); +static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, + enum OFNOper oper); +static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, + enum OFNOper oper); static int GetFileName(ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *const objv[], int isOpen); + Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[], enum OFNOper oper); +static int MakeFilterVista(Tcl_Interp *interp, OFNOpts *optsPtr, + DWORD *countPtr, COMDLG_FILTERSPEC **dlgFilterPtrPtr, + DWORD *defaultFilterIndexPtr); +static void FreeFilterVista(DWORD count, COMDLG_FILTERSPEC *dlgFilterPtr); static int MakeFilter(Tcl_Interp *interp, Tcl_Obj *valuePtr, Tcl_DString *dsPtr, Tcl_Obj *initialPtr, int *indexPtr); @@ -553,12 +561,6 @@ static const char *ConvertExternalFilename(TCHAR *filename, Tcl_DString *dsPtr); static void LoadShellProcs(void); -static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, int open); -static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, int open); -static int MakeFilterVista(Tcl_Interp *interp, OFNOpts *optsPtr, - DWORD *countPtr, COMDLG_FILTERSPEC **dlgFilterPtrPtr, - DWORD *defaultFilterIndexPtr); -static void FreeFilterVista(DWORD count, COMDLG_FILTERSPEC *dlgFilterPtr); /* Definitions of dynamically loaded Win32 calls */ typedef HRESULT (STDAPICALLTYPE SHCreateItemFromParsingNameProc)( @@ -567,9 +569,6 @@ struct ShellProcPointers { SHCreateItemFromParsingNameProc *SHCreateItemFromParsingName; } ShellProcs; - - - /* *------------------------------------------------------------------------- @@ -1011,7 +1010,6 @@ ParseOFNOptions( FILE_DEFAULT, FILE_TYPES, FILE_INITDIR, FILE_INITFILE, FILE_PARENT, FILE_TITLE, FILE_TYPEVARIABLE, FILE_MULTIPLE, FILE_CONFIRMOW, FILE_MUSTEXIST, - FILE_UNDOCUMENTED_XP_STYLE /* XXX - force XP - style dialogs */ }; struct Options { const char *name; @@ -1183,12 +1181,12 @@ static int VistaFileDialogsAvailable() /* Ensure all COM interfaces we use are available */ if (SUCCEEDED(hr)) { hr = CoCreateInstance(&ClsidFileOpenDialog, NULL, - CLSCTX_INPROC_SERVER, &IIDIFileOpenDialog, &fdlgPtr); + CLSCTX_INPROC_SERVER, &IIDIFileOpenDialog, (void **) &fdlgPtr); if (SUCCEEDED(hr)) { fdlgPtr->lpVtbl->Release(fdlgPtr); hr = CoCreateInstance(&ClsidFileSaveDialog, NULL, CLSCTX_INPROC_SERVER, &IIDIFileSaveDialog, - &fdlgPtr); + (void **) &fdlgPtr); if (SUCCEEDED(hr)) { fdlgPtr->lpVtbl->Release(fdlgPtr); @@ -1267,10 +1265,10 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, if (oper == OFN_FILE_OPEN || oper == OFN_DIR_CHOOSE) hr = CoCreateInstance(&ClsidFileOpenDialog, NULL, - CLSCTX_INPROC_SERVER, &IIDIFileOpenDialog, &fdlgIf); + CLSCTX_INPROC_SERVER, &IIDIFileOpenDialog, (void **) &fdlgIf); else hr = CoCreateInstance(&ClsidFileSaveDialog, NULL, - CLSCTX_INPROC_SERVER, &IIDIFileSaveDialog, &fdlgIf); + CLSCTX_INPROC_SERVER, &IIDIFileSaveDialog, (void **) &fdlgIf); if (FAILED(hr)) goto vamoose; @@ -1356,7 +1354,7 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, Tcl_DStringLength(&optsPtr->utfDirString), &dirString); hr = ShellProcs.SHCreateItemFromParsingName( (TCHAR *) Tcl_DStringValue(&dirString), NULL, - &IID_IShellItem, &dirIf); + &IID_IShellItem, (void **) &dirIf); /* XXX - Note on failure we do not raise error, simply ignore ini dir */ if (SUCCEEDED(hr)) { /* Note we use SetFolder, not SetDefaultFolder - see MSDN docs */ @@ -1851,8 +1849,8 @@ OFNHookProc( buffer = ofnData->dynFileBuffer; hdlg = GetParent(hdlg); - selsize = SendMessage(hdlg, CDM_GETSPEC, 0, 0); - dirsize = SendMessage(hdlg, CDM_GETFOLDERPATH, 0, 0); + selsize = (int) SendMessage(hdlg, CDM_GETSPEC, 0, 0); + dirsize = (int) SendMessage(hdlg, CDM_GETFOLDERPATH, 0, 0); buffersize = (selsize + dirsize + 1); /* @@ -2202,7 +2200,7 @@ static int MakeFilterVista( nbytes = Tcl_DStringLength(&ds); /* # bytes, not Unicode chars */ nbytes += sizeof(WCHAR); /* Terminating \0 */ dlgFilterPtr[i].pszName = ckalloc(nbytes); - memmove(dlgFilterPtr[i].pszName, Tcl_DStringValue(&ds), nbytes); + memmove((void *) dlgFilterPtr[i].pszName, Tcl_DStringValue(&ds), nbytes); Tcl_DStringFree(&ds); /* @@ -2230,7 +2228,7 @@ static int MakeFilterVista( nbytes = Tcl_DStringLength(&ds); /* # bytes, not Unicode chars */ nbytes += sizeof(WCHAR); /* Terminating \0 */ dlgFilterPtr[i].pszSpec = ckalloc(nbytes); - memmove(dlgFilterPtr[i].pszSpec, Tcl_DStringValue(&ds), nbytes); + memmove((void *)dlgFilterPtr[i].pszSpec, Tcl_DStringValue(&ds), nbytes); Tcl_DStringFree(&ds); Tcl_DStringFree(&patterns); } -- cgit v0.12 From be604a17415f8e93fa88b4a00fb136732fc5b0e4 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 17 Oct 2014 14:24:09 +0000 Subject: Fix symbol conflict when compiling with latest (??) MinGW-w64. --- win/tkWinDialog.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 51e98f9..211875e 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -285,10 +285,10 @@ typedef enum FDAP { FDAP_TOP = 1 } FDAP; -typedef struct _COMDLG_FILTERSPEC { +typedef struct { LPCWSTR pszName; LPCWSTR pszSpec; -} COMDLG_FILTERSPEC; +} TCLCOMDLG_FILTERSPEC; enum _FILEOPENDIALOGOPTIONS { FOS_OVERWRITEPROMPT = 0x2, @@ -326,7 +326,7 @@ typedef struct IFileDialogVtbl ULONG ( STDMETHODCALLTYPE *Release )( IFileDialog * this); HRESULT ( STDMETHODCALLTYPE *Show )( IFileDialog * this, HWND hwndOwner); HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( IFileDialog * this, - UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec); + UINT cFileTypes, const TCLCOMDLG_FILTERSPEC *rgFilterSpec); HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )(IFileDialog * this, UINT); HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )(IFileDialog * this, UINT *); /* XXX - Actually pfde is IFileDialogEvents* but we do not use @@ -391,7 +391,7 @@ typedef struct IFileSaveDialogVtbl { HRESULT ( STDMETHODCALLTYPE *Show )( IFileSaveDialog * this, HWND hwndOwner); HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( IFileSaveDialog * this, - UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec); + UINT cFileTypes, const TCLCOMDLG_FILTERSPEC *rgFilterSpec); HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( IFileSaveDialog * this, UINT iFileType); HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( @@ -466,7 +466,7 @@ typedef struct IFileOpenDialogVtbl { ULONG ( STDMETHODCALLTYPE *Release )( IFileOpenDialog * this); HRESULT ( STDMETHODCALLTYPE *Show )( IFileOpenDialog * this, HWND); HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( IFileOpenDialog * this, - UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec); + UINT cFileTypes, const TCLCOMDLG_FILTERSPEC *rgFilterSpec); HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( IFileOpenDialog * this, UINT iFileType); HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( @@ -547,9 +547,9 @@ static int GetFileName(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], enum OFNOper oper); static int MakeFilterVista(Tcl_Interp *interp, OFNOpts *optsPtr, - DWORD *countPtr, COMDLG_FILTERSPEC **dlgFilterPtrPtr, + DWORD *countPtr, TCLCOMDLG_FILTERSPEC **dlgFilterPtrPtr, DWORD *defaultFilterIndexPtr); -static void FreeFilterVista(DWORD count, COMDLG_FILTERSPEC *dlgFilterPtr); +static void FreeFilterVista(DWORD count, TCLCOMDLG_FILTERSPEC *dlgFilterPtr); static int MakeFilter(Tcl_Interp *interp, Tcl_Obj *valuePtr, Tcl_DString *dsPtr, Tcl_Obj *initialPtr, int *indexPtr); @@ -1225,7 +1225,7 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, HRESULT hr; HWND hWnd; DWORD flags, nfilters, defaultFilterIndex; - COMDLG_FILTERSPEC *filterPtr = NULL; + TCLCOMDLG_FILTERSPEC *filterPtr = NULL; IFileDialog *fdlgIf = NULL; IShellItem *dirIf = NULL; LPWSTR wstr; @@ -2113,7 +2113,7 @@ MakeFilter( * Frees storage previously allocated by MakeFilterVista. * count is the number of elements in dlgFilterPtr[] */ -static void FreeFilterVista(DWORD count, COMDLG_FILTERSPEC *dlgFilterPtr) +static void FreeFilterVista(DWORD count, TCLCOMDLG_FILTERSPEC *dlgFilterPtr) { if (dlgFilterPtr != NULL) { DWORD dw; @@ -2147,13 +2147,13 @@ static int MakeFilterVista( Tcl_Interp *interp, /* Current interpreter. */ OFNOpts *optsPtr, /* Caller specified options */ DWORD *countPtr, /* Will hold number of filters */ - COMDLG_FILTERSPEC **dlgFilterPtrPtr, /* Will hold pointer to filter array. + TCLCOMDLG_FILTERSPEC **dlgFilterPtrPtr, /* Will hold pointer to filter array. Set to NULL if no filters specified. Must be freed by calling FreeFilterVista */ DWORD *initialIndexPtr) /* Will hold index of default type */ { - COMDLG_FILTERSPEC *dlgFilterPtr; + TCLCOMDLG_FILTERSPEC *dlgFilterPtr; const char *initial = NULL; FileFilterList flist; FileFilter *filterPtr; -- cgit v0.12 From dfc524e359974ceccac12721ce48089adf8818b7 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 17 Oct 2014 14:49:00 +0000 Subject: Previous commit probably broke higher VS versions (>2012) compilation. Fix that. --- win/tkWinDialog.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 211875e..ee30806 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -274,7 +274,9 @@ static const IID IIDIFileSaveDialog = { 0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB} }; -#ifndef __IFileDialog_INTERFACE_DEFINED__ +#ifdef __IFileDialog_INTERFACE_DEFINED__ +# define TCLCOMDLG_FILTERSPEC COMDLG_FILTERSPEC +#else /* Forward declarations for structs that are referenced but not used */ typedef struct IPropertyStore IPropertyStore; -- cgit v0.12 From 555fad6bd56d8aaf4978f6179ad93d29a95629a9 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 18 Oct 2014 18:49:47 +0000 Subject: Fix display of buttons on Cocoa if horizontally scrolled outside parent widget --- macosx/tkMacOSXButton.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index f3405d7..adbdda0 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -67,10 +67,11 @@ static NSRect TkMacOSXGetButtonFrame(TkButton *butPtr); return; } + /* Do not draw if the widget is completely outside of its parent, or within 50 pixels of the right border; this prevents buttons from being drawn on peer widgets as scrolling occurs. */ int parent_width = Tk_Width(Tk_Parent(tkwin)); int widget_width = Tk_Width(tkwin); int x = Tk_X(tkwin); - if (x > parent_width - 30 || x + widget_width < 0) { + if (x > parent_width - 50 || x < 0) { return; } } -- cgit v0.12 From 3773a56dca30e73a9217e21b6790851fd03f0bad Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 20 Oct 2014 03:24:44 +0000 Subject: Replace use of ::env(TEMP) with use of [tcltest::temporaryDirectory] for improved portability of the test suite. --- tests/winDialog.test | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index fc1114a..bbacf3f 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -33,7 +33,8 @@ proc vista? {{prevista 0} {postvista 1}} { # but not having a TEMP would break a lot Windows programs proc initialdir {} { # file join to return in Tcl canonical format (/ separator, not \) - return [file join $::env(TEMP)] + #return [file join $::env(TEMP)] + return [tcltest::temporaryDirectory] } @@ -320,21 +321,19 @@ test winDialog-5.10 {GetFileName: file types: MakeFilter() fails} -constraints { tk_getSaveFile -filetypes {{"foo" .foo FOO}} } -returnCodes error -result {bad Macintosh file type "FOO"} -if {[info exists ::env(TEMP)]} { test winDialog-5.11 {GetFileName: initial directory} -constraints { nt testwinevent } -body { # case FILE_INITDIR: unset -nocomplain x start {set x [tk_getSaveFile \ - -initialdir [file normalize $::env(TEMP)] \ + -initialdir [initialdir] \ -initialfile "12x 455" -title Foo]} then { Click ok } return $x -} -result [file join [file normalize $::env(TEMP)] "12x 455"] -} +} -result [file join [initialdir] "12x 455"] test winDialog-5.12 {GetFileName: initial directory: Tcl_TranslateFilename()} -constraints { nt } -body { @@ -476,7 +475,6 @@ test winDialog-5.22 {GetFileName: call GetSaveFileName} -constraints { } return $x } -result {&Save} -if {[info exists ::env(TEMP)]} { test winDialog-5.23 {GetFileName: convert \ to /} -constraints { nt testwinevent } -body { @@ -484,7 +482,7 @@ test winDialog-5.23 {GetFileName: convert \ to /} -constraints { start {set x [tk_getSaveFile -title Back]} then { if {[catch {SetText [vista? 0x47C 0x3e9] [file nativename \ - [file join [file normalize $::env(TEMP)] "12x 457"]]} msg]} { + [file join [initialdir] "12x 457"]]} msg]} { Click cancel } else { Click ok @@ -493,8 +491,7 @@ test winDialog-5.23 {GetFileName: convert \ to /} -constraints { return $x$msg } -cleanup { unset msg -} -result [file join [file normalize $::env(TEMP)] "12x 457"] -} +} -result [file join [initialdir] "12x 457"] test winDialog-5.24 {GetFileName: file types: MakeFilter() succeeds} -constraints { nt } -body { -- cgit v0.12 From 9fd716587273d2aabf8b67fb6d6110c0cd2e486a Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 20 Oct 2014 03:28:27 +0000 Subject: update changes --- changes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changes b/changes index 199c4c2..5d2997c 100644 --- a/changes +++ b/changes @@ -7134,4 +7134,6 @@ Many revisions to better support a Cygwin environment (nijtmans) 2014-10-14 (bug)[fb35eb] fix PNG transparency appearance (walton,culler) +2014-10-18 (feature)[TIP 432] Win: updated file dialogs (nadkarni) + --- Released 8.6.3, October 25, 2014 --- http://core.tcl.tk/tk/ for details -- cgit v0.12 From 3a75326e43c5f04164e7b9747d8e8e1b081cbe01 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 20 Oct 2014 09:20:32 +0000 Subject: - Fix winDialog-9.7 test in case "initialdir" contains capital characters. - Add "uuid.lib" as requirement for tkWinDialog.c --- tests/winDialog.test | 6 +----- win/tkWinDialog.c | 5 ++--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index bbacf3f..ad648c0 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -264,10 +264,6 @@ test winDialog-5.6 {GetFileName: valid option, but missing value} -constraints { test winDialog-5.7 {GetFileName: extension begins with .} -constraints { nt testwinevent } -body { -# if (string[0] == '.') { -# string++; -# } - start {set x [tk_getSaveFile -defaultextension .foo -title Save]} set msg {} then { @@ -580,7 +576,7 @@ test winDialog-9.7 {Tk_ChooseDirectoryObjCmd: -initialdir} -constraints { Click ok } string tolower [set x] -} -result [initialdir] +} -result [string tolower [initialdir]] test winDialog-9.8 {Tk_ChooseDirectoryObjCmd: initial directory: Tcl_TranslateFilename()} -constraints { nt } -body { diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index ee30806..fd5b809 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -14,9 +14,6 @@ #include "tkFont.h" #include /* includes common dialog functionality */ -#ifdef _MSC_VER -# pragma comment (lib, "comdlg32.lib") -#endif #include /* includes common dialog template defines */ #include /* includes the common dialog error codes */ @@ -25,6 +22,8 @@ #ifdef _MSC_VER # pragma comment (lib, "shell32.lib") +# pragma comment (lib, "comdlg32.lib") +# pragma comment (lib, "uuid.lib") #endif /* These needed for compilation with VC++ 5.2 */ -- cgit v0.12 From bbd2c853245f2b25f75c023031ad1cceb14fd751 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 20 Oct 2014 10:27:01 +0000 Subject: Make sure IID_IShellItem is defined even when uuid.lib does not export it. Idea stolen from here: [http://trac.wxwidgets.org/changeset/71395] --- win/tkWinDialog.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index fd5b809..b4c06fd 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -528,6 +528,13 @@ struct IFileOpenDialog #endif /* __IFileDialog_INTERFACE_DEFINED__ */ +/* Define this GUID in any case, even when __IShellItem_INTERFACE_DEFINED__ is + * defined in the headers we might still not have it in the actual uuid.lib, + * this happens with at least VC7 used with its original (i.e. not updated) SDK + * and there is no harm in defining the GUID unconditionally. */ +DEFINE_GUID(IID_IShellItem, + 0x43826D1E, 0xE718, 0x42EE, 0xBC, 0x55, 0xA1, 0xE2, 0x61, 0xC3, 0x7B, 0xFE); + /* * Definitions of functions used only in this file. */ -- cgit v0.12 From 9e8106de69e58e125920c9d7c3323f205bb711e2 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 20 Oct 2014 22:20:15 +0000 Subject: Make tkWinDialog.c compile with MinGW 4.0.2. Don't use "this" (possible conflict with C++ compiler). Eliminate end-of-line spaces. --- win/tkWinDialog.c | 419 +++++++++++++++++++++++++++++------------------------- 1 file changed, 222 insertions(+), 197 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index b4c06fd..9954a57 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -219,33 +219,63 @@ typedef enum SIATTRIBFLAGS { SIATTRIBFLAGS_MASK = 0x3, SIATTRIBFLAGS_ALLITEMS = 0x4000 } SIATTRIBFLAGS; +typedef ULONG SFGAOF; + +typedef struct IShellItem IShellItem; + +typedef enum __MIDL_IShellItem_0001 { + SIGDN_NORMALDISPLAY = 0,SIGDN_PARENTRELATIVEPARSING = 0x80018001,SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8001c001, + SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,SIGDN_PARENTRELATIVEEDITING = 0x80031001,SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, + SIGDN_FILESYSPATH = 0x80058000,SIGDN_URL = 0x80068000 +} SIGDN; + +typedef DWORD SICHINTF; + +typedef struct IShellItemVtbl +{ + BEGIN_INTERFACE + + HRESULT (STDMETHODCALLTYPE *QueryInterface)(IShellItem *, REFIID, void **); + ULONG (STDMETHODCALLTYPE *AddRef)(IShellItem *); + ULONG (STDMETHODCALLTYPE *Release)(IShellItem *); + HRESULT (STDMETHODCALLTYPE *BindToHandler)(IShellItem *, IBindCtx *, REFGUID, REFIID, void **); + HRESULT (STDMETHODCALLTYPE *GetParent)(IShellItem *, IShellItem **); + HRESULT (STDMETHODCALLTYPE *GetDisplayName)(IShellItem *, SIGDN, LPOLESTR *); + HRESULT (STDMETHODCALLTYPE *GetAttributes)(IShellItem *, SFGAOF, SFGAOF *); + HRESULT (STDMETHODCALLTYPE *Compare)(IShellItem *, IShellItem *, SICHINTF, int *); + + END_INTERFACE +} IShellItemVtbl; +struct IShellItem { + CONST_VTBL struct IShellItemVtbl *lpVtbl; +}; typedef struct IShellItemArray IShellItemArray; typedef struct IShellItemArrayVtbl { BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( - IShellItemArray * this, REFIID riid,void **ppvObject); - ULONG ( STDMETHODCALLTYPE *AddRef )(IShellItemArray * this); - ULONG ( STDMETHODCALLTYPE *Release )(IShellItemArray * this); - HRESULT ( STDMETHODCALLTYPE *BindToHandler )(IShellItemArray * this, - IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppvOut); + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IShellItemArray *, REFIID riid,void **ppvObject); + ULONG ( STDMETHODCALLTYPE *AddRef )(IShellItemArray *); + ULONG ( STDMETHODCALLTYPE *Release )(IShellItemArray *); + HRESULT ( STDMETHODCALLTYPE *BindToHandler )(IShellItemArray *, + IBindCtx *, REFGUID, REFIID, void **); /* flags is actually is enum GETPROPERTYSTOREFLAGS */ HRESULT ( STDMETHODCALLTYPE *GetPropertyStore )( - IShellItemArray * this, int flags, REFIID riid, void **ppv); + IShellItemArray *, int, REFIID, void **); /* keyType actually REFPROPERTYKEY */ - HRESULT ( STDMETHODCALLTYPE *GetPropertyDescriptionList )( - IShellItemArray * this, void* keyType, REFIID riid, void **ppv); - HRESULT ( STDMETHODCALLTYPE *GetAttributes )(IShellItemArray * this, - SIATTRIBFLAGS AttribFlags, SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs); + HRESULT ( STDMETHODCALLTYPE *GetPropertyDescriptionList )( + IShellItemArray *, void *, REFIID, void **); + HRESULT ( STDMETHODCALLTYPE *GetAttributes )(IShellItemArray *, + SIATTRIBFLAGS, SFGAOF, SFGAOF *); HRESULT ( STDMETHODCALLTYPE *GetCount )( - IShellItemArray * this, DWORD *pdwNumItems); - HRESULT ( STDMETHODCALLTYPE *GetItemAt )( - IShellItemArray * this, DWORD dwIndex, IShellItem **ppsi); + IShellItemArray *, DWORD *); + HRESULT ( STDMETHODCALLTYPE *GetItemAt )( + IShellItemArray *, DWORD, IShellItem **); /* ppenumShellItems actually (IEnumShellItems **) */ HRESULT ( STDMETHODCALLTYPE *EnumItems )( - IShellItemArray * this, void **ppenumShellItems); - + IShellItemArray *, void **); + END_INTERFACE } IShellItemArrayVtbl; @@ -255,7 +285,7 @@ struct IShellItemArray { #endif /* __IShellItemArray_INTERFACE_DEFINED__ */ -/* +/* * Older compilers do not define these CLSIDs so we do so here under * a slightly different name so as to not clash with the definitions * in new compilers @@ -272,6 +302,9 @@ static const IID IIDIFileOpenDialog = { static const IID IIDIFileSaveDialog = { 0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB} }; +static const IID IIDIShellItem = { + 0x43826D1E, 0xE718, 0x42EE, {0xBC, 0x55, 0xA1, 0xE2, 0x61, 0xC3, 0x7B, 0xFE} +}; #ifdef __IFileDialog_INTERFACE_DEFINED__ # define TCLCOMDLG_FILTERSPEC COMDLG_FILTERSPEC @@ -320,59 +353,59 @@ typedef struct IFileDialog IFileDialog; typedef struct IFileDialogVtbl { BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( - IFileDialog * this, REFIID riid, void **ppvObject); - ULONG ( STDMETHODCALLTYPE *AddRef )( IFileDialog * this); - ULONG ( STDMETHODCALLTYPE *Release )( IFileDialog * this); - HRESULT ( STDMETHODCALLTYPE *Show )( IFileDialog * this, HWND hwndOwner); - HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( IFileDialog * this, - UINT cFileTypes, const TCLCOMDLG_FILTERSPEC *rgFilterSpec); - HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )(IFileDialog * this, UINT); - HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )(IFileDialog * this, UINT *); + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IFileDialog *, REFIID, void **); + ULONG ( STDMETHODCALLTYPE *AddRef )( IFileDialog *); + ULONG ( STDMETHODCALLTYPE *Release )( IFileDialog *); + HRESULT ( STDMETHODCALLTYPE *Show )( IFileDialog *, HWND); + HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( IFileDialog *, + UINT, const TCLCOMDLG_FILTERSPEC *); + HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )(IFileDialog *, UINT); + HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )(IFileDialog *, UINT *); /* XXX - Actually pfde is IFileDialogEvents* but we do not use this call and do not want to define IFileDialogEvents as that pulls in a whole bunch of other stuff. */ - HRESULT ( STDMETHODCALLTYPE *Advise )( - IFileDialog * this, void *pfde, DWORD *pdwCookie); - HRESULT ( STDMETHODCALLTYPE *Unadvise )(IFileDialog * this, DWORD dwCookie); - HRESULT ( STDMETHODCALLTYPE *SetOptions )( - IFileDialog * this, FILEOPENDIALOGOPTIONS fos); - HRESULT ( STDMETHODCALLTYPE *GetOptions )( - IFileDialog * this, FILEOPENDIALOGOPTIONS *pfos); + HRESULT ( STDMETHODCALLTYPE *Advise )( + IFileDialog *, void *, DWORD *); + HRESULT ( STDMETHODCALLTYPE *Unadvise )(IFileDialog *, DWORD); + HRESULT ( STDMETHODCALLTYPE *SetOptions )( + IFileDialog *, FILEOPENDIALOGOPTIONS); + HRESULT ( STDMETHODCALLTYPE *GetOptions )( + IFileDialog *, FILEOPENDIALOGOPTIONS *); HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( - IFileDialog * this, IShellItem *psi); + IFileDialog *, IShellItem *); HRESULT ( STDMETHODCALLTYPE *SetFolder )( - IFileDialog * this, IShellItem *psi); - HRESULT ( STDMETHODCALLTYPE *GetFolder )( - IFileDialog * this, IShellItem **ppsi); - HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( - IFileDialog * this, IShellItem **ppsi); - HRESULT ( STDMETHODCALLTYPE *SetFileName )( - IFileDialog * this, LPCWSTR pszName); - HRESULT ( STDMETHODCALLTYPE *GetFileName )( - IFileDialog * this, LPWSTR *pszName); + IFileDialog *, IShellItem *); + HRESULT ( STDMETHODCALLTYPE *GetFolder )( + IFileDialog *, IShellItem **); + HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( + IFileDialog *, IShellItem **); + HRESULT ( STDMETHODCALLTYPE *SetFileName )( + IFileDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *GetFileName )( + IFileDialog *, LPWSTR *); HRESULT ( STDMETHODCALLTYPE *SetTitle )( - IFileDialog * this, LPCWSTR pszTitle); - HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( - IFileDialog * this, LPCWSTR pszText); - HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( - IFileDialog * this, LPCWSTR pszLabel); + IFileDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( + IFileDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( + IFileDialog *, LPCWSTR); HRESULT ( STDMETHODCALLTYPE *GetResult )( - IFileDialog * this, IShellItem **ppsi); - HRESULT ( STDMETHODCALLTYPE *AddPlace )( - IFileDialog * this, IShellItem *psi, FDAP fdap); - HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( - IFileDialog * this, LPCWSTR pszDefaultExtension); - HRESULT ( STDMETHODCALLTYPE *Close )( IFileDialog * this, HRESULT hr); + IFileDialog *, IShellItem **); + HRESULT ( STDMETHODCALLTYPE *AddPlace )( + IFileDialog *, IShellItem *, FDAP); + HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( + IFileDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *Close )( IFileDialog *, HRESULT); HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( - IFileDialog * this, REFGUID guid); - HRESULT ( STDMETHODCALLTYPE *ClearClientData )( IFileDialog * this); + IFileDialog *, REFGUID); + HRESULT ( STDMETHODCALLTYPE *ClearClientData )( IFileDialog *); /* pFilter actually IShellItemFilter. But deprecated in Win7 AND we do not use it anyways. So define as void* */ - HRESULT ( STDMETHODCALLTYPE *SetFilter )( - IFileDialog * this, void *pFilter); - + HRESULT ( STDMETHODCALLTYPE *SetFilter )( + IFileDialog *, void *); + END_INTERFACE } IFileDialogVtbl; @@ -384,70 +417,69 @@ struct IFileDialog { typedef struct IFileSaveDialog IFileSaveDialog; typedef struct IFileSaveDialogVtbl { BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( - IFileSaveDialog * this, REFIID riid, void **ppvObject); - ULONG ( STDMETHODCALLTYPE *AddRef )( IFileSaveDialog * this); - ULONG ( STDMETHODCALLTYPE *Release )( IFileSaveDialog * this); - HRESULT ( STDMETHODCALLTYPE *Show )( - IFileSaveDialog * this, HWND hwndOwner); + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IFileSaveDialog *, REFIID, void **); + ULONG ( STDMETHODCALLTYPE *AddRef )( IFileSaveDialog *); + ULONG ( STDMETHODCALLTYPE *Release )( IFileSaveDialog *); + HRESULT ( STDMETHODCALLTYPE *Show )( + IFileSaveDialog *, HWND); HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( IFileSaveDialog * this, - UINT cFileTypes, const TCLCOMDLG_FILTERSPEC *rgFilterSpec); + UINT, const TCLCOMDLG_FILTERSPEC *); HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( - IFileSaveDialog * this, UINT iFileType); - HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( - IFileSaveDialog * this, UINT *piFileType); + IFileSaveDialog *, UINT); + HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( + IFileSaveDialog *, UINT *); /* Actually pfde is IFileSaveDialogEvents* */ - HRESULT ( STDMETHODCALLTYPE *Advise )( - IFileSaveDialog * this, void *pfde, DWORD *pdwCookie); - HRESULT ( STDMETHODCALLTYPE *Unadvise )( IFileSaveDialog * this, DWORD); - HRESULT ( STDMETHODCALLTYPE *SetOptions )( - IFileSaveDialog * this, FILEOPENDIALOGOPTIONS fos); - HRESULT ( STDMETHODCALLTYPE *GetOptions )( - IFileSaveDialog * this, FILEOPENDIALOGOPTIONS *pfos); - HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( - IFileSaveDialog * this, IShellItem *psi); + HRESULT ( STDMETHODCALLTYPE *Advise )( + IFileSaveDialog *, void *, DWORD *); + HRESULT ( STDMETHODCALLTYPE *Unadvise )( IFileSaveDialog *, DWORD); + HRESULT ( STDMETHODCALLTYPE *SetOptions )( + IFileSaveDialog *, FILEOPENDIALOGOPTIONS); + HRESULT ( STDMETHODCALLTYPE *GetOptions )( + IFileSaveDialog *, FILEOPENDIALOGOPTIONS *); + HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( + IFileSaveDialog *, IShellItem *); HRESULT ( STDMETHODCALLTYPE *SetFolder )( - IFileSaveDialog * this, IShellItem *psi); - HRESULT ( STDMETHODCALLTYPE *GetFolder )( - IFileSaveDialog * this, IShellItem **ppsi); - HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( - IFileSaveDialog * this, IShellItem **ppsi); - HRESULT ( STDMETHODCALLTYPE *SetFileName )( - IFileSaveDialog * this, LPCWSTR pszName); - HRESULT ( STDMETHODCALLTYPE *GetFileName )( - IFileSaveDialog * this, LPWSTR *pszName); - HRESULT ( STDMETHODCALLTYPE *SetTitle )( - IFileSaveDialog * this, LPCWSTR pszTitle); - HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( - IFileSaveDialog * this, LPCWSTR pszText); - HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( - IFileSaveDialog * this, LPCWSTR pszLabel); - HRESULT ( STDMETHODCALLTYPE *GetResult )( - IFileSaveDialog * this, IShellItem **ppsi); - HRESULT ( STDMETHODCALLTYPE *AddPlace )( - IFileSaveDialog * this, IShellItem *psi, FDAP fdap); - HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( - IFileSaveDialog * this, LPCWSTR pszDefaultExtension); - HRESULT ( STDMETHODCALLTYPE *Close )( IFileSaveDialog * this, HRESULT hr); + IFileSaveDialog *, IShellItem *); + HRESULT ( STDMETHODCALLTYPE *GetFolder )( + IFileSaveDialog *, IShellItem **); + HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( + IFileSaveDialog *, IShellItem **); + HRESULT ( STDMETHODCALLTYPE *SetFileName )( + IFileSaveDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *GetFileName )( + IFileSaveDialog *, LPWSTR *); + HRESULT ( STDMETHODCALLTYPE *SetTitle )( + IFileSaveDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( + IFileSaveDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( + IFileSaveDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *GetResult )( + IFileSaveDialog *, IShellItem **); + HRESULT ( STDMETHODCALLTYPE *AddPlace )( + IFileSaveDialog *, IShellItem *, FDAP); + HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( + IFileSaveDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *Close )( IFileSaveDialog *, HRESULT); HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( - IFileSaveDialog * this, REFGUID guid); - HRESULT ( STDMETHODCALLTYPE *ClearClientData )( IFileSaveDialog * this); + IFileSaveDialog *, REFGUID); + HRESULT ( STDMETHODCALLTYPE *ClearClientData )( IFileSaveDialog *); /* pFilter Actually IShellItemFilter* */ - HRESULT ( STDMETHODCALLTYPE *SetFilter )( - IFileSaveDialog * this, void *pFilter); - HRESULT ( STDMETHODCALLTYPE *SetSaveAsItem )( - IFileSaveDialog * this, IShellItem *psi); - HRESULT ( STDMETHODCALLTYPE *SetProperties )( - IFileSaveDialog * this, IPropertyStore *pStore); - HRESULT ( STDMETHODCALLTYPE *SetCollectedProperties )( - IFileSaveDialog * this, IPropertyDescriptionList *pList, - BOOL fAppendDefault); - HRESULT ( STDMETHODCALLTYPE *GetProperties )( - IFileSaveDialog * this, IPropertyStore **ppStore); - HRESULT ( STDMETHODCALLTYPE *ApplyProperties )( - IFileSaveDialog * this, IShellItem *psi, IPropertyStore *pStore, - HWND hwnd, IFileOperationProgressSink *pSink); + HRESULT ( STDMETHODCALLTYPE *SetFilter )( + IFileSaveDialog *, void *); + HRESULT ( STDMETHODCALLTYPE *SetSaveAsItem )( + IFileSaveDialog *, IShellItem *); + HRESULT ( STDMETHODCALLTYPE *SetProperties )( + IFileSaveDialog *, IPropertyStore *); + HRESULT ( STDMETHODCALLTYPE *SetCollectedProperties )( + IFileSaveDialog *, IPropertyDescriptionList *, BOOL); + HRESULT ( STDMETHODCALLTYPE *GetProperties )( + IFileSaveDialog *, IPropertyStore **); + HRESULT ( STDMETHODCALLTYPE *ApplyProperties )( + IFileSaveDialog *, IShellItem *, IPropertyStore *, + HWND, IFileOperationProgressSink *); END_INTERFACE @@ -460,63 +492,63 @@ struct IFileSaveDialog { typedef struct IFileOpenDialog IFileOpenDialog; typedef struct IFileOpenDialogVtbl { BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE *QueryInterface )( - IFileOpenDialog * this, REFIID riid, void **ppvObject); - ULONG ( STDMETHODCALLTYPE *AddRef )( IFileOpenDialog * this); - ULONG ( STDMETHODCALLTYPE *Release )( IFileOpenDialog * this); - HRESULT ( STDMETHODCALLTYPE *Show )( IFileOpenDialog * this, HWND); - HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( IFileOpenDialog * this, - UINT cFileTypes, const TCLCOMDLG_FILTERSPEC *rgFilterSpec); - HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( - IFileOpenDialog * this, UINT iFileType); - HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( - IFileOpenDialog * this, UINT *piFileType); + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IFileOpenDialog *, REFIID, void **); + ULONG ( STDMETHODCALLTYPE *AddRef )( IFileOpenDialog *); + ULONG ( STDMETHODCALLTYPE *Release )( IFileOpenDialog *); + HRESULT ( STDMETHODCALLTYPE *Show )( IFileOpenDialog *, HWND); + HRESULT ( STDMETHODCALLTYPE *SetFileTypes )( IFileOpenDialog *, + UINT, const TCLCOMDLG_FILTERSPEC *); + HRESULT ( STDMETHODCALLTYPE *SetFileTypeIndex )( + IFileOpenDialog *, UINT); + HRESULT ( STDMETHODCALLTYPE *GetFileTypeIndex )( + IFileOpenDialog *, UINT *); /* Actually pfde is IFileDialogEvents* */ - HRESULT ( STDMETHODCALLTYPE *Advise )( - IFileOpenDialog * this, void *pfde, DWORD *pdwCookie); - HRESULT ( STDMETHODCALLTYPE *Unadvise )( IFileOpenDialog * this, DWORD); - HRESULT ( STDMETHODCALLTYPE *SetOptions )( - IFileOpenDialog * this, FILEOPENDIALOGOPTIONS fos); - HRESULT ( STDMETHODCALLTYPE *GetOptions )( - IFileOpenDialog * this, FILEOPENDIALOGOPTIONS *pfos); - HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( - IFileOpenDialog * this, IShellItem *psi); - HRESULT ( STDMETHODCALLTYPE *SetFolder )( - IFileOpenDialog * this, IShellItem *psi); - HRESULT ( STDMETHODCALLTYPE *GetFolder )( - IFileOpenDialog * this, IShellItem **ppsi); - HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( - IFileOpenDialog * this, IShellItem **ppsi); - HRESULT ( STDMETHODCALLTYPE *SetFileName )( - IFileOpenDialog * this, LPCWSTR pszName); - HRESULT ( STDMETHODCALLTYPE *GetFileName )( - IFileOpenDialog * this, LPWSTR *pszName); - HRESULT ( STDMETHODCALLTYPE *SetTitle )( - IFileOpenDialog * this, LPCWSTR pszTitle); - HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( - IFileOpenDialog * this, LPCWSTR pszText); - HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( - IFileOpenDialog * this, LPCWSTR pszLabel); - HRESULT ( STDMETHODCALLTYPE *GetResult )( - IFileOpenDialog * this, IShellItem **ppsi); - HRESULT ( STDMETHODCALLTYPE *AddPlace )( - IFileOpenDialog * this, IShellItem *psi, FDAP fdap); - HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( - IFileOpenDialog * this, LPCWSTR pszDefaultExtension); - HRESULT ( STDMETHODCALLTYPE *Close )( IFileOpenDialog * this, HRESULT hr); - HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( - IFileOpenDialog * this, REFGUID guid); - HRESULT ( STDMETHODCALLTYPE *ClearClientData )( - IFileOpenDialog * this); - HRESULT ( STDMETHODCALLTYPE *SetFilter )( - IFileOpenDialog * this, + HRESULT ( STDMETHODCALLTYPE *Advise )( + IFileOpenDialog *, void *, DWORD *); + HRESULT ( STDMETHODCALLTYPE *Unadvise )( IFileOpenDialog *, DWORD); + HRESULT ( STDMETHODCALLTYPE *SetOptions )( + IFileOpenDialog *, FILEOPENDIALOGOPTIONS); + HRESULT ( STDMETHODCALLTYPE *GetOptions )( + IFileOpenDialog *, FILEOPENDIALOGOPTIONS *); + HRESULT ( STDMETHODCALLTYPE *SetDefaultFolder )( + IFileOpenDialog *, IShellItem *); + HRESULT ( STDMETHODCALLTYPE *SetFolder )( + IFileOpenDialog *, IShellItem *); + HRESULT ( STDMETHODCALLTYPE *GetFolder )( + IFileOpenDialog *, IShellItem **); + HRESULT ( STDMETHODCALLTYPE *GetCurrentSelection )( + IFileOpenDialog *, IShellItem **); + HRESULT ( STDMETHODCALLTYPE *SetFileName )( + IFileOpenDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *GetFileName )( + IFileOpenDialog *, LPWSTR *); + HRESULT ( STDMETHODCALLTYPE *SetTitle )( + IFileOpenDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *SetOkButtonLabel )( + IFileOpenDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *SetFileNameLabel )( + IFileOpenDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *GetResult )( + IFileOpenDialog *, IShellItem **); + HRESULT ( STDMETHODCALLTYPE *AddPlace )( + IFileOpenDialog *, IShellItem *, FDAP); + HRESULT ( STDMETHODCALLTYPE *SetDefaultExtension )( + IFileOpenDialog *, LPCWSTR); + HRESULT ( STDMETHODCALLTYPE *Close )( IFileOpenDialog *, HRESULT); + HRESULT ( STDMETHODCALLTYPE *SetClientGuid )( + IFileOpenDialog *, REFGUID); + HRESULT ( STDMETHODCALLTYPE *ClearClientData )( + IFileOpenDialog *); + HRESULT ( STDMETHODCALLTYPE *SetFilter )( + IFileOpenDialog *, /* pFilter is actually IShellItemFilter */ - void *pFilter); - HRESULT ( STDMETHODCALLTYPE *GetResults )( - IFileOpenDialog * this, IShellItemArray **ppenum); - HRESULT ( STDMETHODCALLTYPE *GetSelectedItems )( - IFileOpenDialog * this, IShellItemArray **ppsai); + void *); + HRESULT ( STDMETHODCALLTYPE *GetResults )( + IFileOpenDialog *, IShellItemArray **); + HRESULT ( STDMETHODCALLTYPE *GetSelectedItems )( + IFileOpenDialog *, IShellItemArray **); END_INTERFACE } IFileOpenDialogVtbl; @@ -528,13 +560,6 @@ struct IFileOpenDialog #endif /* __IFileDialog_INTERFACE_DEFINED__ */ -/* Define this GUID in any case, even when __IShellItem_INTERFACE_DEFINED__ is - * defined in the headers we might still not have it in the actual uuid.lib, - * this happens with at least VC7 used with its original (i.e. not updated) SDK - * and there is no harm in defining the GUID unconditionally. */ -DEFINE_GUID(IID_IShellItem, - 0x43826D1E, 0xE718, 0x42EE, 0xBC, 0x55, 0xA1, 0xE2, 0x61, 0xC3, 0x7B, 0xFE); - /* * Definitions of functions used only in this file. */ @@ -549,7 +574,7 @@ static int ParseOFNOptions(ClientData clientData, Tcl_Obj *const objv[], enum OFNOper oper, OFNOpts *optsPtr); static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, enum OFNOper oper); -static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, +static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, enum OFNOper oper); static int GetFileName(ClientData clientData, Tcl_Interp *interp, int objc, @@ -600,7 +625,7 @@ struct ShellProcPointers { * unnecessary bookkeeping. * * Return value: - * None. + * None. * * Side effects: * ShellProcs is populated. @@ -1059,8 +1084,8 @@ ParseOFNOptions( case OFN_FILE_SAVE: options = saveOptions; break; case OFN_DIR_CHOOSE: options = dirOptions; break; case OFN_FILE_OPEN: options = openOptions; break; - } - + } + ZeroMemory(optsPtr, sizeof(*optsPtr)); // optsPtr->forceXPStyle = 1; optsPtr->tkwin = clientData; @@ -1163,7 +1188,7 @@ error_return: /* interp should already hold error */ * * Checks whether the new (Vista) file dialogs can be used on * the system. - * + * * Returns: * 1 if new dialogs are available, 0 otherwise * @@ -1203,7 +1228,7 @@ static int VistaFileDialogsAvailable() } } } - } + } } return (tsdPtr->newFileDialogsState == FDLG_STATE_USE_NEW); @@ -1215,7 +1240,7 @@ static int VistaFileDialogsAvailable() * GetFileNameVista -- * * Displays the new file dialogs on Vista and later. - * This function must generally not be called unless the + * This function must generally not be called unless the * tsdPtr->newFileDialogsState is FDLG_STATE_USE_NEW but if * it is, it will just pass the call to the older GetFileNameXP * @@ -1260,7 +1285,7 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, /* * The only validation we need to do w.r.t caller supplied data - * is the filter specification so do that before creating + * is the filter specification so do that before creating */ if (MakeFilterVista(interp, optsPtr, &nfilters, &filterPtr, &defaultFilterIndex) != TCL_OK) @@ -1298,8 +1323,8 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, hr = fdlgIf->lpVtbl->SetFileTypeIndex(fdlgIf, defaultFilterIndex); if (FAILED(hr)) goto vamoose; - } - + } + /* Flags are equivalent to those we used in the older API */ /* @@ -1348,7 +1373,7 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, Tcl_GetUnicode(optsPtr->titleObj)); if (FAILED(hr)) goto vamoose; - } + } if (optsPtr->file[0]) { hr = fdlgIf->lpVtbl->SetFileName(fdlgIf, optsPtr->file); @@ -1362,14 +1387,14 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, Tcl_DStringLength(&optsPtr->utfDirString), &dirString); hr = ShellProcs.SHCreateItemFromParsingName( (TCHAR *) Tcl_DStringValue(&dirString), NULL, - &IID_IShellItem, (void **) &dirIf); + &IIDIShellItem, (void **) &dirIf); /* XXX - Note on failure we do not raise error, simply ignore ini dir */ if (SUCCEEDED(hr)) { /* Note we use SetFolder, not SetDefaultFolder - see MSDN docs */ fdlgIf->lpVtbl->SetFolder(fdlgIf, dirIf); /* Ignore errors */ } Tcl_DStringFree(&dirString); - } + } oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); hr = fdlgIf->lpVtbl->Show(fdlgIf, hWnd); @@ -2198,7 +2223,7 @@ static int MakeFilterVista( const char *sep; FileFilterClause *clausePtr; int nbytes; - + /* Check if this entry should be shown as the default */ if (initial && strcmp(initial, filterPtr->name) == 0) initialIndex = i+1; /* Windows filter indices are 1-based */ @@ -2230,7 +2255,7 @@ static int MakeFilterVista( sep = ";"; } } - + /* Again we need a Unicode form of the string */ Tcl_WinUtfToTChar(Tcl_DStringValue(&patterns), -1, &ds); nbytes = Tcl_DStringLength(&ds); /* # bytes, not Unicode chars */ @@ -2343,7 +2368,7 @@ Tk_ChooseDirectoryObjCmd( OFNOpts ofnOpts; const char *utfDir; - result = ParseOFNOptions(clientData, interp, objc, objv, + result = ParseOFNOptions(clientData, interp, objc, objv, OFN_DIR_CHOOSE, &ofnOpts); if (result != TCL_OK) return result; -- cgit v0.12 From 48becc71dabdff1fee50892a3f25600dd7e7cc08 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Tue, 21 Oct 2014 15:01:13 +0000 Subject: Fix for Mac crash on Yosemite because of changes in version checking --- macosx/tkMacOSXInit.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index 1f70149..aaeb348 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -236,11 +236,16 @@ TkpInit( if (!uname(&name)) { tkMacOSXMacOSXVersion = (strtod(name.release, NULL) + 96) * 10; } - if (tkMacOSXMacOSXVersion && + /*Check for new versioning scheme on Yosemite (10.10) and later.*/ + if (MAC_OS_X_VERSION_MIN_REQUIRED > 100000) { + tkMacOSXMacOSXVersion = MAC_OS_X_VERSION_MIN_REQUIRED/100; + } + if (tkMacOSXMacOSXVersion && MAC_OS_X_VERSION_MIN_REQUIRED < 100000 && tkMacOSXMacOSXVersion/10 < MAC_OS_X_VERSION_MIN_REQUIRED/10) { Tcl_Panic("Mac OS X 10.%d or later required !", (MAC_OS_X_VERSION_MIN_REQUIRED/10)-100); } + #ifdef TK_FRAMEWORK /* -- cgit v0.12 From 2d76a375ccd53835f64269ac5e8d3c950ac2ace9 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sat, 25 Oct 2014 07:00:26 +0000 Subject: Quick-fix compilation on VC6/PSDK (reported by Andreas Kurpies) --- win/tkWinDialog.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 9954a57..c90d05a 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -219,6 +219,7 @@ typedef enum SIATTRIBFLAGS { SIATTRIBFLAGS_MASK = 0x3, SIATTRIBFLAGS_ALLITEMS = 0x4000 } SIATTRIBFLAGS; +#ifdef __MSVCRT__ typedef ULONG SFGAOF; typedef struct IShellItem IShellItem; @@ -249,6 +250,7 @@ typedef struct IShellItemVtbl struct IShellItem { CONST_VTBL struct IShellItemVtbl *lpVtbl; }; +#endif /* __MSVCRT__ */ typedef struct IShellItemArray IShellItemArray; typedef struct IShellItemArrayVtbl { -- cgit v0.12 From 0788f6fc1ac0b467bdc3e53a74ba66de5da2278f Mon Sep 17 00:00:00 2001 From: ashok Date: Tue, 28 Oct 2014 04:00:02 +0000 Subject: Fix winDialog tests to not assume current working directory when -initialdir is not specified --- tests/winDialog.test | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index ad648c0..cd8d937 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -273,10 +273,10 @@ test winDialog-5.7 {GetFileName: extension begins with .} -constraints { Click ok } } - string totitle $x$msg + set x "[file tail $x]$msg" } -cleanup { unset msg -} -result [string totitle [file join [pwd] bar.foo]] +} -result bar.foo test winDialog-5.8 {GetFileName: extension doesn't begin with .} -constraints { nt testwinevent } -body { @@ -289,27 +289,32 @@ test winDialog-5.8 {GetFileName: extension doesn't begin with .} -constraints { Click ok } } - string totitle $x$msg + set x "[file tail $x]$msg" } -cleanup { unset msg -} -result [string totitle [file join [pwd] bar.foo]] -if {![vista?]} { +} -result bar.foo +test winDialog-5.9 {GetFileName: file types} -constraints { + nt testwinevent +} -body { + # case FILE_TYPES: + + start {tk_getSaveFile -filetypes {{"foo files" .foo FOOF}} -title Foo} # XXX - currently disabled for vista style dialogs because the file # types control has no control ID and we don't have a mechanism to # locate it. - test winDialog-5.9 {GetFileName: file types} -constraints { - nt testwinevent - } -body { - # case FILE_TYPES: - - start {tk_getSaveFile -filetypes {{"foo files" .foo FOOF}} -title Foo} + if {[vista?]} { + then { + Click cancel + } + return 1 + } else { then { set x [GetText 0x470] Click cancel } - return $x - } -result {foo files (*.foo)} -} + return [string equal $x {foo files (*.foo)}] + } +} -result 1 test winDialog-5.10 {GetFileName: file types: MakeFilter() fails} -constraints { nt } -body { @@ -346,8 +351,8 @@ test winDialog-5.13 {GetFileName: initial file} -constraints { then { Click ok } - string totitle $x -} -result [string totitle [file join [pwd] "12x 456"]] + file tail $x +} -result "12x 456" test winDialog-5.14 {GetFileName: initial file: Tcl_TranslateFileName()} -constraints { nt } -body { -- cgit v0.12 From 2de899be4f282336d57ace6810563233c87b13d6 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Tue, 28 Oct 2014 14:40:24 +0000 Subject: Fix for different ttk notebook tab metrics on OS X/Yosemite --- macosx/ttkMacOSXTheme.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c index 5752fb1..a4abc7b 100644 --- a/macosx/ttkMacOSXTheme.c +++ b/macosx/ttkMacOSXTheme.c @@ -294,14 +294,22 @@ static Ttk_StateTable TabPositionTable[] = { * TP30000359-TPXREF116> */ -static const int TAB_HEIGHT = 10; -static const int TAB_OVERLAP = 10; + +int TAB_HEIGHT = 0; +int TAB_OVERLAP = 0; static void TabElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { - *heightPtr = TAB_HEIGHT + TAB_OVERLAP - 1; + TAB_HEIGHT = 10; + TAB_OVERLAP = 10; + /*Different metrics on 10.10/Yosemite.*/ + if (MAC_OS_X_VERSION_MIN_REQUIRED > 100000) { + TAB_OVERLAP = 5; + } + *heightPtr = TAB_HEIGHT + TAB_OVERLAP - 1; + } static void TabElementDraw( -- cgit v0.12 From 25c055f637319725f6db0674486c554ca609a112 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 7 Nov 2014 18:23:39 +0000 Subject: update changes --- changes | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/changes b/changes index 5d2997c..a6373fd 100644 --- a/changes +++ b/changes @@ -7136,4 +7136,12 @@ Many revisions to better support a Cygwin environment (nijtmans) 2014-10-18 (feature)[TIP 432] Win: updated file dialogs (nadkarni) ---- Released 8.6.3, October 25, 2014 --- http://core.tcl.tk/tk/ for details +2014-10-26 Support for Windows 10 (nijtmans) + +2014-10-28 (bug) OSX: Improved ttk notebook tab metrics for Yosemite (walzer) + +2014-10-30 (bug)[3417012] [scale -digits $bigValue] segfault (vogel) + +2014-11-07 (bug)[3529885] [scale] handling of negative resolution (vogel) + +--- Released 8.6.3, November 12, 2014 --- http://core.tcl.tk/tk/ for details -- cgit v0.12 From bc93dcbe231e55cda2878308ddecf7df15c20cf6 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 7 Nov 2014 19:04:10 +0000 Subject: update README --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index ec84200..04034fb 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ README: Tk - This is the Tk 8.6.2 source distribution. + This is the Tk 8.6.3 source distribution. http://sourceforge.net/projects/tcl/files/Tcl/ You can get any source release of Tk from the URL above. -- cgit v0.12 From 387810da124d6770e1928f7b0dc8c3a09ed74f8f Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 13 Nov 2014 13:51:01 +0000 Subject: Fix [d43a10ce2fed950e00890049f3c273f2cdd12583|d43a10ce2f]: tk_getOpenFile crashes when passed a bad -typevariable. --- win/tkWinDialog.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index c90d05a..69dcb06 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -1009,10 +1009,28 @@ Tk_GetSaveFileObjCmd( */ static void CleanupOFNOptions(OFNOpts *optsPtr) { + if (optsPtr->extObj) { + Tcl_DecrRefCount(optsPtr->extObj); + optsPtr->extObj = NULL; + } + if (optsPtr->titleObj) { + Tcl_DecrRefCount(optsPtr->titleObj); + optsPtr->titleObj = NULL; + } + if (optsPtr->filterObj) { + Tcl_DecrRefCount(optsPtr->filterObj); + optsPtr->filterObj = NULL; + } + if (optsPtr->typeVariableObj) { + Tcl_DecrRefCount(optsPtr->typeVariableObj); + optsPtr->typeVariableObj = NULL; + } + if (optsPtr->initialTypeObj) { + Tcl_DecrRefCount(optsPtr->initialTypeObj); + optsPtr->initialTypeObj = NULL; + } Tcl_DStringFree(&optsPtr->utfDirString); } - - /* *---------------------------------------------------------------------- @@ -1124,9 +1142,21 @@ ParseOFNOptions( string = Tcl_GetString(valuePtr); switch (options[index].value) { case FILE_DEFAULT: + if (valuePtr) { + Tcl_IncrRefCount(valuePtr); + } + if (optsPtr->extObj) { + Tcl_DecrRefCount(optsPtr->extObj); + } optsPtr->extObj = valuePtr; break; case FILE_TYPES: + if (valuePtr) { + Tcl_IncrRefCount(valuePtr); + } + if (optsPtr->filterObj) { + Tcl_DecrRefCount(optsPtr->filterObj); + } optsPtr->filterObj = valuePtr; break; case FILE_INITDIR: @@ -1150,12 +1180,30 @@ ParseOFNOptions( goto error_return; break; case FILE_TITLE: + if (valuePtr) { + Tcl_IncrRefCount(valuePtr); + } + if (optsPtr->titleObj) { + Tcl_DecrRefCount(optsPtr->titleObj); + } optsPtr->titleObj = valuePtr; break; case FILE_TYPEVARIABLE: + if (valuePtr) { + Tcl_IncrRefCount(valuePtr); + } + if (optsPtr->typeVariableObj) { + Tcl_DecrRefCount(optsPtr->typeVariableObj); + } optsPtr->typeVariableObj = valuePtr; + if (optsPtr->initialTypeObj) { + Tcl_DecrRefCount(optsPtr->initialTypeObj); + } optsPtr->initialTypeObj = Tcl_ObjGetVar2(interp, valuePtr, NULL, TCL_GLOBAL_ONLY); + if (optsPtr->initialTypeObj) { + Tcl_IncrRefCount(optsPtr->initialTypeObj); + } break; case FILE_MULTIPLE: if (Tcl_GetBooleanFromObj(interp, valuePtr, -- cgit v0.12 From 1529354d816acf50736e152a156118c7335c6b17 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 13 Nov 2014 20:16:54 +0000 Subject: Backout last change, it doesn't solve the issue --- win/tkWinDialog.c | 52 ++-------------------------------------------------- 1 file changed, 2 insertions(+), 50 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 69dcb06..c90d05a 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -1009,28 +1009,10 @@ Tk_GetSaveFileObjCmd( */ static void CleanupOFNOptions(OFNOpts *optsPtr) { - if (optsPtr->extObj) { - Tcl_DecrRefCount(optsPtr->extObj); - optsPtr->extObj = NULL; - } - if (optsPtr->titleObj) { - Tcl_DecrRefCount(optsPtr->titleObj); - optsPtr->titleObj = NULL; - } - if (optsPtr->filterObj) { - Tcl_DecrRefCount(optsPtr->filterObj); - optsPtr->filterObj = NULL; - } - if (optsPtr->typeVariableObj) { - Tcl_DecrRefCount(optsPtr->typeVariableObj); - optsPtr->typeVariableObj = NULL; - } - if (optsPtr->initialTypeObj) { - Tcl_DecrRefCount(optsPtr->initialTypeObj); - optsPtr->initialTypeObj = NULL; - } Tcl_DStringFree(&optsPtr->utfDirString); } + + /* *---------------------------------------------------------------------- @@ -1142,21 +1124,9 @@ ParseOFNOptions( string = Tcl_GetString(valuePtr); switch (options[index].value) { case FILE_DEFAULT: - if (valuePtr) { - Tcl_IncrRefCount(valuePtr); - } - if (optsPtr->extObj) { - Tcl_DecrRefCount(optsPtr->extObj); - } optsPtr->extObj = valuePtr; break; case FILE_TYPES: - if (valuePtr) { - Tcl_IncrRefCount(valuePtr); - } - if (optsPtr->filterObj) { - Tcl_DecrRefCount(optsPtr->filterObj); - } optsPtr->filterObj = valuePtr; break; case FILE_INITDIR: @@ -1180,30 +1150,12 @@ ParseOFNOptions( goto error_return; break; case FILE_TITLE: - if (valuePtr) { - Tcl_IncrRefCount(valuePtr); - } - if (optsPtr->titleObj) { - Tcl_DecrRefCount(optsPtr->titleObj); - } optsPtr->titleObj = valuePtr; break; case FILE_TYPEVARIABLE: - if (valuePtr) { - Tcl_IncrRefCount(valuePtr); - } - if (optsPtr->typeVariableObj) { - Tcl_DecrRefCount(optsPtr->typeVariableObj); - } optsPtr->typeVariableObj = valuePtr; - if (optsPtr->initialTypeObj) { - Tcl_DecrRefCount(optsPtr->initialTypeObj); - } optsPtr->initialTypeObj = Tcl_ObjGetVar2(interp, valuePtr, NULL, TCL_GLOBAL_ONLY); - if (optsPtr->initialTypeObj) { - Tcl_IncrRefCount(optsPtr->initialTypeObj); - } break; case FILE_MULTIPLE: if (Tcl_GetBooleanFromObj(interp, valuePtr, -- cgit v0.12 From 47855ace43a7f946266bfc62a9cb919d478c9580 Mon Sep 17 00:00:00 2001 From: ashok Date: Fri, 14 Nov 2014 04:15:10 +0000 Subject: Fix [d43a10ce2fed950e00890049f3c273f2cdd12583|d43a10ce2f]: tk_getOpenFile crashes when passed a bad -typevariable. Crash was caused by access to a list element after the Tcl_Obj was shimmered to a variable intrep. --- win/tkWinDialog.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index c90d05a..37e4dfb 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -1739,9 +1739,24 @@ static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, enum OFNOper oper listObjv[ofn.nFilterIndex - 1], &count, &typeInfo) != TCL_OK) { result = TCL_ERROR; - } else if (Tcl_ObjSetVar2(interp, optsPtr->typeVariableObj, NULL, - typeInfo[0], TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; + } else { + /* + * BUGFIX for d43a10ce2fed950e00890049f3c273f2cdd12583 + * The original code was broken because it passed typeinfo[0] + * directly into Tcl_ObjSetVar2. In the case of typeInfo[0] + * pointing into a list which is also referenced by + * typeVariableObj, TOSV2 shimmers the object into + * variable intrep which loses the list representation. + * This invalidates typeInfo[0] which is freed but + * nevertheless stored as the value of the variable. + */ + Tcl_Obj *selFilterObj = typeInfo[0]; + Tcl_IncrRefCount(selFilterObj); + if (Tcl_ObjSetVar2(interp, optsPtr->typeVariableObj, NULL, + selFilterObj, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { + result = TCL_ERROR; + } + Tcl_DecrRefCount(selFilterObj); } } } else if (cdlgerr == FNERR_INVALIDFILENAME) { -- cgit v0.12 From 0e22d8ae3dcf3f15ae9df9bab55581868f8dbf5a Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Tue, 18 Nov 2014 14:46:46 +0000 Subject: Remove residual private API calls from Tk/Mac after Mac App Store review flagged them as being present. --- macosx/tkMacOSXDialog.c | 62 ++++++++++++++++++++++++++++++++++++++++++-- macosx/tkMacOSXEmbed.c | 21 ++++++++------- macosx/tkMacOSXInit.c | 8 +++--- macosx/tkMacOSXPrivate.h | 1 + macosx/tkMacOSXScrlbr.c | 8 ++++-- macosx/tkMacOSXWindowEvent.c | 6 ++++- 6 files changed, 86 insertions(+), 20 deletions(-) diff --git a/macosx/tkMacOSXDialog.c b/macosx/tkMacOSXDialog.c index a66939a..ea456a6 100644 --- a/macosx/tkMacOSXDialog.c +++ b/macosx/tkMacOSXDialog.c @@ -24,12 +24,12 @@ enum colorOptions { static const char *const openOptionStrings[] = { "-defaultextension", "-filetypes", "-initialdir", "-initialfile", "-message", "-multiple", "-parent", "-title", "-typevariable", - "-command", NULL + "-command", "-allbutton", "-allbuttontip", NULL }; enum openOptions { OPEN_DEFAULT, OPEN_FILETYPES, OPEN_INITDIR, OPEN_INITFILE, OPEN_MESSAGE, OPEN_MULTIPLE, OPEN_PARENT, OPEN_TITLE, - OPEN_TYPEVARIABLE, OPEN_COMMAND, + OPEN_TYPEVARIABLE, OPEN_COMMAND, OPEN_ALLBUTTON, OPEN_ALLBUTTONTIP }; static const char *const saveOptionStrings[] = { "-defaultextension", "-filetypes", "-initialdir", "-initialfile", @@ -221,6 +221,35 @@ static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = { } @end + @interface TKOpenDialog : NSControl + @property(assign) NSOpenPanel *openPanel; + @property(assign) NSMutableArray *openFileTypes; + - (void)openUnrecognizedFiles:(id)sender; + @end + + @implementation TKOpenDialog + - (id)init { + self = [super init]; + if (self) { + _openPanel = nil; + _openFileTypes = nil; + } + return self; + } + + - (void)openUnrecognizedFiles:(id)sender + { + if ([sender state]) { + self.openPanel.allowedFileTypes = [NSArray arrayWithObjects:@"public.data", nil]; + } else { + self.openPanel.allowedFileTypes = self.openFileTypes; + } + [self.openPanel setDirectoryURL:self.openPanel.directoryURL]; + [self.openPanel validateVisibleColumns]; + } + + @end + #pragma mark - /* @@ -366,11 +395,14 @@ Tk_GetOpenFileObjCmd( FilePanelCallbackInfo *callbackInfo = &callbackInfoStruct; NSString *directory = nil, *filename = nil; NSString *message, *title, *type; + NSString *allbutton, *allbuttontip; NSWindow *parent; NSMutableArray *fileTypes = nil; NSOpenPanel *panel = [NSOpenPanel openPanel]; NSInteger returnCode = NSAlertErrorReturn; + allbutton = nil; + allbuttontip = nil; TkInitFileFilters(&fl); for (i = 1; i < objc; i += 2) { if (Tcl_GetIndexFromObjStruct(interp, objv[i], openOptionStrings, @@ -437,6 +469,14 @@ Tk_GetOpenFileObjCmd( case OPEN_COMMAND: cmdObj = objv[i+1]; break; + case OPEN_ALLBUTTON: + allbutton = [[NSString alloc] initWithUTF8String: + Tcl_GetString(objv[i + 1])]; + break; + case OPEN_ALLBUTTONTIP: + allbuttontip = [[NSString alloc] initWithUTF8String: + Tcl_GetString(objv[i + 1])]; + break; } } if (fl.filters) { @@ -472,6 +512,24 @@ Tk_GetOpenFileObjCmd( } } [panel setAllowsMultipleSelection:multiple]; + + if (allbutton) { + TKOpenDialog *tkDialog = [TKOpenDialog alloc]; + tkDialog.openPanel = panel; + tkDialog.openFileTypes = fileTypes; + + NSButton *openPanelAccessoryView = [[[NSButton alloc] initWithFrame:NSMakeRect(0.0, 0.0, 224.0, 22.0)] autorelease]; + if (allbuttontip) { + [openPanelAccessoryView setToolTip:allbuttontip]; + } + [openPanelAccessoryView setButtonType:NSSwitchButton]; + [openPanelAccessoryView setBezelStyle:0]; + [openPanelAccessoryView setTitle:allbutton]; + [openPanelAccessoryView setAction:@selector(openUnrecognizedFiles:)]; + [openPanelAccessoryView setTarget:tkDialog]; + [panel setAccessoryView:openPanelAccessoryView]; + } + if (cmdObj) { callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo)); if (Tcl_IsShared(cmdObj)) { diff --git a/macosx/tkMacOSXEmbed.c b/macosx/tkMacOSXEmbed.c index 1d66b82..f9700f6 100644 --- a/macosx/tkMacOSXEmbed.c +++ b/macosx/tkMacOSXEmbed.c @@ -207,6 +207,7 @@ TkpUseWindow( MacDrawable *parent, *macWin; Container *containerPtr; + if (winPtr->window != None) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "can't modify container after widget is created", -1)); @@ -247,14 +248,14 @@ TkpUseWindow( * Container structure, since we only allow the case where both container * and embedded app. are in the same process. */ - + for (containerPtr = firstContainerPtr; containerPtr != NULL; - containerPtr = containerPtr->nextPtr) { - if (containerPtr->parent == (Window) parent) { - winPtr->flags |= TK_BOTH_HALVES; - containerPtr->parentPtr->flags |= TK_BOTH_HALVES; - break; - } + containerPtr = containerPtr->nextPtr) { + if (containerPtr->parent == (Window) parent) { + winPtr->flags |= TK_BOTH_HALVES; + containerPtr->parentPtr->flags |= TK_BOTH_HALVES; + break; + } } /* @@ -313,9 +314,10 @@ TkpUseWindow( if (tkMacOSXEmbedHandler == NULL || tkMacOSXEmbedHandler->registerWinProc((long) parent, (Tk_Window) winPtr) != TCL_OK) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "The window ID %s does not correspond to a valid Tk Window", - string)); + "The window ID %s does not correspond to a valid Tk Window", + string)); Tcl_SetErrorCode(interp, "TK", "EMBED", "HANDLE", NULL); return TCL_ERROR; } @@ -391,7 +393,6 @@ TkpMakeContainer( * sure the argument to -use is valid. */ - Tk_MakeWindowExist(tkwin); containerPtr = ckalloc(sizeof(Container)); containerPtr->parent = Tk_WindowId(tkwin); containerPtr->parentPtr = winPtr; diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index aaeb348..00df93e 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -91,11 +91,9 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt - (void) _setupEventLoop { - _running = 1; - if (!_appFlags._hasBeenRun) { - _appFlags._hasBeenRun = YES; - [self finishLaunching]; - } + + /*Remove private API flags here.*/ + [self finishLaunching]; [self setWindowsNeedUpdate:YES]; } diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index adc7106..599317d 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -326,6 +326,7 @@ VISIBILITY_HIDDEN BOOL _subviewsSetAside; #endif NSString *privateWorkingText; + BOOL _in_event; } @end diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index ebb99f3..00f6088 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -50,11 +50,15 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); /* Do not draw if the widget is misplaced or unmapped. */ if ( NSIsEmptyRect(Tkframe) || - ! macWin->winPtr->flags & TK_MAPPED || - ! NSEqualRects(Tkframe, [self frame]) + ! (macWin->winPtr->flags & TK_MAPPED) ) { return; } + for (Tk_Window parent_win = tkwin; parent_win != NULL;parent_win = Tk_Parent(parent_win)) { + if (!Tk_IsMapped(parent_win)) { + return; + } + } /* * Do not draw if the widget is completely outside of its parent. diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index d016790..361b2e2 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -831,7 +831,11 @@ ExposeRestrictProc( HIShapeUnionWithRect(drawShape, &r); } if (CFRunLoopGetMain() == CFRunLoopGetCurrent()) { - [self generateExposeEvents:drawShape]; + if (!_in_event) { + _in_event = true; + [self generateExposeEvents:drawShape]; + _in_event = false; + } } else { [self performSelectorOnMainThread:@selector(generateExposeEvents:) withObject:(id)drawShape waitUntilDone:NO -- cgit v0.12 From 02b543ede36c5f387093c576a915c0788628bedb Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 20 Nov 2014 02:34:09 +0000 Subject: Back out changes not pertaining to private API; those files should not have been updated. --- macosx/tkMacOSXDialog.c | 64 +++----------------------------------------- macosx/tkMacOSXEmbed.c | 23 ++++++++-------- macosx/tkMacOSXPrivate.h | 3 +-- macosx/tkMacOSXScrlbr.c | 10 +++---- macosx/tkMacOSXWindowEvent.c | 8 ++---- 5 files changed, 20 insertions(+), 88 deletions(-) diff --git a/macosx/tkMacOSXDialog.c b/macosx/tkMacOSXDialog.c index ea456a6..2f77203 100644 --- a/macosx/tkMacOSXDialog.c +++ b/macosx/tkMacOSXDialog.c @@ -1,4 +1,4 @@ -/* +/* * tkMacOSXDialog.c -- * * Contains the Mac implementation of the common dialog boxes. @@ -24,12 +24,12 @@ enum colorOptions { static const char *const openOptionStrings[] = { "-defaultextension", "-filetypes", "-initialdir", "-initialfile", "-message", "-multiple", "-parent", "-title", "-typevariable", - "-command", "-allbutton", "-allbuttontip", NULL + "-command", NULL }; enum openOptions { OPEN_DEFAULT, OPEN_FILETYPES, OPEN_INITDIR, OPEN_INITFILE, OPEN_MESSAGE, OPEN_MULTIPLE, OPEN_PARENT, OPEN_TITLE, - OPEN_TYPEVARIABLE, OPEN_COMMAND, OPEN_ALLBUTTON, OPEN_ALLBUTTONTIP + OPEN_TYPEVARIABLE, OPEN_COMMAND, }; static const char *const saveOptionStrings[] = { "-defaultextension", "-filetypes", "-initialdir", "-initialfile", @@ -221,35 +221,6 @@ static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = { } @end - @interface TKOpenDialog : NSControl - @property(assign) NSOpenPanel *openPanel; - @property(assign) NSMutableArray *openFileTypes; - - (void)openUnrecognizedFiles:(id)sender; - @end - - @implementation TKOpenDialog - - (id)init { - self = [super init]; - if (self) { - _openPanel = nil; - _openFileTypes = nil; - } - return self; - } - - - (void)openUnrecognizedFiles:(id)sender - { - if ([sender state]) { - self.openPanel.allowedFileTypes = [NSArray arrayWithObjects:@"public.data", nil]; - } else { - self.openPanel.allowedFileTypes = self.openFileTypes; - } - [self.openPanel setDirectoryURL:self.openPanel.directoryURL]; - [self.openPanel validateVisibleColumns]; - } - - @end - #pragma mark - /* @@ -395,14 +366,11 @@ Tk_GetOpenFileObjCmd( FilePanelCallbackInfo *callbackInfo = &callbackInfoStruct; NSString *directory = nil, *filename = nil; NSString *message, *title, *type; - NSString *allbutton, *allbuttontip; NSWindow *parent; NSMutableArray *fileTypes = nil; NSOpenPanel *panel = [NSOpenPanel openPanel]; NSInteger returnCode = NSAlertErrorReturn; - allbutton = nil; - allbuttontip = nil; TkInitFileFilters(&fl); for (i = 1; i < objc; i += 2) { if (Tcl_GetIndexFromObjStruct(interp, objv[i], openOptionStrings, @@ -469,14 +437,6 @@ Tk_GetOpenFileObjCmd( case OPEN_COMMAND: cmdObj = objv[i+1]; break; - case OPEN_ALLBUTTON: - allbutton = [[NSString alloc] initWithUTF8String: - Tcl_GetString(objv[i + 1])]; - break; - case OPEN_ALLBUTTONTIP: - allbuttontip = [[NSString alloc] initWithUTF8String: - Tcl_GetString(objv[i + 1])]; - break; } } if (fl.filters) { @@ -512,24 +472,6 @@ Tk_GetOpenFileObjCmd( } } [panel setAllowsMultipleSelection:multiple]; - - if (allbutton) { - TKOpenDialog *tkDialog = [TKOpenDialog alloc]; - tkDialog.openPanel = panel; - tkDialog.openFileTypes = fileTypes; - - NSButton *openPanelAccessoryView = [[[NSButton alloc] initWithFrame:NSMakeRect(0.0, 0.0, 224.0, 22.0)] autorelease]; - if (allbuttontip) { - [openPanelAccessoryView setToolTip:allbuttontip]; - } - [openPanelAccessoryView setButtonType:NSSwitchButton]; - [openPanelAccessoryView setBezelStyle:0]; - [openPanelAccessoryView setTitle:allbutton]; - [openPanelAccessoryView setAction:@selector(openUnrecognizedFiles:)]; - [openPanelAccessoryView setTarget:tkDialog]; - [panel setAccessoryView:openPanelAccessoryView]; - } - if (cmdObj) { callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo)); if (Tcl_IsShared(cmdObj)) { diff --git a/macosx/tkMacOSXEmbed.c b/macosx/tkMacOSXEmbed.c index f9700f6..41a1e1b 100644 --- a/macosx/tkMacOSXEmbed.c +++ b/macosx/tkMacOSXEmbed.c @@ -14,7 +14,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ - + #include "tkMacOSXPrivate.h" #include "tkBusy.h" @@ -207,7 +207,6 @@ TkpUseWindow( MacDrawable *parent, *macWin; Container *containerPtr; - if (winPtr->window != None) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "can't modify container after widget is created", -1)); @@ -248,14 +247,14 @@ TkpUseWindow( * Container structure, since we only allow the case where both container * and embedded app. are in the same process. */ - + for (containerPtr = firstContainerPtr; containerPtr != NULL; - containerPtr = containerPtr->nextPtr) { - if (containerPtr->parent == (Window) parent) { - winPtr->flags |= TK_BOTH_HALVES; - containerPtr->parentPtr->flags |= TK_BOTH_HALVES; - break; - } + containerPtr = containerPtr->nextPtr) { + if (containerPtr->parent == (Window) parent) { + winPtr->flags |= TK_BOTH_HALVES; + containerPtr->parentPtr->flags |= TK_BOTH_HALVES; + break; + } } /* @@ -314,10 +313,9 @@ TkpUseWindow( if (tkMacOSXEmbedHandler == NULL || tkMacOSXEmbedHandler->registerWinProc((long) parent, (Tk_Window) winPtr) != TCL_OK) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "The window ID %s does not correspond to a valid Tk Window", - string)); + "The window ID %s does not correspond to a valid Tk Window", + string)); Tcl_SetErrorCode(interp, "TK", "EMBED", "HANDLE", NULL); return TCL_ERROR; } @@ -393,6 +391,7 @@ TkpMakeContainer( * sure the argument to -use is valid. */ + Tk_MakeWindowExist(tkwin); containerPtr = ckalloc(sizeof(Container)); containerPtr->parent = Tk_WindowId(tkwin); containerPtr->parentPtr = winPtr; diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 599317d..1aee7f4 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -1,5 +1,5 @@ /* - * tkMacOSXPrivate.h -- + * tkMacOSXPrivate.h -- * * Macros and declarations that are purely internal & private to TkAqua. * @@ -326,7 +326,6 @@ VISIBILITY_HIDDEN BOOL _subviewsSetAside; #endif NSString *privateWorkingText; - BOOL _in_event; } @end diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index 00f6088..f9a2f5f 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -1,5 +1,5 @@ /* - * tkMacOSXScrollbar.c -- + * tkMacOSXScrollbar.c -- * * This file implements the Macintosh specific portion of the scrollbar * widget. @@ -50,15 +50,11 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); /* Do not draw if the widget is misplaced or unmapped. */ if ( NSIsEmptyRect(Tkframe) || - ! (macWin->winPtr->flags & TK_MAPPED) + ! macWin->winPtr->flags & TK_MAPPED || + ! NSEqualRects(Tkframe, [self frame]) ) { return; } - for (Tk_Window parent_win = tkwin; parent_win != NULL;parent_win = Tk_Parent(parent_win)) { - if (!Tk_IsMapped(parent_win)) { - return; - } - } /* * Do not draw if the widget is completely outside of its parent. diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 361b2e2..b257caa 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ - + #include "tkMacOSXPrivate.h" #include "tkMacOSXWm.h" #include "tkMacOSXEvent.h" @@ -831,11 +831,7 @@ ExposeRestrictProc( HIShapeUnionWithRect(drawShape, &r); } if (CFRunLoopGetMain() == CFRunLoopGetCurrent()) { - if (!_in_event) { - _in_event = true; - [self generateExposeEvents:drawShape]; - _in_event = false; - } + [self generateExposeEvents:drawShape]; } else { [self performSelectorOnMainThread:@selector(generateExposeEvents:) withObject:(id)drawShape waitUntilDone:NO -- cgit v0.12 From d7b68b575526b5f5e9d0a4e1b1b196bf70616154 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 21 Nov 2014 16:01:53 +0000 Subject: Fix [1c0d6e162c8876fd1bc0526c7cc59c320853d23|1c0d6e162c]: tkWinDialog.c defines type "SIGDN" (enum __MIDL_IShellItem_0001), which is already defined --- win/tkWinDialog.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 37e4dfb..adb5e9e 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -209,19 +209,9 @@ enum OFNOper { * older compilers? Should we prefix definitions with Tcl_ instead * of using the same names as in the SDK? */ -#ifndef __IShellItemArray_INTERFACE_DEFINED__ -#define __IShellItemArray_INTERFACE_DEFINED__ - -typedef enum SIATTRIBFLAGS { - SIATTRIBFLAGS_AND = 0x1, - SIATTRIBFLAGS_OR = 0x2, - SIATTRIBFLAGS_APPCOMPAT = 0x3, - SIATTRIBFLAGS_MASK = 0x3, - SIATTRIBFLAGS_ALLITEMS = 0x4000 -} SIATTRIBFLAGS; +#ifndef __IShellItem_INTERFACE_DEFINED__ +# define __IShellItem_INTERFACE_DEFINED__ #ifdef __MSVCRT__ -typedef ULONG SFGAOF; - typedef struct IShellItem IShellItem; typedef enum __MIDL_IShellItem_0001 { @@ -250,6 +240,21 @@ typedef struct IShellItemVtbl struct IShellItem { CONST_VTBL struct IShellItemVtbl *lpVtbl; }; +#endif +#endif + +#ifndef __IShellItemArray_INTERFACE_DEFINED__ +#define __IShellItemArray_INTERFACE_DEFINED__ + +typedef enum SIATTRIBFLAGS { + SIATTRIBFLAGS_AND = 0x1, + SIATTRIBFLAGS_OR = 0x2, + SIATTRIBFLAGS_APPCOMPAT = 0x3, + SIATTRIBFLAGS_MASK = 0x3, + SIATTRIBFLAGS_ALLITEMS = 0x4000 +} SIATTRIBFLAGS; +#ifdef __MSVCRT__ +typedef ULONG SFGAOF; #endif /* __MSVCRT__ */ typedef struct IShellItemArray IShellItemArray; typedef struct IShellItemArrayVtbl @@ -1744,11 +1749,11 @@ static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, enum OFNOper oper * BUGFIX for d43a10ce2fed950e00890049f3c273f2cdd12583 * The original code was broken because it passed typeinfo[0] * directly into Tcl_ObjSetVar2. In the case of typeInfo[0] - * pointing into a list which is also referenced by + * pointing into a list which is also referenced by * typeVariableObj, TOSV2 shimmers the object into * variable intrep which loses the list representation. * This invalidates typeInfo[0] which is freed but - * nevertheless stored as the value of the variable. + * nevertheless stored as the value of the variable. */ Tcl_Obj *selFilterObj = typeInfo[0]; Tcl_IncrRefCount(selFilterObj); -- cgit v0.12 From b04a66064750406884bc65f57f4a4e8b63f69930 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 21 Nov 2014 16:15:40 +0000 Subject: Remove unnecessary end-of-line spacing --- ChangeLog | 2 +- generic/tkEvent.c | 2 +- generic/tkFont.c | 2 +- generic/tkTextBTree.c | 2 +- generic/tkUndo.c | 2 +- macosx/tkMacOSXButton.c | 6 +++--- macosx/tkMacOSXDialog.c | 2 +- macosx/tkMacOSXDraw.c | 28 ++++++++++++++-------------- macosx/tkMacOSXEmbed.c | 2 +- macosx/tkMacOSXInit.c | 2 +- macosx/tkMacOSXMenu.c | 4 ++-- macosx/tkMacOSXPrivate.h | 2 +- macosx/tkMacOSXScrlbr.c | 6 +++--- macosx/tkMacOSXWindowEvent.c | 14 +++++++------- win/tkWinTest.c | 2 +- 15 files changed, 39 insertions(+), 39 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7eb5433..0527b19 100644 --- a/ChangeLog +++ b/ChangeLog @@ -33,7 +33,7 @@ a better first place to look now. * library/ttk/progress.tcl: Bug [c597acdab3]: Call [$pb step] in tail position in ttk::progressbar::Autoincrement, so that the widget is in a consistent state when any write traces on - the linked -variable are fired. + the linked -variable are fired. 2013-08-14 Jan Nijtmans diff --git a/generic/tkEvent.c b/generic/tkEvent.c index 51eca3a..bcc6d98 100644 --- a/generic/tkEvent.c +++ b/generic/tkEvent.c @@ -356,7 +356,7 @@ CreateXIC( /* XCreateIC failed. */ return; } - + /* * Adjust the window's event mask if the IM requires it. */ diff --git a/generic/tkFont.c b/generic/tkFont.c index a955c35..4211d99 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -633,7 +633,7 @@ Tk_FontObjCmd( return result; } return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr); - } + } case FONT_CREATE: { int skip = 3, i; const char *name; diff --git a/generic/tkTextBTree.c b/generic/tkTextBTree.c index e34dae7..a06d7e9 100644 --- a/generic/tkTextBTree.c +++ b/generic/tkTextBTree.c @@ -1989,7 +1989,7 @@ TkBTreeLinesTo( } } if (textPtr != NULL) { - /* + /* * The index to return must be relative to textPtr, not to the entire * tree. Take care to never return a negative index when linePtr * denotes a line before -startline, or an index larger than the diff --git a/generic/tkUndo.c b/generic/tkUndo.c index a642e72..8359e0a 100644 --- a/generic/tkUndo.c +++ b/generic/tkUndo.c @@ -392,7 +392,7 @@ TkUndoSetDepth( prevelem = elem; elem = elem->next; } - CLANG_ASSERT(prevelem); + CLANG_ASSERT(prevelem); prevelem->next = NULL; while (elem != NULL) { prevelem = elem; diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index d4aae8d..720e40d 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -52,9 +52,9 @@ static NSRect TkMacOSXGetButtonFrame(TkButton *butPtr); NSRect Tkframe = TkMacOSXGetButtonFrame(butPtr); Tk_Window tkwin = butPtr->tkwin; /* Do not draw if the widget is misplaced or unmapped. */ - if ( NSIsEmptyRect(Tkframe) || + if ( NSIsEmptyRect(Tkframe) || ! macWin->winPtr->flags & TK_MAPPED || - ! NSEqualRects(Tkframe, [self frame]) + ! NSEqualRects(Tkframe, [self frame]) ) { return; } @@ -71,7 +71,7 @@ static NSRect TkMacOSXGetButtonFrame(TkButton *butPtr); int parent_width = Tk_Width(Tk_Parent(tkwin)); int widget_width = Tk_Width(tkwin); int x = Tk_X(tkwin); - if (x > parent_width - 50 || x < 0) { + if (x > parent_width - 50 || x < 0) { return; } } diff --git a/macosx/tkMacOSXDialog.c b/macosx/tkMacOSXDialog.c index 2f77203..a66939a 100644 --- a/macosx/tkMacOSXDialog.c +++ b/macosx/tkMacOSXDialog.c @@ -1,4 +1,4 @@ -/* +/* * tkMacOSXDialog.c -- * * Contains the Mac implementation of the common dialog boxes. diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 0f8e051..537b2e2 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -1480,19 +1480,19 @@ TkScrollWindow( TkRegion damageRgn) /* Region to accumulate damage in. */ { Drawable drawable = Tk_WindowId(tkwin); - MacDrawable *macDraw = (MacDrawable *) drawable; + MacDrawable *macDraw = (MacDrawable *) drawable; NSView *view = TkMacOSXDrawableView(macDraw); CGRect srcRect, dstRect; HIShapeRef dmgRgn = NULL, extraRgn; NSRect bounds, visRect, scrollSrc, scrollDst; NSPoint delta = NSMakePoint(dx, dy); int result; - + if ( view ) { /* Get the scroll area in NSView coordinates (origin at bottom left). */ bounds = [view bounds]; scrollSrc = NSMakeRect( - macDraw->xOff + x, + macDraw->xOff + x, bounds.size.height - height - (macDraw->yOff + y), width, height); scrollDst = NSOffsetRect(scrollSrc, dx, -dy); @@ -1500,45 +1500,45 @@ TkScrollWindow( visRect = [view visibleRect]; scrollSrc = NSIntersectionRect(scrollSrc, visRect); scrollDst = NSIntersectionRect(scrollDst, visRect); - + if ( !NSIsEmptyRect(scrollSrc) && !NSIsEmptyRect(scrollDst) ) { - + /* * Mark the difference between source and destination as damaged. * This region is described in the Tk coordinate system. */ - + srcRect = CGRectMake(x, y, width, height); dstRect = CGRectOffset(srcRect, dx, dy); dmgRgn = HIShapeCreateMutableWithRect(&srcRect); extraRgn = HIShapeCreateWithRect(&dstRect); ChkErr(HIShapeDifference, dmgRgn, extraRgn, (HIMutableShapeRef) dmgRgn); CFRelease(extraRgn); - + /* Scroll the rectangle. */ [view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)]; - - /* + + /* * Adjust the positions of the button subwindows that meet the scroll * area. */ - + for (NSView *subview in [view subviews] ) { if ( [subview isKindOfClass:[NSButton class]] == YES ) { NSRect subframe = [subview frame]; if ( NSIntersectsRect(scrollSrc, subframe) || - NSIntersectsRect(scrollDst, subframe) ) { + NSIntersectsRect(scrollDst, subframe) ) { TkpShiftButton((NSButton *)subview, delta ); } } } - + /* Redisplay the scrolled area. */ [view displayRect:scrollDst]; - + } } - + if ( dmgRgn == NULL ) { dmgRgn = HIShapeCreateEmpty(); } diff --git a/macosx/tkMacOSXEmbed.c b/macosx/tkMacOSXEmbed.c index 41a1e1b..1d66b82 100644 --- a/macosx/tkMacOSXEmbed.c +++ b/macosx/tkMacOSXEmbed.c @@ -14,7 +14,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ - + #include "tkMacOSXPrivate.h" #include "tkBusy.h" diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index 00df93e..a807dfa 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -243,7 +243,7 @@ TkpInit( Tcl_Panic("Mac OS X 10.%d or later required !", (MAC_OS_X_VERSION_MIN_REQUIRED/10)-100); } - + #ifdef TK_FRAMEWORK /* diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index a8e9f2f..85e1d6c 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -757,7 +757,7 @@ TkpPostMenu( * to be posted. */ int y) /* The global y-coordinate */ { - + /* Get the object that holds this Tk Window.*/ Tk_Window root; @@ -765,7 +765,7 @@ TkpPostMenu( if (root == NULL) { return TCL_ERROR; } - + Drawable d = Tk_WindowId(root); NSView *rootview = TkMacOSXGetRootControl(d); NSWindow *win = [rootview window]; diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 1aee7f4..adc7106 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -1,5 +1,5 @@ /* - * tkMacOSXPrivate.h -- + * tkMacOSXPrivate.h -- * * Macros and declarations that are purely internal & private to TkAqua. * diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index f9a2f5f..405558b 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -1,5 +1,5 @@ /* - * tkMacOSXScrollbar.c -- + * tkMacOSXScrollbar.c -- * * This file implements the Macintosh specific portion of the scrollbar * widget. @@ -49,9 +49,9 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); Tk_Window tkwin = scrollPtr->tkwin; NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); /* Do not draw if the widget is misplaced or unmapped. */ - if ( NSIsEmptyRect(Tkframe) || + if ( NSIsEmptyRect(Tkframe) || ! macWin->winPtr->flags & TK_MAPPED || - ! NSEqualRects(Tkframe, [self frame]) + ! NSEqualRects(Tkframe, [self frame]) ) { return; } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index b257caa..5d50278 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ - + #include "tkMacOSXPrivate.h" #include "tkMacOSXWm.h" #include "tkMacOSXEvent.h" @@ -388,7 +388,7 @@ GenerateUpdates( /* * TODO: Here we should handle out of process embedding. */ - } + } return 1; } @@ -785,7 +785,7 @@ double drawTime; /* * Set a minimum time for drawing to render. With removal of private NSView API's, default drawing * is slower and less responsive. This number, which seems feasible after some experimentatation, skips - * some drawing to avoid lag. + * some drawing to avoid lag. */ #define MAX_DYNAMIC_TIME .000000001 @@ -854,7 +854,7 @@ ExposeRestrictProc( -(void) viewWillDraw { [self setNeedsDisplay:YES]; - } + } - (void) generateExposeEvents: (HIMutableShapeRef) shape { @@ -889,12 +889,12 @@ ExposeRestrictProc( UINT2PTR(serial), &oldArg); while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} - + Tk_RestrictEvents(oldProc, oldArg, &oldArg); while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} - } - + } + } /*This is no-op on 10.7 and up because Apple has removed this widget, but leaving here for backwards compatibility.*/ diff --git a/win/tkWinTest.c b/win/tkWinTest.c index 8a92f5a..d824ee4 100644 --- a/win/tkWinTest.c +++ b/win/tkWinTest.c @@ -82,7 +82,7 @@ TkplatformtestInit( struct TestFindControlState { int id; HWND control; -}; +}; /* Callback for window enumeration - used for TestFindControl */ BOOL CALLBACK TestFindControlCallback( -- cgit v0.12 From a59d256b75d74edc1e878bf776e394636df0a422 Mon Sep 17 00:00:00 2001 From: ashok Date: Wed, 3 Dec 2014 16:33:49 +0000 Subject: Fix for 4a0451f529. Needed a Tcl_ResetResult after recursive event loop otherwise clicking Cancel would return a non-empty result in case a script was run in the background as part of the event loop. Also updated test suite which did not actually check that a Cancel resulted in an empty event string. --- tests/winDialog.test | 18 ++++++++++++------ win/tkWinDialog.c | 15 +++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index cd8d937..b7847a5 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -251,10 +251,14 @@ test winDialog-5.4 {GetFileName: Tcl_GetIndexFromObj() != TCL_OK} -constraints { test winDialog-5.5 {GetFileName: Tcl_GetIndexFromObj() == TCL_OK} -constraints { nt testwinevent } -body { - start {tk_getOpenFile -title bar} - then { + start {set x [tk_getOpenFile -title bar]} + set y [then { Click cancel - } + }] + # Note this also tests fix for + # http://core.tcl.tk/tk/tktview/4a0451f5291b3c9168cc560747dae9264e1d2ef6 + # $x is expected to be empty + append x $y } -result {0} test winDialog-5.6 {GetFileName: valid option, but missing value} -constraints { nt @@ -533,10 +537,12 @@ test winDialog-8.1 {OFNHookProc} -constraints {emptyTest nt} -body {} test winDialog-9.1 {Tk_ChooseDirectoryObjCmd: no arguments} -constraints { nt testwinevent } -body { - start {tk_chooseDirectory} - then { + start {set x [tk_chooseDirectory]} + set y [then { Click cancel - } + }] + # $x should be "" on a Cancel + append x $y } -result {0} test winDialog-9.2 {Tk_ChooseDirectoryObjCmd: one argument} -constraints { nt diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index adb5e9e..c137111 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -1407,6 +1407,21 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, hr = fdlgIf->lpVtbl->Show(fdlgIf, hWnd); Tcl_SetServiceMode(oldMode); + /* + * Ensure that hWnd is enabled, because it can happen that we have updated + * the wrapper of the parent, which causes us to leave this child disabled + * (Windows loses sync). + */ + + if (hWnd) + EnableWindow(hWnd, 1); + + /* + * Clear interp result since it might have been set during the modal loop. + * http://core.tcl.tk/tk/tktview/4a0451f5291b3c9168cc560747dae9264e1d2ef6 + */ + Tcl_ResetResult(interp); + if (SUCCEEDED(hr)) { if ((oper == OFN_FILE_OPEN) && optsPtr->multi) { IShellItemArray *multiIf; -- cgit v0.12 From 907864a09c9230ef3a809b73b835abdacea8c944 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 13 Dec 2014 02:47:44 +0000 Subject: Add header install flag to OS X GNUMakefile; thanks to Stephan Houben for patch --- macosx/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/GNUmakefile b/macosx/GNUmakefile index 333961c..02240ed 100644 --- a/macosx/GNUmakefile +++ b/macosx/GNUmakefile @@ -134,7 +134,7 @@ endif INSTALL_TARGETS = install-binaries install-libraries ifeq (${EMBEDDED_BUILD},) -INSTALL_TARGETS += install-private-headers install-demos +INSTALL_TARGETS += install-private-headers install-headers install-demos endif ifeq (${INSTALL_BUILD}_${EMBEDDED_BUILD}_${BUILD_STYLE},1__Deployment) INSTALL_TARGETS += html-tk -- cgit v0.12 From 8faca188c488af10facd0c8470314303f1b02c5b Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sun, 21 Dec 2014 04:11:51 +0000 Subject: Minor optimization of drawing code in OSX --- macosx/tkMacOSXDraw.c | 4 ++-- macosx/tkMacOSXMenubutton.c | 17 +++++++++++++++-- macosx/tkMacOSXWindowEvent.c | 5 ++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 537b2e2..9e3435d 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -1657,13 +1657,13 @@ TkMacOSXSetupDrawingContext( CGContextSetTextDrawingMode(dc.context, kCGTextFill); CGContextConcatCTM(dc.context, t); if (dc.clipRgn) { -#ifdef TK_MAC_DEBUG_DRAWING + #ifdef TK_MAC_DEBUG_DRAWING CGContextSaveGState(dc.context); ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context); CGContextSetRGBFillColor(dc.context, 1.0, 0.0, 0.0, 0.1); CGContextEOFillPath(dc.context); CGContextRestoreGState(dc.context); -#endif /* TK_MAC_DEBUG_DRAWING */ + #endif /* TK_MAC_DEBUG_DRAWING */ CGRect r; if (!HIShapeIsRectangular(dc.clipRgn) || !CGRectContainsRect( *HIShapeGetBounds(dc.clipRgn, &r), diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index df42763..c79a9c1 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -60,12 +60,23 @@ static const BoundsFix boundsFixes[] = { #endif + + /* * Forward declarations for procedures defined later in this file: */ static void MenuButtonEventProc(ClientData clientData, XEvent *eventPtr); +/* + * The structure below defines menubutton class behavior by means of functions + * that can be invoked from generic window code. + */ + +Tk_ClassProcs tkpMenubuttonClass = { + sizeof(Tk_ClassProcs), /* size */ + TkMenuButtonWorldChanged, /* worldChangedProc */ +}; /* *---------------------------------------------------------------------- @@ -87,9 +98,11 @@ TkMenuButton * TkpCreateMenuButton( Tk_Window tkwin) { - MacMenuButton *macButtonPtr = ckalloc(sizeof(MacMenuButton)); + MacMenuButton *macButtonPtr = + (MacMenuButton *) ckalloc(sizeof(MacMenuButton)); macButtonPtr->button = nil; + Tk_CreateEventHandler(tkwin, ActivateMask, MenuButtonEventProc, (ClientData) macButtonPtr); return (TkMenuButton *) macButtonPtr; @@ -160,7 +173,7 @@ TkpDisplayMenuButton( if (!tkwin || !Tk_IsMapped(tkwin) || !view || !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { return; - } + } CGContextConcatCTM(dc.context, t); Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, mbPtr->normalBorder, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 5d50278..6546070 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -839,8 +839,11 @@ ExposeRestrictProc( NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode, nil]]; } + CFRelease(drawShape); drawTime=-[beginTime timeIntervalSinceNow]; + [super setNeedsDisplayInRect:rect]; + } /*At conclusion of resize event, send notification and set view for redraw if earlier drawing was skipped because of lagginess.*/ @@ -877,7 +880,7 @@ ExposeRestrictProc( * just posted Expose events from generating new redraws. */ - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} /* * For smoother drawing, process Expose events and resulting redraws -- cgit v0.12 From c72a9f168448e8f6b17aa805d5308b4934cfa4d1 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sun, 21 Dec 2014 04:16:44 +0000 Subject: Revert unintended commit of menubutton file --- macosx/tkMacOSXMenubutton.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index c79a9c1..df42763 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -60,23 +60,12 @@ static const BoundsFix boundsFixes[] = { #endif - - /* * Forward declarations for procedures defined later in this file: */ static void MenuButtonEventProc(ClientData clientData, XEvent *eventPtr); -/* - * The structure below defines menubutton class behavior by means of functions - * that can be invoked from generic window code. - */ - -Tk_ClassProcs tkpMenubuttonClass = { - sizeof(Tk_ClassProcs), /* size */ - TkMenuButtonWorldChanged, /* worldChangedProc */ -}; /* *---------------------------------------------------------------------- @@ -98,11 +87,9 @@ TkMenuButton * TkpCreateMenuButton( Tk_Window tkwin) { - MacMenuButton *macButtonPtr = - (MacMenuButton *) ckalloc(sizeof(MacMenuButton)); + MacMenuButton *macButtonPtr = ckalloc(sizeof(MacMenuButton)); macButtonPtr->button = nil; - Tk_CreateEventHandler(tkwin, ActivateMask, MenuButtonEventProc, (ClientData) macButtonPtr); return (TkMenuButton *) macButtonPtr; @@ -173,7 +160,7 @@ TkpDisplayMenuButton( if (!tkwin || !Tk_IsMapped(tkwin) || !view || !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { return; - } + } CGContextConcatCTM(dc.context, t); Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, mbPtr->normalBorder, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); -- cgit v0.12 From 6137cff44fac896616e033bcba2aa90cd3d4adf5 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Wed, 24 Dec 2014 04:43:40 +0000 Subject: All on Tk/Cocoa: Improve view performance during resizing; implement custom drawing of scroller to remove flickering and ghosted appearance during window operations; reduce flickering of menubutton during resizing, but do not completely eliminate ghosted rendering when widget is unmapped --- macosx/tkMacOSXButton.c | 2 +- macosx/tkMacOSXMenubutton.c | 2 +- macosx/tkMacOSXScrlbr.c | 117 ++++++++++++++++++++++++++++++------------- macosx/tkMacOSXWindowEvent.c | 46 +++++++++-------- macosx/ttkMacOSXTheme.c | 10 ++++ 5 files changed, 119 insertions(+), 58 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 720e40d..627565a 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -38,7 +38,7 @@ static NSRect TkMacOSXGetButtonFrame(TkButton *butPtr); */ @interface TkNSButton: NSButton - +- (void)drawRect:(NSRect)dirtyRect; @end @implementation TkNSButton diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index df42763..02a7a38 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -15,7 +15,7 @@ #include "tkMacOSXPrivate.h" #include "tkMenubutton.h" #include "tkMacOSXFont.h" -#include "tkMacOSXDebug.h" +#include "tkMacOSXDebug.h" /* #ifdef TK_MAC_DEBUG diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index 405558b..bd05df8 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -7,7 +7,8 @@ * Copyright (c) 1996 by Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen - * + * Copyright (c) 2014 Marc Culler. + * Copyright (c) 2014 Kevin Walzer/WordTech Commununications LLC. * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ @@ -21,6 +22,7 @@ #endif */ + NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); /* @@ -31,56 +33,103 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); * aware of the state of its Tk parent. This subclass overrides the drawRect * method so that it will not draw itself if the widget is completely outside * of its container. + * + * Custom drawing of the knob seems to work around the flickering visible after * private API's were removed. Based on technique outlined at + * http://stackoverflow.com/questions/1604682/nsscroller- + * graphical-glitches-lag. Only supported on 10.7 and above. */ @interface TkNSScroller: NSScroller -(void) drawRect:(NSRect)dirtyRect; - +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 +-(BOOL) isHorizontal; +-(void) drawKnob; +- (void)drawArrow:(NSScrollerArrow)arrow highlightPart:(int)flag; +- (void)drawKnobSlotInRect:(NSRect)rect highlight:(BOOL)highlight; +#endif @end @implementation TkNSScroller - - (void)drawRect:(NSRect)dirtyRect - { - NSInteger tag = [self tag]; - if ( tag != -1) { - TkScrollbar *scrollPtr = (TkScrollbar *)tag; - MacDrawable* macWin = (MacDrawable *)scrollPtr; - Tk_Window tkwin = scrollPtr->tkwin; - NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); - /* Do not draw if the widget is misplaced or unmapped. */ - if ( NSIsEmptyRect(Tkframe) || - ! macWin->winPtr->flags & TK_MAPPED || - ! NSEqualRects(Tkframe, [self frame]) - ) { + +- (void)drawRect:(NSRect)dirtyRect +{ + NSInteger tag = [self tag]; + if ( tag != -1) { + TkScrollbar *scrollPtr = (TkScrollbar *)tag; + MacDrawable* macWin = (MacDrawable *)scrollPtr; + Tk_Window tkwin = scrollPtr->tkwin; + NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); + /* Do not draw if the widget is misplaced or unmapped. */ + if ( NSIsEmptyRect(Tkframe) || + ! macWin->winPtr->flags & TK_MAPPED || + ! NSEqualRects(Tkframe, [self frame]) + ) { + return; + } + + /* + * Do not draw if the widget is completely outside of its parent. + */ + if (tkwin) { + int parent_height = Tk_Height(Tk_Parent(tkwin)); + int widget_height = Tk_Height(tkwin); + int y = Tk_Y(tkwin); + if ( y > parent_height || y + widget_height < 0 ) { return; } - /* - * Do not draw if the widget is completely outside of its parent. - */ - if (tkwin) { - int parent_height = Tk_Height(Tk_Parent(tkwin)); - int widget_height = Tk_Height(tkwin); - int y = Tk_Y(tkwin); - if ( y > parent_height || y + widget_height < 0 ) { - return; - } - - int parent_width = Tk_Width(Tk_Parent(tkwin)); - int widget_width = Tk_Width(tkwin); - int x = Tk_X(tkwin); - if (x > parent_width || x + widget_width < 0) { - return; - } + int parent_width = Tk_Width(Tk_Parent(tkwin)); + int widget_width = Tk_Width(tkwin); + int x = Tk_X(tkwin); + if (x > parent_width || x + widget_width < 0) { + return; } } - [super drawRect:dirtyRect]; } + [super drawRect:dirtyRect]; +} -@end +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 +- (BOOL)isHorizontal { + NSRect bounds = [self bounds]; + return NSWidth(bounds) < NSHeight (bounds); +} +- (void)drawKnob +{ + NSRect knobRect = [self rectForPart:NSScrollerKnob]; + + if ([self isHorizontal]) { + NSRect newRect = NSMakeRect(knobRect.origin.x, knobRect.origin.y, knobRect.size.width - 5, knobRect.size.height); + NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:newRect xRadius:7 yRadius:7]; + + [[NSColor lightGrayColor] set]; + [path fill]; + } else { + NSRect newRect = NSMakeRect(knobRect.origin.x, knobRect.origin.y, knobRect.size.width, knobRect.size.height - 5); + NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:newRect xRadius:7 yRadius:7]; + + [[NSColor lightGrayColor] set]; + [path fill]; + } + +} + +- (void)drawArrow:(NSScrollerArrow)arrow highlightPart:(int)flag +{ + // We don't want arrows +} + +- (void)drawKnobSlotInRect:(NSRect)rect highlight:(BOOL)highlight +{ + +} +#endif + +@end + /* * Declaration of Mac specific scrollbar structure. diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 6546070..7207859 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -769,6 +769,8 @@ Tk_MacOSXIsAppInFront(void) @interface TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect; - (void) generateExposeEvents: (HIMutableShapeRef) shape; +- (BOOL) preservesContentDuringLiveResize; +- (void) viewWillStartLiveResize; - (void) viewDidEndLiveResize; - (void) viewWillDraw; - (BOOL) isOpaque; @@ -780,15 +782,6 @@ Tk_MacOSXIsAppInFront(void) @implementation TKContentView @end -double drawTime; - -/* - * Set a minimum time for drawing to render. With removal of private NSView API's, default drawing - * is slower and less responsive. This number, which seems feasible after some experimentatation, skips - * some drawing to avoid lag. - */ - -#define MAX_DYNAMIC_TIME .000000001 /*Restrict event processing to Expose events.*/ static Tk_RestrictAction @@ -805,10 +798,12 @@ ExposeRestrictProc( - (void) drawRect: (NSRect) rect { + const NSRect *rectsBeingDrawn; NSInteger rectsBeingDrawnCount; [self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount]; + #ifdef TK_MAC_DEBUG_DRAWING TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, NSStringFromRect(rect)); [[NSColor colorWithDeviceRed:0.0 green:1.0 blue:0.0 alpha:.1] setFill]; @@ -816,11 +811,7 @@ ExposeRestrictProc( NSCompositeSourceOver); #endif - NSDate *beginTime=[NSDate date]; - - /*Skip drawing during live resize if redraw is too slow.*/ - if([self inLiveResize] && drawTime>MAX_DYNAMIC_TIME) return; - + CGFloat height = [self bounds].size.height; HIMutableShapeRef drawShape = HIShapeCreateMutable(); @@ -841,24 +832,35 @@ ExposeRestrictProc( } CFRelease(drawShape); - drawTime=-[beginTime timeIntervalSinceNow]; - [super setNeedsDisplayInRect:rect]; } -/*At conclusion of resize event, send notification and set view for redraw if earlier drawing was skipped because of lagginess.*/ + +/*Provide more fine-grained control over resizing of content to reduce flicker after removal of private API's.*/ + +- (BOOL) preservesContentDuringLiveResize +{ + return YES; +} + +- (void)viewWillStartLiveResize +{ + [super viewWillStartLiveResize]; + [self setNeedsDisplay:NO]; +} + + - (void)viewDidEndLiveResize { - if(drawTime>MAX_DYNAMIC_TIME) { + [self setNeedsDisplay:YES]; + [super setNeedsDisplay:YES]; [super viewDidEndLiveResize]; - } + } --(void) viewWillDraw { - [self setNeedsDisplay:YES]; - } +/*Core function of this class, generates expose events for redrawing.*/ - (void) generateExposeEvents: (HIMutableShapeRef) shape { diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c index a4abc7b..c5be354 100644 --- a/macosx/ttkMacOSXTheme.c +++ b/macosx/ttkMacOSXTheme.c @@ -528,6 +528,10 @@ static Ttk_ElementSpec ComboboxElementSpec = { ComboboxElementDraw }; + + + + /*---------------------------------------------------------------------- * +++ Spinbuttons. * @@ -600,6 +604,11 @@ static TrackElementData ScaleData = { kThemeSlider, kThemeMetricHSliderHeight }; +static TrackElementData ScrollData = { + kThemeScrollBarMedium +}; + + typedef struct { Tcl_Obj *fromObj; /* minimum value */ Tcl_Obj *toObj; /* maximum value */ @@ -661,6 +670,7 @@ static void TrackElementDraw( info.trackInfo.slider.thumbDir = kThemeThumbPlain; } + BEGIN_DRAWING(d) ChkErr(HIThemeDrawTrack, &info, NULL, dc.context, HIOrientation); END_DRAWING -- cgit v0.12 From df487fa7f2296cda3e3bd23546b545ca6ecd3751 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Wed, 24 Dec 2014 04:47:21 +0000 Subject: Revert change from ttk Mac theme --- macosx/ttkMacOSXTheme.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c index c5be354..3f507b0 100644 --- a/macosx/ttkMacOSXTheme.c +++ b/macosx/ttkMacOSXTheme.c @@ -604,10 +604,6 @@ static TrackElementData ScaleData = { kThemeSlider, kThemeMetricHSliderHeight }; -static TrackElementData ScrollData = { - kThemeScrollBarMedium -}; - typedef struct { Tcl_Obj *fromObj; /* minimum value */ -- cgit v0.12 From 25af82850347b3fec95a0c04c3277942f41db2c5 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Wed, 24 Dec 2014 07:13:08 +0000 Subject: Refinement of custom scrollbars on Tk-Cocoa; now more centered, virtually identical to scrollbars in Safari, etc. --- macosx/tkMacOSXScrlbr.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index bd05df8..6b4d1ff 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -39,6 +39,7 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); * graphical-glitches-lag. Only supported on 10.7 and above. */ + @interface TkNSScroller: NSScroller -(void) drawRect:(NSRect)dirtyRect; #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 @@ -91,7 +92,7 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); } #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 -- (BOOL)isHorizontal { +- (BOOL)isVertical { NSRect bounds = [self bounds]; return NSWidth(bounds) < NSHeight (bounds); } @@ -101,18 +102,18 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); { NSRect knobRect = [self rectForPart:NSScrollerKnob]; - if ([self isHorizontal]) { - NSRect newRect = NSMakeRect(knobRect.origin.x, knobRect.origin.y, knobRect.size.width - 5, knobRect.size.height); - NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:newRect xRadius:7 yRadius:7]; + if ([self isVertical]) { + NSRect newRect = NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y, knobRect.size.width - 6, knobRect.size.height); + NSBezierPath *scrollerPath = [NSBezierPath bezierPathWithRoundedRect:newRect xRadius:4 yRadius:4]; [[NSColor lightGrayColor] set]; - [path fill]; + [scrollerPath fill]; } else { - NSRect newRect = NSMakeRect(knobRect.origin.x, knobRect.origin.y, knobRect.size.width, knobRect.size.height - 5); - NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:newRect xRadius:7 yRadius:7]; + NSRect newRect = NSMakeRect(knobRect.origin.x, knobRect.origin.y + 3, knobRect.size.width, knobRect.size.height - 6); + NSBezierPath *scrollerPath = [NSBezierPath bezierPathWithRoundedRect:newRect xRadius:4 yRadius:4]; [[NSColor lightGrayColor] set]; - [path fill]; + [scrollerPath fill]; } } @@ -124,8 +125,9 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); - (void)drawKnobSlotInRect:(NSRect)rect highlight:(BOOL)highlight { - + } + #endif @end -- cgit v0.12 From 226cb2b752c57912f6b32e77b467e7e77d619079 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sun, 28 Dec 2014 05:24:34 +0000 Subject: Refinement of redraw during window resizing in Cocoa; refinement of button display --- macosx/tkMacOSXButton.c | 5 +++-- macosx/tkMacOSXWindowEvent.c | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 627565a..80324cc 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -67,14 +67,15 @@ static NSRect TkMacOSXGetButtonFrame(TkButton *butPtr); return; } - /* Do not draw if the widget is completely outside of its parent, or within 50 pixels of the right border; this prevents buttons from being drawn on peer widgets as scrolling occurs. */ + /* Do not draw if the widget is completely outside of its parent, or within 20 pixels of the right border; this prevents buttons from being drawn on peer widgets as scrolling occurs. */ int parent_width = Tk_Width(Tk_Parent(tkwin)); int widget_width = Tk_Width(tkwin); int x = Tk_X(tkwin); - if (x > parent_width - 50 || x < 0) { + if (x > parent_width - 20 || x < 0) { return; } } + [super drawRect:dirtyRect]; } } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 7207859..bce64f2 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -817,7 +817,6 @@ ExposeRestrictProc( while (rectsBeingDrawnCount--) { CGRect r = NSRectToCGRect(*rectsBeingDrawn++); - r.origin.y = height - (r.origin.y + r.size.height); HIShapeUnionWithRect(drawShape, &r); } @@ -838,6 +837,13 @@ ExposeRestrictProc( /*Provide more fine-grained control over resizing of content to reduce flicker after removal of private API's.*/ +-(void) viewWillDraw +{ + + [super viewWillDraw]; +} + + - (BOOL) preservesContentDuringLiveResize { return YES; @@ -845,21 +851,24 @@ ExposeRestrictProc( - (void)viewWillStartLiveResize { + NSDisableScreenUpdates(); [super viewWillStartLiveResize]; [self setNeedsDisplay:NO]; + [self setHidden:YES]; } - (void)viewDidEndLiveResize { + NSEnableScreenUpdates(); + [self setHidden:NO]; [self setNeedsDisplay:YES]; [super setNeedsDisplay:YES]; [super viewDidEndLiveResize]; } - /*Core function of this class, generates expose events for redrawing.*/ - (void) generateExposeEvents: (HIMutableShapeRef) shape { @@ -872,6 +881,7 @@ ExposeRestrictProc( return; } + HIShapeGetBounds(shape, &updateBounds); serial = LastKnownRequestProcessed(Tk_Display(winPtr)); if (GenerateUpdates(shape, &updateBounds, winPtr) && @@ -896,6 +906,7 @@ ExposeRestrictProc( while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} Tk_RestrictEvents(oldProc, oldArg, &oldArg); + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} } -- cgit v0.12 From 577a9d3b2ca963ffebd97c5a092fea50cae3eddf Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Wed, 31 Dec 2014 21:26:37 +0000 Subject: Reduce redraw issues during window zoom events on Cocoa --- library/button.tcl | 1 + macosx/tkMacOSXWindowEvent.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/library/button.tcl b/library/button.tcl index 815b137..c48515a 100644 --- a/library/button.tcl +++ b/library/button.tcl @@ -17,6 +17,7 @@ #------------------------------------------------------------------------- if {[tk windowingsystem] eq "aqua"} { + bind Radiobutton { tk::ButtonEnter %W } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index bce64f2..0e0d8ef 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -80,6 +80,10 @@ extern NSString *opaqueTag; NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); + /*Disable drawing until window is resized removes flicker and drawing artifacts;necessary after removal of private API.*/ + NSDisableScreenUpdates(); + [ [w contentView] setHidden:YES]; + if (winPtr) { WmInfo *wmPtr = winPtr->wmInfoPtr; NSRect bounds = [w frame]; @@ -107,6 +111,8 @@ extern NSString *opaqueTag; } TkGenWMConfigureEvent((Tk_Window) winPtr, x, y, width, height, flags); } + [[w contentView] setHidden:NO]; + NSEnableScreenUpdates(); } - (void) windowExpanded: (NSNotification *) notification -- cgit v0.12 From f738b3d5e502f4e2cec85924873ae8b4d8c5a768 Mon Sep 17 00:00:00 2001 From: fvogel Date: Fri, 2 Jan 2015 11:18:04 +0000 Subject: Cherrypicked [97391a2fef] - Increased the after delay in test spinbox-1.8.4 because it failed sometimes for me, depending on the load of the computer running the test suite --- tests/ttk/spinbox.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ttk/spinbox.test b/tests/ttk/spinbox.test index 3397e37..f7741c6 100644 --- a/tests/ttk/spinbox.test +++ b/tests/ttk/spinbox.test @@ -144,7 +144,7 @@ test spinbox-1.8.4 "-validate option: " -setup { pack .sb .sb set 50 focus .sb - after 100 {set ::spinbox_wait 1} ; vwait ::spinbox_wait + after 500 {set ::spinbox_wait 1} ; vwait ::spinbox_wait set ::spinbox_test } -cleanup { destroy .sb -- cgit v0.12 From 94446123f6728f30f9bae4c73ad5d242e249ee0b Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sun, 4 Jan 2015 23:16:41 +0000 Subject: Improved scrolling for text under Cocoa; thanks to Marc Culler for patch. --- macosx/tkMacOSXDraw.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 9e3435d..07bfe81 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -1488,6 +1488,7 @@ TkScrollWindow( NSPoint delta = NSMakePoint(dx, dy); int result; + if ( view ) { /* Get the scroll area in NSView coordinates (origin at bottom left). */ bounds = [view bounds]; @@ -1533,8 +1534,12 @@ TkScrollWindow( } } - /* Redisplay the scrolled area. */ - [view displayRect:scrollDst]; + /* Redisplay the scrolled area; hide to reduce flicker after removal of private API calls. */ + [view setHidden:YES]; + [view displayRect:scrollDst]; + [view setHidden:NO]; + + } } -- cgit v0.12 From 526838c498310083108c2dce3c2d9a71dd924d89 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sun, 4 Jan 2015 23:24:23 +0000 Subject: Improved scrolling for text under Cocoa; thanks to Marc Culler for patch. --- generic/tkTextDisp.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index a0cbc52..4391f0c 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -3885,6 +3885,21 @@ TkTextUpdateOneLine( * *---------------------------------------------------------------------- */ +#ifdef MAC_OSX_TK +static void +RedisplayText( + ClientData clientData ) +{ + register TkText *textPtr = (TkText *) clientData; + TextDInfo *dInfoPtr = textPtr->dInfoPtr; + TkRegion damageRegion = TkCreateRegion(); + XRectangle rectangle = {0, 0, dInfoPtr->maxX, dInfoPtr->maxY}; + TkUnionRectWithRegion(&rectangle, damageRegion, damageRegion); + + TextInvalidateRegion(textPtr, damageRegion); + DisplayText(clientData); +} +#endif static void DisplayText( @@ -3899,6 +3914,9 @@ DisplayText( int bottomY = 0; /* Initialization needed only to stop compiler * warnings. */ Tcl_Interp *interp; +#ifdef MAC_OSX_TK + Tcl_TimerToken macRefreshTimer = NULL; +#endif if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { /* @@ -4100,6 +4118,22 @@ DisplayText( oldY, dInfoPtr->maxX-dInfoPtr->x, height, 0, y-oldY, damageRgn)) { TextInvalidateRegion(textPtr, damageRgn); + +#ifdef MAC_OSX_TK + + /* + * On OS X large scrolls sometimes leave garbage on the screen. + * This attempts to clean it up by redisplaying the Text window + * after 200 milliseconds. + */ + if ( abs(y-oldY) > 14 ) { + Tcl_DeleteTimerHandler(macRefreshTimer); + macRefreshTimer = Tcl_CreateTimerHandler(200, + RedisplayText, + clientData); + } +#endif + } numCopies++; TkDestroyRegion(damageRgn); -- cgit v0.12 From 13a883e4c3662265de27a4013622d4ccb6512e7a Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Mon, 12 Jan 2015 03:18:08 +0000 Subject: Revert changes to Mac scrollbar; native implementation is best that can be done, custom drawing in scrollbar is worse from UI standpoint. --- macosx/tkMacOSXInit.c | 4 +- macosx/tkMacOSXScrlbr.c | 119 +++++++++++++------------------------------ macosx/tkMacOSXWindowEvent.c | 5 -- 3 files changed, 36 insertions(+), 92 deletions(-) diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index a807dfa..79ce70a 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -54,7 +54,7 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt @end @interface TKApplication(TKScrlbr) -- (void) _setupScrollBarNotifications; +//- (void) _setupScrollBarNotifications; @end @interface TKApplication(TKMenus) @@ -108,7 +108,7 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt selector:@selector(_postedNotification:) name:nil object:nil]; #endif [self _setupWindowNotifications]; - [self _setupScrollBarNotifications]; + // [self _setupScrollBarNotifications]; [self _setupApplicationNotifications]; } diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index 6b4d1ff..ebb99f3 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -7,8 +7,7 @@ * Copyright (c) 1996 by Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen - * Copyright (c) 2014 Marc Culler. - * Copyright (c) 2014 Kevin Walzer/WordTech Commununications LLC. + * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ @@ -22,7 +21,6 @@ #endif */ - NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); /* @@ -33,106 +31,57 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); * aware of the state of its Tk parent. This subclass overrides the drawRect * method so that it will not draw itself if the widget is completely outside * of its container. - * - * Custom drawing of the knob seems to work around the flickering visible after * private API's were removed. Based on technique outlined at - * http://stackoverflow.com/questions/1604682/nsscroller- - * graphical-glitches-lag. Only supported on 10.7 and above. */ - @interface TkNSScroller: NSScroller -(void) drawRect:(NSRect)dirtyRect; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 --(BOOL) isHorizontal; --(void) drawKnob; -- (void)drawArrow:(NSScrollerArrow)arrow highlightPart:(int)flag; -- (void)drawKnobSlotInRect:(NSRect)rect highlight:(BOOL)highlight; -#endif + @end @implementation TkNSScroller - -- (void)drawRect:(NSRect)dirtyRect -{ - NSInteger tag = [self tag]; - if ( tag != -1) { - TkScrollbar *scrollPtr = (TkScrollbar *)tag; - MacDrawable* macWin = (MacDrawable *)scrollPtr; - Tk_Window tkwin = scrollPtr->tkwin; - NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); - /* Do not draw if the widget is misplaced or unmapped. */ - if ( NSIsEmptyRect(Tkframe) || - ! macWin->winPtr->flags & TK_MAPPED || - ! NSEqualRects(Tkframe, [self frame]) - ) { - return; - } - - /* - * Do not draw if the widget is completely outside of its parent. - */ - if (tkwin) { - int parent_height = Tk_Height(Tk_Parent(tkwin)); - int widget_height = Tk_Height(tkwin); - int y = Tk_Y(tkwin); - if ( y > parent_height || y + widget_height < 0 ) { + - (void)drawRect:(NSRect)dirtyRect + { + NSInteger tag = [self tag]; + if ( tag != -1) { + TkScrollbar *scrollPtr = (TkScrollbar *)tag; + MacDrawable* macWin = (MacDrawable *)scrollPtr; + Tk_Window tkwin = scrollPtr->tkwin; + NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); + /* Do not draw if the widget is misplaced or unmapped. */ + if ( NSIsEmptyRect(Tkframe) || + ! macWin->winPtr->flags & TK_MAPPED || + ! NSEqualRects(Tkframe, [self frame]) + ) { return; } - int parent_width = Tk_Width(Tk_Parent(tkwin)); - int widget_width = Tk_Width(tkwin); - int x = Tk_X(tkwin); - if (x > parent_width || x + widget_width < 0) { - return; + /* + * Do not draw if the widget is completely outside of its parent. + */ + if (tkwin) { + int parent_height = Tk_Height(Tk_Parent(tkwin)); + int widget_height = Tk_Height(tkwin); + int y = Tk_Y(tkwin); + if ( y > parent_height || y + widget_height < 0 ) { + return; + } + + int parent_width = Tk_Width(Tk_Parent(tkwin)); + int widget_width = Tk_Width(tkwin); + int x = Tk_X(tkwin); + if (x > parent_width || x + widget_width < 0) { + return; + } } } + [super drawRect:dirtyRect]; } - [super drawRect:dirtyRect]; -} - -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 -- (BOOL)isVertical { - NSRect bounds = [self bounds]; - return NSWidth(bounds) < NSHeight (bounds); -} - - -- (void)drawKnob -{ - NSRect knobRect = [self rectForPart:NSScrollerKnob]; - - if ([self isVertical]) { - NSRect newRect = NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y, knobRect.size.width - 6, knobRect.size.height); - NSBezierPath *scrollerPath = [NSBezierPath bezierPathWithRoundedRect:newRect xRadius:4 yRadius:4]; - - [[NSColor lightGrayColor] set]; - [scrollerPath fill]; - } else { - NSRect newRect = NSMakeRect(knobRect.origin.x, knobRect.origin.y + 3, knobRect.size.width, knobRect.size.height - 6); - NSBezierPath *scrollerPath = [NSBezierPath bezierPathWithRoundedRect:newRect xRadius:4 yRadius:4]; - - [[NSColor lightGrayColor] set]; - [scrollerPath fill]; - } - -} - -- (void)drawArrow:(NSScrollerArrow)arrow highlightPart:(int)flag -{ - // We don't want arrows -} - -- (void)drawKnobSlotInRect:(NSRect)rect highlight:(BOOL)highlight -{ - -} - -#endif @end + /* * Declaration of Mac specific scrollbar structure. */ diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 0e0d8ef..0e3ecf7 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -952,11 +952,6 @@ ExposeRestrictProc( [super setFrameSize:newSize]; } -- (void) setNeedsDisplayInRect: (NSRect) invalidRect -{ - [super setNeedsDisplayInRect:invalidRect]; -} - - (BOOL) isOpaque { NSWindow *w = [self window]; -- cgit v0.12 From 0cf2ddb889ee20cd163b86cbd3df3a95f9b504e1 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Mon, 12 Jan 2015 03:21:15 +0000 Subject: Revert additional changes to scrollbar code --- macosx/tkMacOSXInit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index 79ce70a..a807dfa 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -54,7 +54,7 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt @end @interface TKApplication(TKScrlbr) -//- (void) _setupScrollBarNotifications; +- (void) _setupScrollBarNotifications; @end @interface TKApplication(TKMenus) @@ -108,7 +108,7 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt selector:@selector(_postedNotification:) name:nil object:nil]; #endif [self _setupWindowNotifications]; - // [self _setupScrollBarNotifications]; + [self _setupScrollBarNotifications]; [self _setupApplicationNotifications]; } -- cgit v0.12 From 82a83e55c5f93ae3e6545f829f98c828fefa3c5b Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 15 Jan 2015 16:06:18 +0000 Subject: remove some unnecessary eol-spacing --- generic/tkTextDisp.c | 4 ++-- macosx/tkMacOSXButton.c | 2 +- macosx/tkMacOSXDraw.c | 2 +- macosx/tkMacOSXMenubutton.c | 2 +- macosx/tkMacOSXScrlbr.c | 4 ++-- macosx/tkMacOSXWindowEvent.c | 8 ++++---- tests/bugs.tcl | 2 +- tests/butGeom2.tcl | 2 +- tests/canvPsGrph.tcl | 6 +++--- tests/canvPsImg.tcl | 2 +- tests/constraints.tcl | 6 +++--- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 4391f0c..7422fd1 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -3895,7 +3895,7 @@ RedisplayText( TkRegion damageRegion = TkCreateRegion(); XRectangle rectangle = {0, 0, dInfoPtr->maxX, dInfoPtr->maxY}; TkUnionRectWithRegion(&rectangle, damageRegion, damageRegion); - + TextInvalidateRegion(textPtr, damageRegion); DisplayText(clientData); } @@ -3915,7 +3915,7 @@ DisplayText( * warnings. */ Tcl_Interp *interp; #ifdef MAC_OSX_TK - Tcl_TimerToken macRefreshTimer = NULL; + Tcl_TimerToken macRefreshTimer = NULL; #endif if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 80324cc..64a05d6 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -75,7 +75,7 @@ static NSRect TkMacOSXGetButtonFrame(TkButton *butPtr); return; } } - + [super drawRect:dirtyRect]; } } diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 07bfe81..6c0268c 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -1539,7 +1539,7 @@ TkScrollWindow( [view displayRect:scrollDst]; [view setHidden:NO]; - + } } diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index 02a7a38..df42763 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -15,7 +15,7 @@ #include "tkMacOSXPrivate.h" #include "tkMenubutton.h" #include "tkMacOSXFont.h" -#include "tkMacOSXDebug.h" +#include "tkMacOSXDebug.h" /* #ifdef TK_MAC_DEBUG diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index ebb99f3..405558b 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -49,9 +49,9 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); Tk_Window tkwin = scrollPtr->tkwin; NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); /* Do not draw if the widget is misplaced or unmapped. */ - if ( NSIsEmptyRect(Tkframe) || + if ( NSIsEmptyRect(Tkframe) || ! macWin->winPtr->flags & TK_MAPPED || - ! NSEqualRects(Tkframe, [self frame]) + ! NSEqualRects(Tkframe, [self frame]) ) { return; } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 0e3ecf7..63df797 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -817,7 +817,7 @@ ExposeRestrictProc( NSCompositeSourceOver); #endif - + CGFloat height = [self bounds].size.height; HIMutableShapeRef drawShape = HIShapeCreateMutable(); @@ -835,9 +835,9 @@ ExposeRestrictProc( NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode, nil]]; } - + CFRelease(drawShape); - + } @@ -872,7 +872,7 @@ ExposeRestrictProc( [self setNeedsDisplay:YES]; [super setNeedsDisplay:YES]; [super viewDidEndLiveResize]; - + } /*Core function of this class, generates expose events for redrawing.*/ diff --git a/tests/bugs.tcl b/tests/bugs.tcl index 83d9519..55e5f84 100644 --- a/tests/bugs.tcl +++ b/tests/bugs.tcl @@ -1,6 +1,6 @@ # This file is a Tcl script to test out various known bugs that will # cause Tk to crash. This file ends with .tcl instead of .test to make -# sure it isn't run when you type "source all". We currently are not +# sure it isn't run when you type "source all". We currently are not # shipping this file with the rest of the source release. # # Copyright (c) 1996 Sun Microsystems, Inc. diff --git a/tests/butGeom2.tcl b/tests/butGeom2.tcl index 96ff209..096225c 100644 --- a/tests/butGeom2.tcl +++ b/tests/butGeom2.tcl @@ -35,7 +35,7 @@ pack .t.anchorLabel .t.control.left.f -in .t.control.left -side top -anchor w foreach opt {activebackground activeforeground background disabledforeground foreground highlightbackground highlightcolor } { #button .t.color-$opt -text $opt -command "config -$opt \[tk_chooseColor]" menubutton .t.color-$opt -text $opt -menu .t.color-$opt.m -indicatoron 1 \ - -relief raised -bd 2 + -relief raised -bd 2 menu .t.color-$opt.m -tearoff 0 .t.color-$opt.m add command -label Red -command "config -$opt red" .t.color-$opt.m add command -label Green -command "config -$opt green" diff --git a/tests/canvPsGrph.tcl b/tests/canvPsGrph.tcl index 343979f..08ccd74 100644 --- a/tests/canvPsGrph.tcl +++ b/tests/canvPsGrph.tcl @@ -50,13 +50,13 @@ proc mkObjs c { $c create rect 380 200 420 240 -fill black $c create rect 200 330 240 370 -fill black } - + if {$what == "oval"} { $c create oval 50 10 150 80 -fill black -stipple gray25 -outline {} $c create oval 100 100 200 150 -outline {} -fill black -stipple gray50 $c create oval 250 100 400 300 -width .5c } - + if {$what == "poly"} { $c create poly 100 200 200 50 300 200 -smooth yes -stipple gray25 \ -outline black -width 4 @@ -68,7 +68,7 @@ proc mkObjs c { $c create poly 20 200 100 220 90 100 40 250 \ -fill {} -outline brown -width 3 } - + if {$what == "line"} { $c create line 20 20 120 20 -arrow both -width 5 $c create line 20 80 150 80 20 200 150 200 -smooth yes diff --git a/tests/canvPsImg.tcl b/tests/canvPsImg.tcl index c06aeaa..1f46eca 100644 --- a/tests/canvPsImg.tcl +++ b/tests/canvPsImg.tcl @@ -35,7 +35,7 @@ toplevel .t wm title .t "Postscript Tests for Canvases: Images" wm iconname .t "Postscript" -message .t.m -text {This screen exercises the Postscript-generation abilities of Tk canvas widgets for images. Click the buttons below to select a Visual type for the canvas and colormode for the Postscript output. Then click "Print" to send the results to the default printer, or "Print to file" to put the Postscript output in a file called "/tmp/test.ps". You can also click on items in the canvas to delete them. +message .t.m -text {This screen exercises the Postscript-generation abilities of Tk canvas widgets for images. Click the buttons below to select a Visual type for the canvas and colormode for the Postscript output. Then click "Print" to send the results to the default printer, or "Print to file" to put the Postscript output in a file called "/tmp/test.ps". You can also click on items in the canvas to delete them. NOTE: Some Postscript printers may not be able to handle Postscript generated in color mode.} -width 6i pack .t.m -side top -fill both diff --git a/tests/constraints.tcl b/tests/constraints.tcl index 535d839..6402753 100644 --- a/tests/constraints.tcl +++ b/tests/constraints.tcl @@ -38,7 +38,7 @@ namespace eval tk { } namespace eval bg { - # Manage a background process. + # Manage a background process. # Replace with slave interp or thread? namespace import ::tcltest::interpreter namespace import ::tk::test::loadTkCommand @@ -126,7 +126,7 @@ namespace eval tk { eval destroy [winfo children .] } - namespace export fixfocus + namespace export fixfocus proc fixfocus {} { catch {destroy .focus} toplevel .focus @@ -185,7 +185,7 @@ testConstraint aqua [expr {[tk windowingsystem] eq "aqua"}] testConstraint nonwin [expr {[tk windowingsystem] ne "win32"}] testConstraint userInteraction 0 testConstraint nonUnixUserInteraction [expr { - [testConstraint userInteraction] || + [testConstraint userInteraction] || ([testConstraint unix] && [testConstraint notAqua]) }] testConstraint haveDISPLAY [info exists env(DISPLAY)] -- cgit v0.12 From 57e8fb13bcd2a96f3d4eb84599dffc8d31cc5be4 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 22 Jan 2015 19:18:52 +0000 Subject: Stop `make test` segfaults. --- generic/tkTextDisp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 7422fd1..3c98178 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -3892,8 +3892,17 @@ RedisplayText( { register TkText *textPtr = (TkText *) clientData; TextDInfo *dInfoPtr = textPtr->dInfoPtr; - TkRegion damageRegion = TkCreateRegion(); - XRectangle rectangle = {0, 0, dInfoPtr->maxX, dInfoPtr->maxY}; + TkRegion damageRegion; + XRectangle rectangle; + + if (dInfoPtr == NULL) { + return; + } + damageRegion = TkCreateRegion(); + rectangle.x = 0; + rectangle.y = 0; + rectangle.width = dInfoPtr->maxX; + rectangle.height = dInfoPtr->maxY; TkUnionRectWithRegion(&rectangle, damageRegion, damageRegion); TextInvalidateRegion(textPtr, damageRegion); -- cgit v0.12 From ca14184dca42dcaf581cb61ec5917066e8ffdfe3 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 24 Jan 2015 16:36:32 +0000 Subject: Commiting HITheme implementation on buttons; deferring scrolling for now because no adequate solution, even using themed scrolling via ttk, exists --- macosx/tkMacOSXButton.c | 2044 +++++++++++++++++++++---------------------- macosx/tkMacOSXDraw.c | 22 - macosx/tkMacOSXMenubutton.c | 997 ++++++++++++++------- macosx/tkMacOSXPrivate.h | 3 - 4 files changed, 1696 insertions(+), 1370 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 64a05d6..6cb4f56 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -5,12 +5,14 @@ * button widgets. * * Copyright (c) 1996-1997 by Sun Microsystems, Inc. - * Copyright 2001-2009, Apple Inc. - * Copyright (c) 2006-2009 Daniel A. Steffen - * Copyright 2014 Marc Culler. + * Copyright 2001, Apple Computer, Inc. + * Copyright (c) 2006-2007 Daniel A. Steffen + * Copyright 2007 Revar Desmera. + * Copyright 2015 Kevin Walzer/WordTech Communications LLC. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * */ #include "tkMacOSXPrivate.h" @@ -18,119 +20,82 @@ #include "tkMacOSXFont.h" #include "tkMacOSXDebug.h" -/* -#ifdef TK_MAC_DEBUG -#define TK_MAC_DEBUG_BUTTON -#endif -*/ -static NSRect TkMacOSXGetButtonFrame(TkButton *butPtr); +#define FIRST_DRAW 2 +#define ACTIVE 4 + /* - * A subclass of NSButton with sanity checking: - * NSButtons created by Tk will have their tag set to a pointer to the TkButton - * which manages the NSButton. This allows a TkNSButton to be aware of the - * state of its Tk parent. This subclass overrides the drawRect method - * so that it will not draw itself unless the NSButton frame matches - * the frame which was installed by DisplayButton, and the TkButton is - * mapped. Also, it will not draw anything if the widget is completely - * outside of its container. + * Default insets for controls */ -@interface TkNSButton: NSButton -- (void)drawRect:(NSRect)dirtyRect; -@end - -@implementation TkNSButton - - - (void)drawRect:(NSRect)dirtyRect - { - NSInteger tag = [self tag]; - if ( tag != -1) { - TkButton *butPtr = (TkButton *)tag; - MacDrawable* macWin = (MacDrawable *)butPtr; - NSRect Tkframe = TkMacOSXGetButtonFrame(butPtr); - Tk_Window tkwin = butPtr->tkwin; - /* Do not draw if the widget is misplaced or unmapped. */ - if ( NSIsEmptyRect(Tkframe) || - ! macWin->winPtr->flags & TK_MAPPED || - ! NSEqualRects(Tkframe, [self frame]) - ) { - return; - } - /* Do not draw if the widget is completely outside of its parent, or within 20 pixels of the lower border; this prevents buttons from being drawn on peer widgets as scrolling occurs. */ - if (tkwin) { - int parent_height = Tk_Height(Tk_Parent(tkwin)); - int widget_height = Tk_Height(tkwin); - int y = Tk_Y(tkwin); - if ( y > parent_height - 20 || y + widget_height < 0 ) { - return; - } +#define DEF_INSET_LEFT 2 +#define DEF_INSET_RIGHT 2 +#define DEF_INSET_TOP 2 +#define DEF_INSET_BOTTOM 4 - /* Do not draw if the widget is completely outside of its parent, or within 20 pixels of the right border; this prevents buttons from being drawn on peer widgets as scrolling occurs. */ - int parent_width = Tk_Width(Tk_Parent(tkwin)); - int widget_width = Tk_Width(tkwin); - int x = Tk_X(tkwin); - if (x > parent_width - 20 || x < 0) { - return; - } - } +/* + * Some defines used to control what type of control is drawn. + */ - [super drawRect:dirtyRect]; - } - } +#define DRAW_LABEL 0 /* Labels are treated genericly. */ +#define DRAW_CONTROL 1 /* Draw using the Native control. */ +#define DRAW_CUSTOM 2 /* Make our own button drawing. */ +#define DRAW_BEVEL 3 -@end +/* + * The delay in milliseconds between pulsing default button redraws. + */ +#define PULSE_TIMER_MSECS 62 /* Largest value that didn't look stuttery */ +/* + * Declaration of Mac specific button structure. + */ -typedef struct MacButton { - TkButton info; - TkNSButton *button; - NSImage *image, *selectImage, *tristateImage; -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - int fix; -#endif -} MacButton; -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS +typedef struct { + int drawType; + Tk_3DBorder border; + int relief; + int offset; /* 0 means this is a normal widget. 1 means + * it is an image button, so we offset the + * image to make the button appear to move + * up and down as the relief changes. */ + GC gc; + int hasImageOrBitmap; +} DrawParams; -int tkMacOSXUseCompatibilityMetrics = 1; +typedef struct { + TkButton info; /* Generic button info */ + int id; + int usingControl; + int useTkText; + int flags; /* Initialisation status */ + ThemeButtonKind btnkind; + HIThemeButtonDrawInfo drawinfo; + HIThemeButtonDrawInfo lastdrawinfo; + DrawParams drawParams; + Tcl_TimerToken defaultPulseHandler; +} MacButton; /* - * Use the following heuristic conversion constants to make NSButton-based - * widget metrics match up with the old Carbon control buttons (for the - * default Lucida Grande 13 font). + * Forward declarations for procedures defined later in this file: */ -#define NATIVE_BUTTON_INSET 2 -#define NATIVE_BUTTON_EXTRA_H 2 -typedef struct { - int trimW, trimH, inset, shrinkH, offsetX, offsetY; -} BoundsFix; - -#define fixForTypeStyle(type, style) ( \ - type == NSSwitchButton ? 0 : \ - type == NSRadioButton ? 1 : \ - style == NSRoundedBezelStyle ? 2 : \ - style == NSRegularSquareBezelStyle ? 3 : \ - style == NSShadowlessSquareBezelStyle ? 4 : \ - INT_MIN) - -static const BoundsFix boundsFixes[] = { - [fixForTypeStyle(NSSwitchButton,0)] = { 2, 2, -1, 0, 2, 1 }, - [fixForTypeStyle(NSRadioButton,0)] = { 0, 2, -1, 0, 1, 1 }, - [fixForTypeStyle(0,NSRoundedBezelStyle)] = { 28, 16, -6, 0, 0, 3 }, - [fixForTypeStyle(0,NSRegularSquareBezelStyle)] = { 28, 15, -2, -1 }, - [fixForTypeStyle(0,NSShadowlessSquareBezelStyle)] = { 2, 2 }, -}; +static void ButtonBackgroundDrawCB (const HIRect *btnbounds, MacButton *ptr, + SInt16 depth, Boolean isColorDev); +static void ButtonContentDrawCB (const HIRect *bounds, ThemeButtonKind kind, + const HIThemeButtonDrawInfo *info, MacButton *ptr, SInt16 depth, + Boolean isColorDev); +static void ButtonEventProc(ClientData clientData, XEvent *eventPtr); +static void TkMacOSXComputeButtonParams (TkButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo* drawinfo); +static int TkMacOSXComputeButtonDrawParams (TkButton * butPtr, DrawParams * dpPtr); +static void TkMacOSXDrawButton (MacButton *butPtr, + GC gc, Pixmap pixmap); +static void DrawButtonImageAndText(TkButton* butPtr); +static void PulseDefaultButtonProc(ClientData clientData); -#endif - -static void DisplayNativeButton(TkButton *butPtr); -static void ComputeNativeButtonGeometry(TkButton *butPtr); -static void DisplayUnixButton(TkButton *butPtr); -static void ComputeUnixButtonGeometry(TkButton *butPtr); /* * The class procedure table for the button widgets. @@ -139,68 +104,67 @@ static void ComputeUnixButtonGeometry(TkButton *butPtr); const Tk_ClassProcs tkpButtonProcs = { sizeof(Tk_ClassProcs), /* size */ TkButtonWorldChanged, /* worldChangedProc */ - NULL, /* createProc */ - NULL /* modalProc */ }; - +static int bCount; + /* *---------------------------------------------------------------------- * - * TkpCreateButton -- + * TkpButtonSetDefaults -- * - * Allocate a new TkButton structure. + * This procedure is invoked before option tables are created for + * buttons. It modifies some of the default values to match the current + * values defined for this platform. * * Results: - * Returns a newly allocated TkButton structure. + * Some of the default values in *specPtr are modified. * * Side effects: - * Registers an event handler for the widget. + * Updates some of. * *---------------------------------------------------------------------- */ -TkButton * -TkpCreateButton( - Tk_Window tkwin) +void +TkpButtonSetDefaults() { - MacButton *macButtonPtr = ckalloc(sizeof(MacButton)); - - macButtonPtr->button = nil; - macButtonPtr->image = nil; - macButtonPtr->selectImage = nil; - macButtonPtr->tristateImage = nil; - - return (TkButton *) macButtonPtr; +/*No-op.*/ } + /* *---------------------------------------------------------------------- * - * TkpDestroyButton -- + * TkpCreateButton -- * - * Free data structures associated with the button control. + * Allocate a new TkButton structure. * * Results: - * None. + * Returns a newly allocated TkButton structure. * * Side effects: - * Restores the default control state. + * Registers an event handler for the widget. * *---------------------------------------------------------------------- */ -void -TkpDestroyButton( - TkButton *butPtr) +TkButton * +TkpCreateButton( + Tk_Window tkwin) { - MacButton *macButtonPtr = (MacButton *) butPtr; - [macButtonPtr->button setTag:(NSInteger)-1]; - - TkMacOSXMakeCollectableAndRelease(macButtonPtr->button); - TkMacOSXMakeCollectableAndRelease(macButtonPtr->image); - TkMacOSXMakeCollectableAndRelease(macButtonPtr->selectImage); - TkMacOSXMakeCollectableAndRelease(macButtonPtr->tristateImage); + MacButton *macButtonPtr = (MacButton *) ckalloc(sizeof(MacButton)); + + Tk_CreateEventHandler(tkwin, ActivateMask, + ButtonEventProc, (ClientData) macButtonPtr); + macButtonPtr->id = bCount++; + macButtonPtr->flags = FIRST_DRAW; + macButtonPtr->btnkind = kThemePushButton; + macButtonPtr->defaultPulseHandler = NULL; + bzero(&macButtonPtr->drawinfo, sizeof(macButtonPtr->drawinfo)); + bzero(&macButtonPtr->lastdrawinfo, sizeof(macButtonPtr->lastdrawinfo)); + + return (TkButton *)macButtonPtr; } /* @@ -225,63 +189,63 @@ void TkpDisplayButton( ClientData clientData) /* Information about widget. */ { + MacButton *macButtonPtr = (MacButton *) clientData; TkButton *butPtr = (TkButton *) clientData; + Tk_Window tkwin = butPtr->tkwin; + Pixmap pixmap; + DrawParams* dpPtr = &macButtonPtr->drawParams; + int needhighlight = 0; butPtr->flags &= ~REDRAW_PENDING; - if (!butPtr->tkwin || !Tk_IsMapped(butPtr->tkwin)) { + if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } + pixmap = (Pixmap) Tk_WindowId(tkwin); + TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin)); - switch (butPtr->type) { - case TYPE_LABEL: - DisplayUnixButton(butPtr); - break; - case TYPE_BUTTON: - case TYPE_CHECK_BUTTON: - case TYPE_RADIO_BUTTON: - DisplayNativeButton(butPtr); - break; + if (TkMacOSXComputeButtonDrawParams(butPtr, dpPtr) ) { + macButtonPtr->useTkText = 0; + } else { + macButtonPtr->useTkText = 1; } -} - -/* - *---------------------------------------------------------------------- - * - * TkpShiftButton -- - * - * Moves the frame of an NSButton (or TkNSButton) and in case the tag is - * set, also adjusts the xOff and yOff of the controlling TkButton's - * MacDrawable. This is used to avoid jitter when scrolling. - * - * Results: - * None - * - * Side effects: - * Moves the NSbutton after adjusting the associated MacDrawable. - * - *---------------------------------------------------------------------- - */ -void -TkpShiftButton( - NSButton *button, - NSPoint delta ) - { - NSPoint origin = [button frame].origin; - NSInteger tag = [button tag]; - if ( tag != -1) { - TkButton* butPtr = (TkButton *)tag; - TkWindow *winPtr = (TkWindow *) (butPtr->tkwin); - if (winPtr) { - MacDrawable *macWin = (MacDrawable *) winPtr->window; - macWin->xOff += delta.x; - macWin->yOff += delta.y; - } + + + /* + * Set up clipping region. Make sure the we are using the port + * for this button, or we will set the wrong window's clip. + */ + + if (macButtonPtr->useTkText) { + if (butPtr->type == TYPE_BUTTON) { + Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); + } else { + Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); } - origin.x += delta.x; - origin.y -= delta.y; - [button setFrameOrigin:origin]; + + /* Display image or bitmap or text for labels or custom controls. */ + DrawButtonImageAndText(butPtr); + needhighlight = 1; + } else { + /* Draw the native portion of the buttons. */ + TkMacOSXDrawButton(macButtonPtr, dpPtr->gc, pixmap); + + /* Draw highlight border, if needed. */ + if (butPtr->highlightWidth < 3) { + needhighlight = 1; + } } + /* Draw highlight border, if needed. */ + if (needhighlight) { + if ((butPtr->flags & GOT_FOCUS)) { + Tk_Draw3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), + butPtr->highlightWidth, TK_RELIEF_SOLID); + } + } +} /* *---------------------------------------------------------------------- @@ -300,1015 +264,1017 @@ TkpShiftButton( * *---------------------------------------------------------------------- */ - + void TkpComputeButtonGeometry( - register TkButton *butPtr) /* Button whose geometry may have changed. */ + TkButton *butPtr) /* Button whose geometry may have changed. */ { - MacButton *macButtonPtr = (MacButton *) butPtr; + int width, height, avgWidth, haveImage = 0, haveText = 0; + int txtWidth, txtHeight; + MacButton *mbPtr = (MacButton*)butPtr; + Tk_FontMetrics fm; + DrawParams drawParams; - switch (butPtr->type) { - case TYPE_LABEL: - if (macButtonPtr->button && [macButtonPtr->button superview]) { - [macButtonPtr->button removeFromSuperviewWithoutNeedingDisplay]; - } - ComputeUnixButtonGeometry(butPtr); + /* + * First figure out the size of the contents of the button. + */ + + width = 0; + height = 0; + txtWidth = 0; + txtHeight = 0; + avgWidth = 0; + + TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); + + butPtr->indicatorSpace = 0; + if (butPtr->image != NULL) { + Tk_SizeOfImage(butPtr->image, &width, &height); + haveImage = 1; + } else if (butPtr->bitmap != None) { + Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); + haveImage = 1; + } + + /*Tk Aqua can't handle metrics for radiobuttons and checkbuttons with images unless they are set first. These are derived from experimentation.*/ + if (haveImage && !haveText) { + switch (butPtr->type) { + case TYPE_RADIO_BUTTON: + width = butPtr->width; + width +=50; break; - case TYPE_BUTTON: - case TYPE_CHECK_BUTTON: + case TYPE_CHECK_BUTTON: + width = butPtr->width; + width += 50; + break; + case TYPE_BUTTON: + width = butPtr->width; + width += 0; + break; + } + } + + if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) { + Tk_FreeTextLayout(butPtr->textLayout); + butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, + Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, + butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); + + txtWidth = butPtr->textWidth; + txtHeight = butPtr->textHeight; + avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); + Tk_GetFontMetrics(butPtr->tkfont, &fm); + haveText = (txtWidth != 0 && txtHeight != 0); + } + + /* + * If the button is compound (ie, it shows both an image and text), + * the new geometry is a combination of the image and text geometry. + * We only honor the compound bit if the button has both text and an + * image, because otherwise it is not really a compound button. + */ + + if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { + switch ((enum compound) butPtr->compound) { + case COMPOUND_TOP: + case COMPOUND_BOTTOM: + /* + * Image is above or below text. + */ + + height += txtHeight + butPtr->padY; + width = (width > txtWidth ? width : txtWidth); + break; + case COMPOUND_LEFT: + case COMPOUND_RIGHT: + /* + * Image is left or right of text. + */ + + width += txtWidth + butPtr->padX; + height = (height > txtHeight ? height : txtHeight); + break; + case COMPOUND_CENTER: + /* + * Image and text are superimposed. + */ + + width = (width > txtWidth ? width : txtWidth); + height = (height > txtHeight ? height : txtHeight); + break; + case COMPOUND_NONE: + break; + } + if (butPtr->width > 0) { + width = butPtr->width; + } + if (butPtr->height > 0) { + height = butPtr->height; + } + + } else if (haveImage) { + + if (butPtr->width > 0) { + width = butPtr->width; + } + if (butPtr->height > 0) { + height = butPtr->height; + } + + } else { + width = txtWidth; + height = txtHeight; + + if (butPtr->width > 0) { + width = butPtr->width * avgWidth; + } + if (butPtr->height > 0) { + height = butPtr->height * fm.linespace; + } + } + + width += 2 * butPtr->padX; + height += 2 * butPtr->padY; + + + /* Need special handling for radiobuttons and checkbuttons: the text is drawn right on top of the button unless we expand the width. This is not perfect; some radiobuttons may render on top anyway. Need to find a better solution to calculate average text width.*/ + switch (butPtr->type) { case TYPE_RADIO_BUTTON: - if (!macButtonPtr->button) { - TkNSButton *button = [[TkNSButton alloc] initWithFrame:NSZeroRect]; - [button setTag:(NSInteger)butPtr]; - macButtonPtr->button = TkMacOSXMakeUncollectable(button); + width += 50; + break; + case TYPE_CHECK_BUTTON: + width += 50; + break; + } + + /* + * Now figure out the size of the border decorations for the button. + */ + + if (butPtr->highlightWidth < 0) { + butPtr->highlightWidth = 0; + } + + butPtr->inset = 0; + butPtr->inset += butPtr->highlightWidth; + + if (TkMacOSXComputeButtonDrawParams(butPtr,&drawParams)) { + + + HIRect tmpRect; + HIRect contBounds; + int paddingx = 0; + int paddingy = 0; + + tmpRect = CGRectMake(0, 0, width, height); + + + HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds); + + + /* If the content region has a minimum height, match it. */ + if (height < contBounds.size.height) { + height = contBounds.size.height; + } + + /* If the content region has a minimum width, match it. */ + if (width < contBounds.size.width) { + width = contBounds.size.width; + } + + /* Pad to fill difference between content bounds and button bounds. */ + paddingx = tmpRect.origin.x - contBounds.origin.x; + paddingy = tmpRect.origin.y - contBounds.origin.y; + if (paddingx > 0) { + width += paddingx; + } + if (paddingy > 0) { + height += paddingy; + } + + if (height < paddingx - 4) { + /* can't have buttons much shorter than button side diameter. */ + height = paddingx - 4; } - ComputeNativeButtonGeometry(butPtr); - break; + + } else { + height += butPtr->borderWidth*2; + width += butPtr->borderWidth*2; } + + width += butPtr->inset*2; + height += butPtr->inset*2; + + Tk_GeometryRequest(butPtr->tkwin, width, height); + Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); + } - + +/* /* *---------------------------------------------------------------------- * - * TkpButtonSetDefaults -- + * DrawButtonImageAndText -- * - * This procedure is invoked before option tables are created for - * buttons. It modifies some of the default values to match the current - * values defined for this platform. + * Draws the image and text associated with a button or label. * * Results: - * Some of the default values in *specPtr are modified. + * None. * * Side effects: - * Updates some of. + * The image and text are drawn. * *---------------------------------------------------------------------- */ - -void -TkpButtonSetDefaults() +static void +DrawButtonImageAndText( + TkButton* butPtr) { -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - if (!tkMacOSXUseCompatibilityMetrics) { - strcpy(tkDefButtonHighlightWidth, DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM); - strcpy(tkDefLabelHighlightWidth, DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM); - strcpy(tkDefButtonPadx, DEF_BUTTON_PADX_NOCM); - strcpy(tkDefLabelPadx, DEF_BUTTON_PADX_NOCM); - strcpy(tkDefButtonPady, DEF_BUTTON_PADY_NOCM); - strcpy(tkDefLabelPady, DEF_BUTTON_PADY_NOCM); + + MacButton *mbPtr = (MacButton*)butPtr; + Tk_Window tkwin = butPtr->tkwin; + Pixmap pixmap; + int haveImage = 0; + int haveText = 0; + int imageWidth = 0; + int imageHeight = 0; + int imageXOffset = 0; + int imageYOffset = 0; + int textXOffset = 0; + int textYOffset = 0; + int width = 0; + int height = 0; + int fullWidth = 0; + int fullHeight = 0; + int pressed = 0; + + + if (tkwin == NULL || !Tk_IsMapped(tkwin)) { + return; } -#endif -} -#pragma mark - -#pragma mark Native Buttons: + DrawParams* dpPtr = &mbPtr->drawParams; + pixmap = (Pixmap)Tk_WindowId(tkwin); + + if (butPtr->image != None) { + Tk_SizeOfImage(butPtr->image, &width, &height); + haveImage = 1; + } else if (butPtr->bitmap != None) { + Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); + haveImage = 1; + } + + imageWidth = width; + imageHeight = height; + + if (mbPtr->drawinfo.state == kThemeStatePressed) { + /* Offset bitmaps by a bit when the button is pressed. */ + pressed = 1; + } + + haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); + if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { + int x; + int y; + textXOffset = 0; + textYOffset = 0; + fullWidth = 0; + fullHeight = 0; + + switch ((enum compound) butPtr->compound) { + case COMPOUND_TOP: + case COMPOUND_BOTTOM: { + /* Image is above or below text */ + if (butPtr->compound == COMPOUND_TOP) { + textYOffset = height + butPtr->padY; + } else { + imageYOffset = butPtr->textHeight + butPtr->padY; + } + fullHeight = height + butPtr->textHeight + butPtr->padY; + fullWidth = (width > butPtr->textWidth ? width : + butPtr->textWidth); + textXOffset = (fullWidth - butPtr->textWidth)/2; + imageXOffset = (fullWidth - width)/2; + break; + } + case COMPOUND_LEFT: + case COMPOUND_RIGHT: { + /* + * Image is left or right of text + */ + + if (butPtr->compound == COMPOUND_LEFT) { + textXOffset = width + butPtr->padX; + } else { + imageXOffset = butPtr->textWidth + butPtr->padX; + } + fullWidth = butPtr->textWidth + butPtr->padX + width; + fullHeight = (height > butPtr->textHeight ? height : + butPtr->textHeight); + textYOffset = (fullHeight - butPtr->textHeight)/2; + imageYOffset = (fullHeight - height)/2; + break; + } + case COMPOUND_CENTER: { + /* + * Image and text are superimposed + */ + + fullWidth = (width > butPtr->textWidth ? width : + butPtr->textWidth); + fullHeight = (height > butPtr->textHeight ? height : + butPtr->textHeight); + textXOffset = (fullWidth - butPtr->textWidth)/2; + imageXOffset = (fullWidth - width)/2; + textYOffset = (fullHeight - butPtr->textHeight)/2; + imageYOffset = (fullHeight - height)/2; + break; + } + case COMPOUND_NONE: {break;} + } + TkComputeAnchor(butPtr->anchor, tkwin, + butPtr->padX + butPtr->borderWidth, + butPtr->padY + butPtr->borderWidth, + fullWidth, fullHeight, &x, &y); + if (dpPtr->relief == TK_RELIEF_SUNKEN) { + x += dpPtr->offset; + y += dpPtr->offset; + } else if (dpPtr->relief == TK_RELIEF_RAISED) { + x -= dpPtr->offset; + y -= dpPtr->offset; + } + if (pressed) { + x += dpPtr->offset; + y += dpPtr->offset; + } + imageXOffset += x; + imageYOffset += y; + textYOffset -= 1; + + if (butPtr->image != NULL) { + if ((butPtr->selectImage != NULL) && + (butPtr->flags & SELECTED)) { + Tk_RedrawImage(butPtr->selectImage, 0, 0, + width, height, pixmap, imageXOffset, imageYOffset); + } else if ((butPtr->tristateImage != NULL) && + (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, + width, height, pixmap, imageXOffset, imageYOffset); + } else { + Tk_RedrawImage(butPtr->image, 0, 0, width, + height, pixmap, imageXOffset, imageYOffset); + } + } else { + XSetClipOrigin(butPtr->display, dpPtr->gc, + imageXOffset, imageYOffset); + XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc, + 0, 0, (unsigned int) width, (unsigned int) height, + imageXOffset, imageYOffset, 1); + XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); + } + + Tk_DrawTextLayout(butPtr->display, pixmap, + dpPtr->gc, butPtr->textLayout, + x + textXOffset, y + textYOffset, 0, -1); + Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc, + butPtr->textLayout, + x + textXOffset, y + textYOffset, + butPtr->underline); + } else { + if (haveImage) { + int x = 0; + int y; + TkComputeAnchor(butPtr->anchor, tkwin, + butPtr->padX + butPtr->borderWidth, + butPtr->padY + butPtr->borderWidth, + width, height, &x, &y); + if (dpPtr->relief == TK_RELIEF_SUNKEN) { + x += dpPtr->offset; + y += dpPtr->offset; + } else if (dpPtr->relief == TK_RELIEF_RAISED) { + x -= dpPtr->offset; + y -= dpPtr->offset; + } + if (pressed) { + x += dpPtr->offset; + y += dpPtr->offset; + } + imageXOffset += x; + imageYOffset += y; + + if (butPtr->image != NULL) { + + if ((butPtr->selectImage != NULL) && + (butPtr->flags & SELECTED)) { + Tk_RedrawImage(butPtr->selectImage, 0, 0, width, + height, pixmap, imageXOffset, imageYOffset); + } else if ((butPtr->tristateImage != NULL) && + (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, + height, pixmap, imageXOffset, imageYOffset); + } else { + Tk_RedrawImage(butPtr->image, 0, 0, width, height, + pixmap, imageXOffset, imageYOffset); + } + } else { + XSetClipOrigin(butPtr->display, dpPtr->gc, x, y); + XCopyPlane(butPtr->display, butPtr->bitmap, + pixmap, dpPtr->gc, + 0, 0, (unsigned int) width, + (unsigned int) height, + imageXOffset, imageYOffset, 1); + XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); + } + } else { + /*Adequate padding / offset for text in various buttons.*/ + int x = 0; + int y; + switch (butPtr->type) { + case TYPE_RADIO_BUTTON: + case TYPE_CHECK_BUTTON: + if (butPtr->indicatorOn) { + TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, + butPtr->textWidth, butPtr->textHeight, &x, &y); + Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, + butPtr->textLayout, x + 20, y, 0, -1); + } else { + TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, + butPtr->textWidth, butPtr->textHeight, &x, &y); + Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, + butPtr->textLayout, x, y, 0, -1); + } + break; + case TYPE_BUTTON: + case TYPE_LABEL: + TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, + butPtr->textWidth, butPtr->textHeight, &x, &y); + Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, + butPtr->textLayout, x, y, 0, -1); + y += butPtr->textHeight/2; + break; + } + } + } + + + /* + * If the button is disabled with a stipple rather than a special + * foreground color, generate the stippled effect. If the widget + * is selected and we use a different background color when selected, + * must temporarily modify the GC so the stippling is the right color. + */ + + if (mbPtr->useTkText) { + if ((butPtr->state == STATE_DISABLED) + && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) { + if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn + && (butPtr->selectBorder != NULL)) { + XSetForeground(butPtr->display, butPtr->stippleGC, + Tk_3DBorderColor(butPtr->selectBorder)->pixel); + } + /* + * Stipple the whole button if no disabledFg was specified, + * otherwise restrict stippling only to displayed image + */ + if (butPtr->disabledFg == NULL) { + XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC, + 0, 0, (unsigned) Tk_Width(tkwin), + (unsigned) Tk_Height(tkwin)); + } else { + XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC, + imageXOffset, imageYOffset, + (unsigned) imageWidth, (unsigned) imageHeight); + } + if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn + && (butPtr->selectBorder != NULL) + ) { + XSetForeground(butPtr->display, butPtr->stippleGC, + Tk_3DBorderColor(butPtr->normalBorder)->pixel); + } + } + + /* + * Draw the border and traversal highlight last. This way, if the + * button's contents overflow they'll be covered up by the border. + */ + + if (dpPtr->relief != TK_RELIEF_FLAT) { + int inset = butPtr->highlightWidth; + Tk_Draw3DRectangle(tkwin, pixmap, dpPtr->border, inset, inset, + Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset, + butPtr->borderWidth, dpPtr->relief); + } + } + + } + + + - /* *---------------------------------------------------------------------- * - * TkMacOSXGetButtonFrame -- + * TkpDestroyButton -- * - * Computes a frame for an NSButton that will correspond to where - * Tk thinks the button is located. + * Free data structures associated with the button control. * * Results: - * Returns an NSRect describing a frame for an NSButton. + * None. * * Side effects: - * None + * Restores the default control state. * *---------------------------------------------------------------------- */ -NSRect TkMacOSXGetButtonFrame( - TkButton *butPtr) -{ - MacButton *macButtonPtr = (MacButton *) butPtr; - Tk_Window tkwin = butPtr->tkwin; - TkWindow *winPtr = (TkWindow *) tkwin; - if (tkwin) { - MacDrawable *macWin = (MacDrawable *) winPtr->window; - NSView *view = TkMacOSXDrawableView(macWin); - CGFloat viewHeight = [view bounds].size.height; - NSRect frame = NSMakeRect(macWin->xOff, macWin->yOff, - Tk_Width(tkwin), Tk_Height(tkwin)); - -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - if (tkMacOSXUseCompatibilityMetrics) { - BoundsFix boundsFix = boundsFixes[macButtonPtr->fix]; - frame = NSOffsetRect(frame, boundsFix.offsetX, boundsFix.offsetY); - frame.size.height -= boundsFix.shrinkH + NATIVE_BUTTON_EXTRA_H; - frame = NSInsetRect(frame, boundsFix.inset + NATIVE_BUTTON_INSET, - boundsFix.inset + NATIVE_BUTTON_INSET); - } -#endif - frame.origin.y = viewHeight - (frame.origin.y + frame.size.height); - return frame; - } else { - return NSZeroRect; +void +TkpDestroyButton( + TkButton *butPtr) +{ + MacButton *mbPtr = (MacButton *) butPtr; /* Mac button. */ + if (mbPtr->defaultPulseHandler) { + Tcl_DeleteTimerHandler(mbPtr->defaultPulseHandler); } } /* - *---------------------------------------------------------------------- + *-------------------------------------------------------------- * - * DisplayNativeButton -- + * TkMacOSXDrawButton -- * - * This procedure is invoked to display a button widget. It is - * normally invoked as an idle handler. + * This function draws the tk button using Mac controls + * In addition, this code may apply custom colors passed + * in the TkButton. * * Results: - * None. + * None. * * Side effects: - * Commands are output to X to display the button in its - * current mode. The REDRAW_PENDING flag is cleared. + * The control is created, or reinitialised as needed * - *---------------------------------------------------------------------- + *-------------------------------------------------------------- */ static void -DisplayNativeButton( - TkButton *butPtr) +TkMacOSXDrawButton( + MacButton *mbPtr, /* Mac button. */ + GC gc, /* The GC we are drawing into - needed for + * the bevel button */ + Pixmap pixmap) /* The pixmap we are drawing into - needed + * for the bevel button */ { - MacButton *macButtonPtr = (MacButton *) butPtr; - TkNSButton *button = macButtonPtr->button; - Tk_Window tkwin = butPtr->tkwin; - TkWindow *winPtr = (TkWindow *) tkwin; - MacDrawable *macWin = (MacDrawable *) winPtr->window; + TkButton * butPtr = ( TkButton *)mbPtr; + TkWindow * winPtr; + HIRect cntrRect; TkMacOSXDrawingContext dc; - NSView *view = TkMacOSXDrawableView(macWin); - CGFloat viewHeight = [view bounds].size.height; - CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, - .ty = viewHeight}; - NSRect frame; - int enabled; - NSCellStateValue state; - - if (!view || - !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { - return; - } - CGContextConcatCTM(dc.context, t); + DrawParams* dpPtr = &mbPtr->drawParams; + int useNewerHITools = 1; + + winPtr = (TkWindow *)butPtr->tkwin; - /* - * We cannot change the background color of the button itself, only the - * color of the background of its container. - * This will be the color that peeks around the rounded corners of the - * button. We make this the highlightbackground rather than the background, - * because if you color the background of a frame containing a - * button, you usually also color the highlightbackground as well, - * or you will get a thin grey ring around the button. - */ + TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); + + cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin),Tk_Height(butPtr->tkwin)); + + cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset); + + if (useNewerHITools == 1) { + HIRect contHIRec; + static HIThemeButtonDrawInfo hiinfo; + + ButtonBackgroundDrawCB(&cntrRect, mbPtr, 32, true); + + if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { + return; + } + + + if (mbPtr->btnkind == kThemePushButton) { + /* + * For some reason, pushbuttons get drawn a bit + * too low, normally. Correct for this. + */ + if (cntrRect.size.height < 22) { + cntrRect.origin.y -= 1; + } else if (cntrRect.size.height < 23) { + cntrRect.origin.y -= 2; + } + } + + hiinfo.version = 0; + hiinfo.state = mbPtr->drawinfo.state; + hiinfo.kind = mbPtr->btnkind; + hiinfo.value = mbPtr->drawinfo.value; + hiinfo.adornment = mbPtr->drawinfo.adornment; + hiinfo.animation.time.current = CFAbsoluteTimeGetCurrent(); + if (hiinfo.animation.time.start == 0) { + hiinfo.animation.time.start = hiinfo.animation.time.current; + } + + HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); + + TkMacOSXRestoreDrawingContext(&dc); + + ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, (MacButton *)mbPtr, 32, true); - Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, butPtr->type == TYPE_BUTTON ? - butPtr->highlightBorder : butPtr->normalBorder, 0, 0, - Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); - if ([button superview] != view) { - [view addSubview:button]; - } - if (macButtonPtr->tristateImage) { - NSImage *selectImage = macButtonPtr->selectImage ? - macButtonPtr->selectImage : macButtonPtr->image; - [button setImage:(butPtr->flags & TRISTATED ? - selectImage : macButtonPtr->image)]; - [button setAlternateImage:(butPtr->flags & TRISTATED ? - macButtonPtr->tristateImage : selectImage)]; - } - if (butPtr->flags & SELECTED) { - state = NSOnState; - } else if (butPtr->flags & TRISTATED) { - state = NSMixedState; - } else { - state = NSOffState; - } - [button setState:state]; - enabled = !(butPtr->state == STATE_DISABLED); - [button setEnabled:enabled]; - if (enabled) { - //[button highlight:(butPtr->state == STATE_ACTIVE)]; - //[cell setHighlighted:(butPtr->state == STATE_ACTIVE)]; - } - if (butPtr->type == TYPE_BUTTON && butPtr->defaultState == STATE_ACTIVE) { - //[[view window] setDefaultButtonCell:cell]; - [button setKeyEquivalent:@"\r"]; } else { - [button setKeyEquivalent:@""]; + if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { + return; + } + + TkMacOSXRestoreDrawingContext(&dc); } - frame = TkMacOSXGetButtonFrame(butPtr); - [button setFrame:frame]; - [button displayRectIgnoringOpacity:[button bounds]]; - TkMacOSXRestoreDrawingContext(&dc); -#ifdef TK_MAC_DEBUG_BUTTON - TKLog(@"button %s frame %@ width %d height %d", - ((TkWindow *)butPtr->tkwin)->pathName, NSStringFromRect(frame), - Tk_Width(tkwin), Tk_Height(tkwin)); -#endif + mbPtr->lastdrawinfo = mbPtr->drawinfo; } /* - *---------------------------------------------------------------------- + *-------------------------------------------------------------- * - * ComputeNativeButtonGeometry -- + * ButtonBackgroundDrawCB -- * - * After changes in a button's text or bitmap, this procedure - * recomputes the button's geometry and passes this information - * along to the geometry manager for the window. + * This function draws the background that + * lies under checkboxes and radiobuttons. * * Results: - * None. + * None. * * Side effects: - * The button's window may change size. + * The background gets updated to the current color. * - *---------------------------------------------------------------------- + *-------------------------------------------------------------- */ - static void -ComputeNativeButtonGeometry( - TkButton *butPtr) /* Button whose geometry may have changed. */ +ButtonBackgroundDrawCB ( + const HIRect * btnbounds, + MacButton *ptr, + SInt16 depth, + Boolean isColorDev) { - MacButton *macButtonPtr = (MacButton *) butPtr; - TkNSButton *button = macButtonPtr->button; - NSButtonCell *cell = [button cell]; - NSButtonType type = -1; - NSBezelStyle style = 0; - NSInteger highlightsBy = 0, showsStateBy = 0; - NSFont *font; - NSRect bounds = NSZeroRect, titleRect = NSZeroRect; - int haveImage = (butPtr->image || butPtr->bitmap != None), haveText = 0; - int haveCompound = (butPtr->compound != COMPOUND_NONE); - int width, height, border = 0; + MacButton* mbPtr = (MacButton*)ptr; + TkButton* butPtr = (TkButton*)mbPtr; + Tk_Window tkwin = butPtr->tkwin; + Pixmap pixmap; + int usehlborder = 0; - butPtr->indicatorSpace = 0; - butPtr->inset = 0; - if (butPtr->highlightWidth < 0) { - butPtr->highlightWidth = 0; + if (tkwin == NULL || !Tk_IsMapped(tkwin)) { + return; } - switch (butPtr->type) { - case TYPE_BUTTON: - type = NSMomentaryPushInButton; - if (!haveImage) { - style = NSRoundedBezelStyle; - butPtr->inset = butPtr->defaultState != STATE_DISABLED ? - butPtr->highlightWidth : 0; - [button setImage:nil]; - [button setImagePosition:NSNoImage]; - } else { - style = NSShadowlessSquareBezelStyle; - highlightsBy = butPtr->selectImage || butPtr->bitmap ? - NSContentsCellMask : 0; - border = butPtr->borderWidth; - } - break; - case TYPE_RADIO_BUTTON: - case TYPE_CHECK_BUTTON: - if (!haveImage /*|| butPtr->indicatorOn*/) { // TODO: indicatorOn - type = butPtr->type == TYPE_RADIO_BUTTON ? - NSRadioButton : NSSwitchButton; - butPtr->inset = /*butPtr->indicatorOn ? 0 :*/ butPtr->borderWidth; - } else { - type = NSPushOnPushOffButton; - style = NSShadowlessSquareBezelStyle; - highlightsBy = butPtr->selectImage || butPtr->bitmap ? - NSContentsCellMask : 0; - showsStateBy = butPtr->selectImage || butPtr->tristateImage ? - NSContentsCellMask : 0; -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - if (tkMacOSXUseCompatibilityMetrics) { - border = butPtr->borderWidth > 1 ? butPtr->borderWidth - 1 : 1; - } else -#endif - { - border = butPtr->borderWidth; - } - } - break; - } - [button setButtonType:type]; - if (style) { - [button setBezelStyle:style]; - } - if (highlightsBy) { - [cell setHighlightsBy:highlightsBy|[cell highlightsBy]]; + pixmap = (Pixmap)Tk_WindowId(tkwin); + + if (butPtr->type != TYPE_LABEL) { + switch (mbPtr->btnkind) { + case kThemeSmallBevelButton: + case kThemeBevelButton: + case kThemeRoundedBevelButton: + case kThemePushButton: + usehlborder = 1; + break; + } } - if (showsStateBy) { - [cell setShowsStateBy:showsStateBy|[cell showsStateBy]]; - } -#if 0 - if (style == NSShadowlessSquareBezelStyle) { - NSControlSize controlSize = NSRegularControlSize; - - if (butPtr->borderWidth <= 2) { - controlSize = NSMiniControlSize; - } else if (butPtr->borderWidth == 3) { - controlSize = NSSmallControlSize; - } - [cell setControlSize:controlSize]; - } -#endif - [button setAllowsMixedState:YES]; - - if (!haveImage || haveCompound) { - int len; - char *text = Tcl_GetStringFromObj(butPtr->textPtr, &len); - - if (len) { - NSString *title = [[NSString alloc] initWithBytes:text length:len - encoding:NSUTF8StringEncoding]; - [button setTitle:title]; - [title release]; - haveText = 1; - } - } - haveCompound = (haveCompound && haveImage && haveText); - if (haveText) { - NSTextAlignment alignment = NSNaturalTextAlignment; - - switch (butPtr->justify) { - case TK_JUSTIFY_LEFT: - alignment = NSLeftTextAlignment; - break; - case TK_JUSTIFY_RIGHT: - alignment = NSRightTextAlignment; - break; - case TK_JUSTIFY_CENTER: - alignment = NSCenterTextAlignment; - break; - } - [button setAlignment:alignment]; + if (usehlborder) { + Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); } else { - [button setTitle:@""]; - } - font = TkMacOSXNSFontForFont(butPtr->tkfont); - if (font) { - [button setFont:font]; - } - TkMacOSXMakeCollectableAndRelease(macButtonPtr->image); - TkMacOSXMakeCollectableAndRelease(macButtonPtr->selectImage); - TkMacOSXMakeCollectableAndRelease(macButtonPtr->tristateImage); - if (haveImage) { - int width, height; - NSImage *image, *selectImage = nil, *tristateImage = nil; - NSCellImagePosition pos = NSImageOnly; - - if (butPtr->image) { - Tk_SizeOfImage(butPtr->image, &width, &height); - image = TkMacOSXGetNSImageWithTkImage(butPtr->display, - butPtr->image, width, height); - if (butPtr->selectImage) { - selectImage = TkMacOSXGetNSImageWithTkImage(butPtr->display, - butPtr->selectImage, width, height); - } - if (butPtr->tristateImage) { - tristateImage = TkMacOSXGetNSImageWithTkImage(butPtr->display, - butPtr->tristateImage, width, height); - } - } else { - Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); - image = TkMacOSXGetNSImageWithBitmap(butPtr->display, - butPtr->bitmap, butPtr->normalTextGC, width, height); - selectImage = TkMacOSXGetNSImageWithBitmap(butPtr->display, - butPtr->bitmap, butPtr->activeTextGC, width, height); - } - [button setImage:image]; - if (selectImage) { - [button setAlternateImage:selectImage]; - } - if (tristateImage) { - macButtonPtr->image = TkMacOSXMakeUncollectableAndRetain(image); - if (selectImage) { - macButtonPtr->selectImage = - TkMacOSXMakeUncollectableAndRetain(selectImage); - } - macButtonPtr->tristateImage = - TkMacOSXMakeUncollectableAndRetain(tristateImage); - } - if (haveCompound) { - switch ((enum compound) butPtr->compound) { - case COMPOUND_TOP: - pos = NSImageAbove; - break; - case COMPOUND_BOTTOM: - pos = NSImageBelow; - break; - case COMPOUND_LEFT: - pos = NSImageLeft; - break; - case COMPOUND_RIGHT: - pos = NSImageRight; - break; - case COMPOUND_CENTER: - pos = NSImageOverlaps; - break; - case COMPOUND_NONE: - pos = NSImageOnly; - break; - } - } - [button setImagePosition:pos]; + Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); } +} + +/* + *-------------------------------------------------------------- + * + * ButtonContentDrawCB -- + * + * This function draws the label and image for the button. + * + * Results: + * None. + * + * Side effects: + * The content of the button gets updated. + * + *-------------------------------------------------------------- + */ +static void +ButtonContentDrawCB ( + const HIRect * btnbounds, + ThemeButtonKind kind, + const HIThemeButtonDrawInfo *drawinfo, + MacButton *ptr, + SInt16 depth, + Boolean isColorDev) +{ + TkButton *butPtr = (TkButton *)ptr; + Tk_Window tkwin = butPtr->tkwin; + HIRect * bounds; - // if font is too tall, we can't use the fixed-height rounded bezel - if (!haveImage && haveText && style == NSRoundedBezelStyle) { - Tk_FontMetrics fm; - Tk_GetFontMetrics(butPtr->tkfont, &fm); - if (fm.linespace > 18) { - [button setBezelStyle:(style = NSShadowlessSquareBezelStyle)]; - } + if (tkwin == NULL || !Tk_IsMapped(tkwin)) { + return; } + MacDrawable *macWin = (MacDrawable *) Tk_WindowId(tkwin); - bounds.size = [cell cellSize]; - if (haveText) { - titleRect = [cell titleRectForBounds:bounds]; - if (butPtr->wrapLength > 0 && - titleRect.size.width > butPtr->wrapLength) { - if (style == NSRoundedBezelStyle) { - [button setBezelStyle:(style = NSRegularSquareBezelStyle)]; - bounds.size = [cell cellSize]; - titleRect = [cell titleRectForBounds:bounds]; - } - bounds.size.width -= titleRect.size.width - butPtr->wrapLength; - bounds.size.height = 40000.0; - [cell setWraps:YES]; - bounds.size = [cell cellSizeForBounds:bounds]; -#ifdef TK_MAC_DEBUG_BUTTON - titleRect = [cell titleRectForBounds:bounds]; -#endif -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - if (tkMacOSXUseCompatibilityMetrics) { - bounds.size.height += 3; - } -#endif - } - } - width = lround(bounds.size.width); - height = lround(bounds.size.height); -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - if (tkMacOSXUseCompatibilityMetrics) { - macButtonPtr->fix = fixForTypeStyle(type, style); - width -= boundsFixes[macButtonPtr->fix].trimW; - height -= boundsFixes[macButtonPtr->fix].trimH; - } -#endif + /*Overlay Tk elements over button native region: drawing elements within button boundaries/native region causes unpredictable metrics.*/ + DrawButtonImageAndText( butPtr); +} + +/* + *-------------------------------------------------------------- + * + * ButtonEventProc -- + * + * This procedure is invoked by the Tk dispatcher for various + * events on buttons. + * + * Results: + * None. + * + * Side effects: + * When it gets exposed, it is redisplayed. + * + *-------------------------------------------------------------- + */ - if (haveImage || haveCompound) { - if (butPtr->width > 0) { - width = butPtr->width; +static void +ButtonEventProc( + ClientData clientData, /* Information about window. */ + XEvent *eventPtr) /* Information about event. */ +{ + TkButton *buttonPtr = (TkButton *) clientData; + MacButton *mbPtr = (MacButton *) clientData; + + if (eventPtr->type == ActivateNotify + || eventPtr->type == DeactivateNotify) { + if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) { + return; } - if (butPtr->height > 0) { - height = butPtr->height; + if (eventPtr->type == ActivateNotify) { + mbPtr->flags |= ACTIVE; + } else { + mbPtr->flags &= ~ACTIVE; } - } else { - if (butPtr->width > 0) { - int avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); - width = butPtr->width * avgWidth; + if ((buttonPtr->flags & REDRAW_PENDING) == 0) { + Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) buttonPtr); + buttonPtr->flags |= REDRAW_PENDING; } - if (butPtr->height > 0) { - Tk_FontMetrics fm; - - Tk_GetFontMetrics(butPtr->tkfont, &fm); - height = butPtr->height * fm.linespace; - } - } - if (!haveImage || haveCompound) { - width += 2*butPtr->padX; - height += 2*butPtr->padY; - } - if (haveImage) { - width += 2*border; - height += 2*border; } -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - if (tkMacOSXUseCompatibilityMetrics) { - width += 2*NATIVE_BUTTON_INSET; - height += 2*NATIVE_BUTTON_INSET + NATIVE_BUTTON_EXTRA_H; - } -#endif - Tk_GeometryRequest(butPtr->tkwin, width, height); - Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); -#ifdef TK_MAC_DEBUG_BUTTON - TKLog(@"button %s bounds %@ titleRect %@ width %d height %d inset %d borderWidth %d", - ((TkWindow *)butPtr->tkwin)->pathName, NSStringFromRect(bounds), - NSStringFromRect(titleRect), width, height, butPtr->inset, - butPtr->borderWidth); -#endif } - -#pragma mark - -#pragma mark Unix Buttons: - /* *---------------------------------------------------------------------- * - * DisplayUnixButton -- + * TkMacOSXComputeButtonParams -- * - * This procedure is invoked to display a button widget. It is - * normally invoked as an idle handler. + * This procedure computes the various parameters used + * when creating a Carbon Appearance control. + * These are determined by the various tk button parameters * * Results: * None. * * Side effects: - * Commands are output to X to display the button in its - * current mode. The REDRAW_PENDING flag is cleared. + * Sets the btnkind and drawinfo parameters * *---------------------------------------------------------------------- */ -void -DisplayUnixButton( - TkButton *butPtr) +static void +TkMacOSXComputeButtonParams( + TkButton * butPtr, + ThemeButtonKind* btnkind, + HIThemeButtonDrawInfo *drawinfo) { - GC gc; - Tk_3DBorder border; - Pixmap pixmap; - int x = 0; /* Initialization only needed to stop compiler - * warning. */ - int y, relief; - Tk_Window tkwin = butPtr->tkwin; - int width = 0, height = 0, fullWidth, fullHeight; - int textXOffset, textYOffset; - int haveImage = 0, haveText = 0; - int imageWidth, imageHeight; - int imageXOffset = 0, imageYOffset = 0; - /* image information that will be used to - * restrict disabled pixmap as well */ - - border = butPtr->normalBorder; - if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { - gc = butPtr->disabledGC; - } else if ((butPtr->state == STATE_ACTIVE) - && !Tk_StrictMotif(butPtr->tkwin)) { - gc = butPtr->activeTextGC; - border = butPtr->activeBorder; + MacButton *mbPtr = (MacButton *)butPtr; + + if (butPtr->borderWidth <= 2) { + *btnkind = kThemeSmallBevelButton; + } else if (butPtr->borderWidth == 3) { + *btnkind = kThemeBevelButton; + } else if (butPtr->borderWidth == 4) { + *btnkind = kThemeRoundedBevelButton; } else { - gc = butPtr->normalTextGC; + *btnkind = kThemePushButton; } - if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE) - && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) { - border = butPtr->selectBorder; - } - - relief = butPtr->relief; - - pixmap = (Pixmap) Tk_WindowId(tkwin); - Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin), - Tk_Height(tkwin), 0, TK_RELIEF_FLAT); - - /* - * Display image or bitmap or text for button. - */ - - if (butPtr->image != NULL) { - Tk_SizeOfImage(butPtr->image, &width, &height); - haveImage = 1; - } else if (butPtr->bitmap != None) { - Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); - haveImage = 1; - } - imageWidth = width; - imageHeight = height; - - haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); - - if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { - textXOffset = 0; - textYOffset = 0; - fullWidth = 0; - fullHeight = 0; - - switch ((enum compound) butPtr->compound) { - case COMPOUND_TOP: - case COMPOUND_BOTTOM: - /* - * Image is above or below text. - */ - - if (butPtr->compound == COMPOUND_TOP) { - textYOffset = height + butPtr->padY; - } else { - imageYOffset = butPtr->textHeight + butPtr->padY; - } - fullHeight = height + butPtr->textHeight + butPtr->padY; - fullWidth = (width > butPtr->textWidth ? width : - butPtr->textWidth); - textXOffset = (fullWidth - butPtr->textWidth)/2; - imageXOffset = (fullWidth - width)/2; - break; - case COMPOUND_LEFT: - case COMPOUND_RIGHT: - /* - * Image is left or right of text. - */ - if (butPtr->compound == COMPOUND_LEFT) { - textXOffset = width + butPtr->padX; - } else { - imageXOffset = butPtr->textWidth + butPtr->padX; - } - fullWidth = butPtr->textWidth + butPtr->padX + width; - fullHeight = (height > butPtr->textHeight ? height : - butPtr->textHeight); - textYOffset = (fullHeight - butPtr->textHeight)/2; - imageYOffset = (fullHeight - height)/2; - break; - case COMPOUND_CENTER: - /* - * Image and text are superimposed. - */ - - fullWidth = (width > butPtr->textWidth ? width : - butPtr->textWidth); - fullHeight = (height > butPtr->textHeight ? height : - butPtr->textHeight); - textXOffset = (fullWidth - butPtr->textWidth)/2; - imageXOffset = (fullWidth - width)/2; - textYOffset = (fullHeight - butPtr->textHeight)/2; - imageYOffset = (fullHeight - height)/2; - break; - case COMPOUND_NONE: - break; - } - - TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, - fullWidth, fullHeight, &x, &y); - - imageXOffset += x; - imageYOffset += y; - - if (butPtr->image != NULL) { - /* - * Do boundary clipping, so that Tk_RedrawImage is passed valid - * coordinates. [Bug 979239] - */ - - if (imageXOffset < 0) { - imageXOffset = 0; - } - if (imageYOffset < 0) { - imageYOffset = 0; - } - if (width > Tk_Width(tkwin)) { - width = Tk_Width(tkwin); - } - if (height > Tk_Height(tkwin)) { - height = Tk_Height(tkwin); - } - if ((width + imageXOffset) > Tk_Width(tkwin)) { - imageXOffset = Tk_Width(tkwin) - width; - } - if ((height + imageYOffset) > Tk_Height(tkwin)) { - imageYOffset = Tk_Height(tkwin) - height; - } - - if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) { - Tk_RedrawImage(butPtr->selectImage, 0, 0, - width, height, pixmap, imageXOffset, imageYOffset); - } else if ((butPtr->tristateImage != NULL) && (butPtr->flags & TRISTATED)) { - Tk_RedrawImage(butPtr->tristateImage, 0, 0, - width, height, pixmap, imageXOffset, imageYOffset); - } else { - Tk_RedrawImage(butPtr->image, 0, 0, width, - height, pixmap, imageXOffset, imageYOffset); - } - } else { - XSetClipOrigin(butPtr->display, gc, imageXOffset, imageYOffset); - XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, - 0, 0, (unsigned int) width, (unsigned int) height, - imageXOffset, imageYOffset, 1); - XSetClipOrigin(butPtr->display, gc, 0, 0); - } - - Tk_DrawTextLayout(butPtr->display, pixmap, gc, - butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1); - Tk_UnderlineTextLayout(butPtr->display, pixmap, gc, - butPtr->textLayout, x + textXOffset, y + textYOffset, - butPtr->underline); - y += fullHeight/2; - } else { - if (haveImage) { - TkComputeAnchor(butPtr->anchor, tkwin, 0, 0, - width, height, &x, &y); - imageXOffset += x; - imageYOffset += y; - if (butPtr->image != NULL) { - /* - * Do boundary clipping, so that Tk_RedrawImage is passed - * valid coordinates. [Bug 979239] - */ - - if (imageXOffset < 0) { - imageXOffset = 0; - } - if (imageYOffset < 0) { - imageYOffset = 0; - } - if (width > Tk_Width(tkwin)) { - width = Tk_Width(tkwin); - } - if (height > Tk_Height(tkwin)) { - height = Tk_Height(tkwin); - } - if ((width + imageXOffset) > Tk_Width(tkwin)) { - imageXOffset = Tk_Width(tkwin) - width; - } - if ((height + imageYOffset) > Tk_Height(tkwin)) { - imageYOffset = Tk_Height(tkwin) - height; - } - - if ((butPtr->selectImage != NULL) && - (butPtr->flags & SELECTED)) { - Tk_RedrawImage(butPtr->selectImage, 0, 0, width, - height, pixmap, imageXOffset, imageYOffset); - } else if ((butPtr->tristateImage != NULL) && - (butPtr->flags & TRISTATED)) { - Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, - height, pixmap, imageXOffset, imageYOffset); + if ((butPtr->image == None) && (butPtr->bitmap == None)) { + switch (butPtr->type) { + case TYPE_BUTTON: + *btnkind = kThemePushButton; + break; + case TYPE_RADIO_BUTTON: + if (butPtr->borderWidth <= 1) { + *btnkind = kThemeSmallRadioButton; } else { - Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, - imageXOffset, imageYOffset); + *btnkind = kThemeRadioButton; } - } else { - XSetClipOrigin(butPtr->display, gc, x, y); - XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0, - (unsigned int) width, (unsigned int) height, x, y, 1); - XSetClipOrigin(butPtr->display, gc, 0, 0); - } - y += height/2; - } else { - TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, - butPtr->textWidth, butPtr->textHeight, &x, &y); - - Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout, - x, y, 0, -1); - Tk_UnderlineTextLayout(butPtr->display, pixmap, gc, - butPtr->textLayout, x, y, butPtr->underline); - y += butPtr->textHeight/2; + break; + case TYPE_CHECK_BUTTON: + if (butPtr->borderWidth <= 1) { + *btnkind = kThemeSmallCheckBox; + } else { + *btnkind = kThemeCheckBox; + } + break; } } - /* - * If the button is disabled with a stipple rather than a special - * foreground color, generate the stippled effect. If the widget is - * selected and we use a different background color when selected, must - * temporarily modify the GC so the stippling is the right color. - */ - - if ((butPtr->state == STATE_DISABLED) - && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) { - if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn - && (butPtr->selectBorder != NULL)) { - XSetForeground(butPtr->display, butPtr->stippleGC, - Tk_3DBorderColor(butPtr->selectBorder)->pixel); - } - - /* - * Stipple the whole button if no disabledFg was specified, otherwise - * restrict stippling only to displayed image - */ - - if (butPtr->disabledFg == NULL) { - XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC, 0, 0, - (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin)); - } else { - XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC, - imageXOffset, imageYOffset, - (unsigned) imageWidth, (unsigned) imageHeight); - } - if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn - && (butPtr->selectBorder != NULL)) { - XSetForeground(butPtr->display, butPtr->stippleGC, - Tk_3DBorderColor(butPtr->normalBorder)->pixel); - } + if (butPtr->indicatorOn) { + switch (butPtr->type) { + case TYPE_RADIO_BUTTON: + if (butPtr->borderWidth <= 1) { + *btnkind = kThemeSmallRadioButton; + } else { + *btnkind = kThemeRadioButton; + } + break; + case TYPE_CHECK_BUTTON: + if (butPtr->borderWidth <= 1) { + *btnkind = kThemeSmallCheckBox; + } else { + *btnkind = kThemeCheckBox; + } + break; + } + } else { + if (butPtr->type == TYPE_RADIO_BUTTON || + butPtr->type == TYPE_CHECK_BUTTON + ) { + if (*btnkind == kThemePushButton) { + *btnkind = kThemeBevelButton; + } + } } - /* - * Draw the border and traversal highlight last. This way, if the button's - * contents overflow they'll be covered up by the border. This code is - * complicated by the possible combinations of focus highlight and default - * rings. We draw the focus and highlight rings using the highlight border - * and highlight foreground color. - */ - - if (relief != TK_RELIEF_FLAT) { - int inset = butPtr->highlightWidth; - - if (butPtr->defaultState == DEFAULT_ACTIVE) { - /* - * Draw the default ring with 2 pixels of space between the - * default ring and the button and the default ring and the focus - * ring. Note that we need to explicitly draw the space in the - * highlightBorder color to ensure that we overwrite any overflow - * text and/or a different button background color. - */ - - Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset, - inset, Tk_Width(tkwin) - 2*inset, - Tk_Height(tkwin) - 2*inset, 2, TK_RELIEF_FLAT); - inset += 2; - Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset, - inset, Tk_Width(tkwin) - 2*inset, - Tk_Height(tkwin) - 2*inset, 1, TK_RELIEF_SUNKEN); - inset++; - Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset, - inset, Tk_Width(tkwin) - 2*inset, - Tk_Height(tkwin) - 2*inset, 2, TK_RELIEF_FLAT); - - inset += 2; - } else if (butPtr->defaultState == DEFAULT_NORMAL) { - /* - * Leave room for the default ring and write over any text or - * background color. - */ - - Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, - 0, Tk_Width(tkwin), Tk_Height(tkwin), 5, TK_RELIEF_FLAT); - inset += 5; - } - - /* - * Draw the button border. - */ - - Tk_Draw3DRectangle(tkwin, pixmap, border, inset, inset, - Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset, - butPtr->borderWidth, relief); + if (butPtr->flags & SELECTED) { + drawinfo->value = kThemeButtonOn; + } else if (butPtr->flags & TRISTATED) { + drawinfo->value = kThemeButtonMixed; + } else { + drawinfo->value = kThemeButtonOff; } - if (butPtr->highlightWidth > 0) { - GC gc; - - if (butPtr->flags & GOT_FOCUS) { - gc = Tk_GCForColor(butPtr->highlightColorPtr, pixmap); - } else { - gc = Tk_GCForColor(Tk_3DBorderColor(butPtr->highlightBorder), - pixmap); + + if ((mbPtr->flags & FIRST_DRAW) != 0) { + mbPtr->flags &= ~FIRST_DRAW; + if (Tk_MacOSXIsAppInFront()) { + mbPtr->flags |= ACTIVE; } + } - /* - * Make sure the focus ring shrink-wraps the actual button, not the - * padding space left for a default ring. - */ + drawinfo->state = kThemeStateInactive; + if ((mbPtr->flags & ACTIVE) == 0) { + if (butPtr->state == STATE_DISABLED) { + drawinfo->state = kThemeStateUnavailableInactive; + } else { + drawinfo->state = kThemeStateInactive; + } + } else if (butPtr->state == STATE_DISABLED) { + drawinfo->state = kThemeStateUnavailable; + } else if (butPtr->state == STATE_ACTIVE) { + drawinfo->state = kThemeStatePressed; + } else { + drawinfo->state = kThemeStateActive; + } - if (butPtr->defaultState == DEFAULT_NORMAL) { - TkDrawInsetFocusHighlight(tkwin, gc, butPtr->highlightWidth, - pixmap, 5); - } else { - Tk_DrawFocusHighlight(tkwin, gc, butPtr->highlightWidth, pixmap); - } + drawinfo->adornment = kThemeAdornmentNone; + if (butPtr->defaultState == DEFAULT_ACTIVE) { + drawinfo->adornment |= kThemeAdornmentDefault; + if (!mbPtr->defaultPulseHandler) { + mbPtr->defaultPulseHandler = Tcl_CreateTimerHandler( + PULSE_TIMER_MSECS, PulseDefaultButtonProc, + (ClientData) butPtr); + } + } else if (mbPtr->defaultPulseHandler) { + Tcl_DeleteTimerHandler(mbPtr->defaultPulseHandler); + } + if (butPtr->highlightWidth >= 3) { + if ((butPtr->flags & GOT_FOCUS)) { + drawinfo->adornment |= kThemeAdornmentFocus; + } } } /* *---------------------------------------------------------------------- * - * ComputeUnixButtonGeometry -- + * TkMacOSXComputeButtonDrawParams -- * - * After changes in a button's text or bitmap, this procedure - * recomputes the button's geometry and passes this information - * along to the geometry manager for the window. + * This procedure computes the various parameters used + * when drawing a button + * These are determined by the various tk button parameters * * Results: - * None. + * 1 if control will be used, 0 otherwise. * * Side effects: - * The button's window may change size. + * Sets the button draw parameters * *---------------------------------------------------------------------- */ -void -ComputeUnixButtonGeometry( - register TkButton *butPtr) /* Button whose geometry may have changed. */ +static int +TkMacOSXComputeButtonDrawParams( + TkButton *butPtr, + DrawParams *dpPtr) { - int width, height, avgWidth, txtWidth, txtHeight; - int haveImage = 0, haveText = 0; - Tk_FontMetrics fm; - - butPtr->inset = butPtr->highlightWidth + butPtr->borderWidth; - - /* - * Leave room for the default ring if needed. - */ - - if (butPtr->defaultState != DEFAULT_DISABLED) { - butPtr->inset += 5; + MacButton *mbPtr = (MacButton *)butPtr; + + dpPtr->hasImageOrBitmap = ((butPtr->image != NULL) + || (butPtr->bitmap != None)); + + if (butPtr->type != TYPE_LABEL) { + dpPtr->offset = 0; + if (dpPtr->hasImageOrBitmap) { + switch (mbPtr->btnkind) { + case kThemeSmallBevelButton: + case kThemeBevelButton: + case kThemeRoundedBevelButton: + case kThemePushButton: + dpPtr->offset = 1; + break; + } + } } - butPtr->indicatorSpace = 0; - width = 0; - height = 0; - txtWidth = 0; - txtHeight = 0; - avgWidth = 0; - if (butPtr->image != NULL) { - Tk_SizeOfImage(butPtr->image, &width, &height); - haveImage = 1; - } else if (butPtr->bitmap != None) { - Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); - haveImage = 1; + dpPtr->border = butPtr->normalBorder; + if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { + dpPtr->gc = butPtr->disabledGC; + } else if (butPtr->type == TYPE_BUTTON && butPtr->state == STATE_ACTIVE) { + dpPtr->gc = butPtr->activeTextGC; + dpPtr->border = butPtr->activeBorder; + } else { + dpPtr->gc = butPtr->normalTextGC; } - if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) { - Tk_FreeTextLayout(butPtr->textLayout); - - butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, - Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, - butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); - - txtWidth = butPtr->textWidth; - txtHeight = butPtr->textHeight; - avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); - Tk_GetFontMetrics(butPtr->tkfont, &fm); - haveText = (txtWidth != 0 && txtHeight != 0); + if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE) + && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) { + dpPtr->border = butPtr->selectBorder; } /* - * If the button is compound (i.e., it shows both an image and text), the - * new geometry is a combination of the image and text geometry. We only - * honor the compound bit if the button has both text and an image, - * because otherwise it is not really a compound button. + * Override the relief specified for the button if this is a + * checkbutton or radiobutton and there's no indicator. + * However, don't do this in the presence of Appearance, since + * then the bevel button will take care of the relief. */ - if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { - switch ((enum compound) butPtr->compound) { - case COMPOUND_TOP: - case COMPOUND_BOTTOM: - /* - * Image is above or below text. - */ - - height += txtHeight + butPtr->padY; - width = (width > txtWidth ? width : txtWidth); - break; - case COMPOUND_LEFT: - case COMPOUND_RIGHT: - /* - * Image is left or right of text. - */ + dpPtr->relief = butPtr->relief; - width += txtWidth + butPtr->padX; - height = (height > txtHeight ? height : txtHeight); - break; - case COMPOUND_CENTER: - /* - * Image and text are superimposed. - */ - - width = (width > txtWidth ? width : txtWidth); - height = (height > txtHeight ? height : txtHeight); - break; - case COMPOUND_NONE: - break; - } - if (butPtr->width > 0) { - width = butPtr->width; - } - if (butPtr->height > 0) { - height = butPtr->height; + if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) { + if (!dpPtr->hasImageOrBitmap) { + dpPtr->relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN + : TK_RELIEF_RAISED; } + } - width += 2*butPtr->padX; - height += 2*butPtr->padY; - } else { - if (haveImage) { - if (butPtr->width > 0) { - width = butPtr->width; - } - if (butPtr->height > 0) { - height = butPtr->height; - } - } else { - width = txtWidth; - height = txtHeight; + /* + * Determine the draw type + */ - if (butPtr->width > 0) { - width = butPtr->width * avgWidth; - } - if (butPtr->height > 0) { - height = butPtr->height * fm.linespace; - } + if (butPtr->type == TYPE_LABEL) { + dpPtr->drawType = DRAW_LABEL; + } else if (butPtr->type == TYPE_BUTTON) { + if (!dpPtr->hasImageOrBitmap) { + dpPtr->drawType = DRAW_CONTROL; + } else { + dpPtr->drawType = DRAW_BEVEL; } + } else if (butPtr->indicatorOn) { + dpPtr->drawType = DRAW_CONTROL; + } else if (dpPtr->hasImageOrBitmap) { + dpPtr->drawType = DRAW_BEVEL; + } else { + dpPtr->drawType = DRAW_CUSTOM; } - if (!haveImage) { - width += 2*butPtr->padX; - height += 2*butPtr->padY; + if ((dpPtr->drawType == DRAW_CONTROL) || (dpPtr->drawType == DRAW_BEVEL)) { + return 1; + } else { + return 0; } - Tk_GeometryRequest(butPtr->tkwin, (int) (width - + 2*butPtr->inset), (int) (height + 2*butPtr->inset)); - Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); } - /* - * Local Variables: - * mode: objc - * c-basic-offset: 4 - * fill-column: 79 - * coding: utf-8 - * End: + *-------------------------------------------------------------- + * + * PulseDefaultButtonProc -- + * + * This function redraws the button on a timer, to pulse + * default buttons. + * + * Results: + * None. + * + * Side effects: + * Sets a timer to run itself again. + * + *-------------------------------------------------------------- */ +static void +PulseDefaultButtonProc(ClientData clientData) +{ + MacButton *mbPtr = (MacButton *)clientData; + TkpDisplayButton(clientData); + mbPtr->defaultPulseHandler = Tcl_CreateTimerHandler( + PULSE_TIMER_MSECS, PulseDefaultButtonProc, clientData); +} + diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 6c0268c..962dd1a 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -101,13 +101,6 @@ TkMacOSXInitCGDrawing( (char *) &useThemedFrame, TCL_LINK_BOOLEAN) != TCL_OK) { Tcl_ResetResult(interp); } -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - if (Tcl_LinkVar(interp, "::tk::mac::useCompatibilityMetrics", - (char *) &tkMacOSXUseCompatibilityMetrics, TCL_LINK_BOOLEAN) - != TCL_OK) { - Tcl_ResetResult(interp); - } -#endif } return TCL_OK; } @@ -1519,21 +1512,6 @@ TkScrollWindow( /* Scroll the rectangle. */ [view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)]; - /* - * Adjust the positions of the button subwindows that meet the scroll - * area. - */ - - for (NSView *subview in [view subviews] ) { - if ( [subview isKindOfClass:[NSButton class]] == YES ) { - NSRect subframe = [subview frame]; - if ( NSIntersectsRect(scrollSrc, subframe) || - NSIntersectsRect(scrollDst, subframe) ) { - TkpShiftButton((NSButton *)subview, delta ); - } - } - } - /* Redisplay the scrolled area; hide to reduce flicker after removal of private API calls. */ [view setHidden:YES]; [view displayRect:scrollDst]; diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index df42763..a1c3138 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -5,66 +5,70 @@ * menubutton widget. * * Copyright (c) 1996 by Sun Microsystems, Inc. - * Copyright 2001-2009, Apple Inc. - * Copyright (c) 2006-2009 Daniel A. Steffen + * Copyright 2001, Apple Computer, Inc. + * Copyright (c) 2006-2007 Daniel A. Steffen + * Copyright 2007 Revar Desmera. + * Copyright 2015 Kevin Walzer/WordTech Communications LLC. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * */ #include "tkMacOSXPrivate.h" +#include "tkMenu.h" #include "tkMenubutton.h" #include "tkMacOSXFont.h" #include "tkMacOSXDebug.h" -/* -#ifdef TK_MAC_DEBUG -#define TK_MAC_DEBUG_MENUBUTTON -#endif -*/ +#define FIRST_DRAW 2 +#define ACTIVE 4 -typedef struct MacMenuButton { - TkMenuButton info; - NSPopUpButton *button; -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - int fix; -#endif -} MacMenuButton; -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS +typedef struct { + Tk_3DBorder border; + int relief; + GC gc; + int hasImageOrBitmap; +} DrawParams; + /* - * Use the following heuristic conversion constants to make NSButton-based - * widget metrics match up with the old Carbon control buttons (for the - * default Lucida Grande 13 font). - * TODO: provide a scriptable way to turn this off and use the raw NSButton - * metrics (will also need dynamic adjustment of the default padding, - * c.f. tkMacOSXDefault.h). + * Declaration of Mac specific button structure. */ -typedef struct { - int trimW, trimH, inset, shrinkW, offsetX, offsetY; -} BoundsFix; - -#define fixForStyle(style) ( \ - style == NSRoundedBezelStyle ? 1 : \ - style == NSRegularSquareBezelStyle ? 2 : \ - style == NSShadowlessSquareBezelStyle ? 3 : \ - INT_MIN) - -static const BoundsFix boundsFixes[] = { - [fixForStyle(NSRoundedBezelStyle)] = { 14, 10, -2, -1}, - [fixForStyle(NSRegularSquareBezelStyle)] = { 6, 13, -2, 1, 1}, - [fixForStyle(NSShadowlessSquareBezelStyle)] = { 15, 0, 2 }, -}; - -#endif +typedef struct MacMenuButton { + TkMenuButton info; /* Generic button info. */ + int flags; + ThemeButtonKind btnkind; + HIThemeButtonDrawInfo drawinfo; + HIThemeButtonDrawInfo lastdrawinfo; + DrawParams drawParams; +} MacMenuButton; /* * Forward declarations for procedures defined later in this file: */ static void MenuButtonEventProc(ClientData clientData, XEvent *eventPtr); +static void MenuButtonBackgroundDrawCB ( MacMenuButton *ptr, SInt16 depth, Boolean isColorDev); +static void MenuButtonContentDrawCB ( ThemeButtonKind kind, const HIThemeButtonDrawInfo * info, MacMenuButton *ptr, SInt16 depth, Boolean isColorDev); +static void MenuButtonEventProc ( ClientData clientData, XEvent *eventPtr); +static void TkMacOSXComputeMenuButtonParams (TkMenuButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo* drawinfo); +static int TkMacOSXComputeMenuButtonDrawParams (TkMenuButton * butPtr, DrawParams * dpPtr); +static void TkMacOSXDrawMenuButton (MacMenuButton *butPtr, + GC gc, Pixmap pixmap); +static void DrawMenuButtonImageAndText(TkMenuButton* butPtr); + +/* + * The structure below defines menubutton class behavior by means of + * procedures that can be invoked from generic window code. + */ + +Tk_ClassProcs tkpMenubuttonClass = { + sizeof(Tk_ClassProcs), /* size */ + TkMenuButtonWorldChanged, /* worldChangedProc */ +}; /* @@ -87,113 +91,94 @@ TkMenuButton * TkpCreateMenuButton( Tk_Window tkwin) { - MacMenuButton *macButtonPtr = ckalloc(sizeof(MacMenuButton)); + MacMenuButton *mbPtr = (MacMenuButton *) ckalloc(sizeof(MacMenuButton)); - macButtonPtr->button = nil; Tk_CreateEventHandler(tkwin, ActivateMask, - MenuButtonEventProc, (ClientData) macButtonPtr); - return (TkMenuButton *) macButtonPtr; + MenuButtonEventProc, (ClientData) mbPtr); + mbPtr->flags = FIRST_DRAW; + mbPtr->btnkind = kThemePopupButton; + bzero(&mbPtr->drawinfo, sizeof(mbPtr->drawinfo)); + bzero(&mbPtr->lastdrawinfo, sizeof(mbPtr->lastdrawinfo)); + + return (TkMenuButton *) mbPtr; } /* *---------------------------------------------------------------------- * - * TkpDestroyMenuButton -- + * TkpDisplayMenuButton -- * - * Free data structures associated with the menubutton control. + * This procedure is invoked to display a menubutton widget. * * Results: * None. * * Side effects: - * Restores the default control state. + * Commands are output to X to display the menubutton in its + * current mode. * *---------------------------------------------------------------------- */ void -TkpDestroyMenuButton( - TkMenuButton *mbPtr) +TkpDisplayMenuButton( + ClientData clientData) /* Information about widget. */ { - MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr; - [macButtonPtr->button setTag:(NSInteger)-1]; + MacMenuButton *mbPtr = (MacMenuButton *)clientData; + TkMenuButton *butPtr = (TkMenuButton *) clientData; + Tk_Window tkwin = butPtr->tkwin; + Pixmap pixmap; + DrawParams* dpPtr = &mbPtr->drawParams; + + butPtr->flags &= ~REDRAW_PENDING; + if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { + return; + } - TkMacOSXMakeCollectableAndRelease(macButtonPtr->button); + pixmap = (Pixmap) Tk_WindowId(tkwin); + + TkMacOSXComputeMenuButtonDrawParams(butPtr, dpPtr); + + /* + * set up clipping region. Make sure the we are using the port + * for this button, or we will set the wrong window's clip. + */ + + TkMacOSXSetUpClippingRgn(pixmap); + + /* Draw the native portion of the buttons. */ + TkMacOSXDrawMenuButton(mbPtr, dpPtr->gc, pixmap); + + /* Draw highlight border, if needed. */ + if (butPtr->highlightWidth < 3) { + if ((butPtr->flags & GOT_FOCUS)) { + Tk_Draw3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), + butPtr->highlightWidth, TK_RELIEF_SOLID); + } + } } /* *---------------------------------------------------------------------- * - * TkpDisplayMenuButton -- + * TkpDestroyMenuButton -- * - * This function is invoked to display a menubutton widget. + * Free data structures associated with the menubutton control. * * Results: * None. * * Side effects: - * Commands are output to X to display the menubutton in its current - * mode. + * Restores the default control state. * *---------------------------------------------------------------------- */ void -TkpDisplayMenuButton( - ClientData clientData) /* Information about widget. */ +TkpDestroyMenuButton( + TkMenuButton *mbPtr) { - TkMenuButton *mbPtr = (TkMenuButton *) clientData; - MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr; - NSPopUpButton *button = macButtonPtr->button; - Tk_Window tkwin = mbPtr->tkwin; - TkWindow *winPtr = (TkWindow *) tkwin; - MacDrawable *macWin = (MacDrawable *) winPtr->window; - TkMacOSXDrawingContext dc; - NSView *view = TkMacOSXDrawableView(macWin); - CGFloat viewHeight = [view bounds].size.height; - CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, - .ty = viewHeight}; - NSRect frame; - int enabled; - - mbPtr->flags &= ~REDRAW_PENDING; - if (!tkwin || !Tk_IsMapped(tkwin) || !view || - !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { - return; - } - CGContextConcatCTM(dc.context, t); - Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, mbPtr->normalBorder, 0, 0, - Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); - if ([button superview] != view) { - [view addSubview:button]; - } - enabled = !(mbPtr->state == STATE_DISABLED); - [button setEnabled:enabled]; - if (enabled) { - [[button cell] setHighlighted:(mbPtr->state == STATE_ACTIVE)]; - } - frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin), - Tk_Height(tkwin)); - frame = NSInsetRect(frame, mbPtr->inset, mbPtr->inset); -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - if (tkMacOSXUseCompatibilityMetrics) { - BoundsFix boundsFix = boundsFixes[macButtonPtr->fix]; - frame = NSOffsetRect(frame, boundsFix.offsetX, boundsFix.offsetY); - frame.size.width -= boundsFix.shrinkW; - frame = NSInsetRect(frame, boundsFix.inset, boundsFix.inset); - } -#endif - frame.origin.y = viewHeight - (frame.origin.y + frame.size.height); - if (!NSEqualRects(frame, [button frame])) { - [button setFrame:frame]; - } - [button displayRectIgnoringOpacity:[button bounds]]; - TkMacOSXRestoreDrawingContext(&dc); -#ifdef TK_MAC_DEBUG_MENUBUTTON - TKLog(@"menubutton %s frame %@ width %d height %d", - ((TkWindow *)mbPtr->tkwin)->pathName, NSStringFromRect(frame), - Tk_Width(tkwin), Tk_Height(tkwin)); -#endif } /* @@ -201,7 +186,7 @@ TkpDisplayMenuButton( * * TkpComputeMenuButtonGeometry -- * - * After changes in a menu button's text or bitmap, this function + * After changes in a menu button's text or bitmap, this procedure * recomputes the menu button's geometry and passes this information * along to the geometry manager for the window. * @@ -215,205 +200,508 @@ TkpDisplayMenuButton( */ void -TkpComputeMenuButtonGeometry( - TkMenuButton *mbPtr) /* Widget record for menu button. */ +TkpComputeMenuButtonGeometry(butPtr) + register TkMenuButton *butPtr; /* Widget record for menu button. */ { - MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr; - NSPopUpButton *button = macButtonPtr->button; - NSPopUpButtonCell *cell; - NSMenuItem *menuItem; - NSBezelStyle style = NSRoundedBezelStyle; - NSFont *font; - NSRect bounds = NSZeroRect, titleRect = NSZeroRect; - int haveImage = (mbPtr->image || mbPtr->bitmap != None), haveText = 0; - int haveCompound = (mbPtr->compound != COMPOUND_NONE); - int width, height; - - if (!button) { - button = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:YES]; - macButtonPtr->button = TkMacOSXMakeUncollectable(button); - cell = [button cell]; - [cell setUsesItemFromMenu:NO]; - menuItem = [[[NSMenuItem alloc] initWithTitle:@"" - action:NULL keyEquivalent:@""] autorelease]; - [cell setMenuItem:menuItem]; - } else { - cell = [button cell]; - menuItem = [cell menuItem]; + int width, height, avgWidth, haveImage = 0, haveText = 0; + MacMenuButton *mbPtr = (MacMenuButton*)butPtr; + int txtWidth, txtHeight; + Tk_FontMetrics fm; + DrawParams drawParams; + int paddingx = 0; + int paddingy = 0; + + /* + * First figure out the size of the contents of the button. + */ + + width = 0; + height = 0; + txtWidth = 0; + txtHeight = 0; + avgWidth = 0; + + TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); + + if (butPtr->image != NULL) { + Tk_SizeOfImage(butPtr->image, &width, &height); + haveImage = 1; + } else if (butPtr->bitmap != None) { + Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); + haveImage = 1; } - if (haveImage) { - style = NSShadowlessSquareBezelStyle; - } else if (!mbPtr->indicatorOn) { - style = NSRegularSquareBezelStyle; + + if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) { + Tk_FreeTextLayout(butPtr->textLayout); + butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, + butPtr->text, -1, butPtr->wrapLength, + butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); + + txtWidth = butPtr->textWidth; + txtHeight = butPtr->textHeight; + avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); + Tk_GetFontMetrics(butPtr->tkfont, &fm); + haveText = (txtWidth != 0 && txtHeight != 0); } - [button setBezelStyle:style]; - [cell setArrowPosition:(mbPtr->indicatorOn ? NSPopUpArrowAtBottom : - NSPopUpNoArrow)]; -#if 0 - NSControlSize controlSize = NSRegularControlSize; - - if (mbPtr->borderWidth <= 2) { - controlSize = NSMiniControlSize; - } else if (mbPtr->borderWidth == 3) { - controlSize = NSSmallControlSize; + + /* + * If the button is compound (ie, it shows both an image and text), + * the new geometry is a combination of the image and text geometry. + * We only honor the compound bit if the button has both text and an + * image, because otherwise it is not really a compound button. + */ + + if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { + switch ((enum compound) butPtr->compound) { + case COMPOUND_TOP: + case COMPOUND_BOTTOM: { + /* + * Image is above or below text + */ + + height += txtHeight + butPtr->padY; + width = (width > txtWidth ? width : txtWidth); + break; + } + case COMPOUND_LEFT: + case COMPOUND_RIGHT: { + /* + * Image is left or right of text + */ + + width += txtWidth + butPtr->padX; + height = (height > txtHeight ? height : txtHeight); + break; + } + case COMPOUND_CENTER: { + /* + * Image and text are superimposed + */ + + width = (width > txtWidth ? width : txtWidth); + height = (height > txtHeight ? height : txtHeight); + break; + } + case COMPOUND_NONE: {break;} + } + + if (butPtr->width > 0) { + width = butPtr->width; + } + if (butPtr->height > 0) { + height = butPtr->height; + } + + } else { + if (haveImage) { + if (butPtr->width > 0) { + width = butPtr->width; + } + if (butPtr->height > 0) { + height = butPtr->height; + } + } else { + width = txtWidth; + height = txtHeight; + if (butPtr->width > 0) { + width = butPtr->width * avgWidth; + } + if (butPtr->height > 0) { + height = butPtr->height * fm.linespace; + } + } } - [cell setControlSize:controlSize]; -#endif - - if (mbPtr->text && *(mbPtr->text) && (!haveImage || haveCompound)) { - NSString *title = [[NSString alloc] initWithUTF8String:mbPtr->text]; - [button setTitle:title]; - [title release]; - haveText = 1; + width += 2 * butPtr->padX - 2; + height += 2 * butPtr->padY - 2; + + /*Add padding for button arrows.*/ + width += 22; + + /* + * Now figure out the size of the border decorations for the button. + */ + + if (butPtr->highlightWidth < 0) { + butPtr->highlightWidth = 0; } - haveCompound = (haveCompound && haveImage && haveText); - if (haveText) { - NSTextAlignment alignment = NSNaturalTextAlignment; - - switch (mbPtr->justify) { - case TK_JUSTIFY_LEFT: - alignment = NSLeftTextAlignment; - break; - case TK_JUSTIFY_RIGHT: - alignment = NSRightTextAlignment; - break; - case TK_JUSTIFY_CENTER: - alignment = NSCenterTextAlignment; - break; - } - [button setAlignment:alignment]; - } else { - [button setTitle:@""]; + butPtr->inset = 0; + butPtr->inset += butPtr->highlightWidth; + + TkMacOSXComputeMenuButtonDrawParams(butPtr,&drawParams); + + HIRect tmpRect; + HIRect contBounds; + + tmpRect = CGRectMake(0, 0, width, height); + + HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds); + + + + /* If the content region has a minimum height, match it. */ + if (height < contBounds.size.height) { + height = contBounds.size.height; + } + + /* If the content region has a minimum width, match it. */ + if (width < contBounds.size.width) { + width = contBounds.size.width; + } + + /* Pad to fill difference between content bounds and button bounds. */ + paddingx = tmpRect.origin.x - contBounds.origin.x; + paddingy = tmpRect.origin.y - contBounds.origin.y; + + if (paddingx > 0) { + width += paddingx; } - font = TkMacOSXNSFontForFont(mbPtr->tkfont); - if (font) { - [button setFont:font]; + if (paddingy > 0) { + height += paddingy; } - if (haveImage) { - int width, height; - NSImage *image; - NSCellImagePosition pos = NSImageOnly; - - if (mbPtr->image) { - Tk_SizeOfImage(mbPtr->image, &width, &height); - image = TkMacOSXGetNSImageWithTkImage(mbPtr->display, - mbPtr->image, width, height); - } else { - Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height); - image = TkMacOSXGetNSImageWithBitmap(mbPtr->display, - mbPtr->bitmap, mbPtr->normalTextGC, width, height); - } - if (haveCompound) { - switch ((enum compound) mbPtr->compound) { - case COMPOUND_TOP: - pos = NSImageAbove; - break; - case COMPOUND_BOTTOM: - pos = NSImageBelow; - break; - case COMPOUND_LEFT: - pos = NSImageLeft; - break; - case COMPOUND_RIGHT: - pos = NSImageRight; - break; - case COMPOUND_CENTER: - pos = NSImageOverlaps; - break; - case COMPOUND_NONE: - pos = NSImageOnly; - break; - } - } - [button setImagePosition:pos]; - [menuItem setImage:image]; - bounds.size = cell ? [cell cellSize] : NSZeroSize; - if (bounds.size.height < height + 8) { /* workaround AppKit sizing bug */ - bounds.size.height = height + 8; - } -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - if (!mbPtr->indicatorOn && tkMacOSXUseCompatibilityMetrics) { - bounds.size.width -= 16; - } -#endif - } else { - bounds.size = cell ? [cell cellSize] : NSZeroSize; + + width += butPtr->inset*2; + height += butPtr->inset*2; + + + Tk_GeometryRequest(butPtr->tkwin, width, height); + Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); +} + +/* + *---------------------------------------------------------------------- + * + * DrawMenuButtonImageAndText -- + * + * Draws the image and text associated witha button or label. + * + * Results: + * None. + * + * Side effects: + * The image and text are drawn. + * + *---------------------------------------------------------------------- + */ +void +DrawMenuButtonImageAndText( + TkMenuButton* butPtr) +{ + MacMenuButton *mbPtr = (MacMenuButton*)butPtr; + Tk_Window tkwin = butPtr->tkwin; + Pixmap pixmap; + int haveImage = 0; + int haveText = 0; + int imageWidth = 0; + int imageHeight = 0; + int imageXOffset = 0; + int imageYOffset = 0; + int textXOffset = 0; + int textYOffset = 0; + int width = 0; + int height = 0; + int fullWidth = 0; + int fullHeight = 0; + int pressed; + + if (tkwin == NULL || !Tk_IsMapped(tkwin)) { + return; } - if (haveText) { - titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect; - if (mbPtr->wrapLength > 0 && - titleRect.size.width > mbPtr->wrapLength) { - if (style == NSRoundedBezelStyle) { - [button setBezelStyle:(style = NSRegularSquareBezelStyle)]; - bounds.size = cell ? [cell cellSize] : NSZeroSize; - titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect; - } - bounds.size.width -= titleRect.size.width - mbPtr->wrapLength; - bounds.size.height = 40000.0; - [cell setWraps:YES]; - bounds.size = cell ? [cell cellSizeForBounds:bounds] : NSZeroSize; -#ifdef TK_MAC_DEBUG_MENUBUTTON - titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect; -#endif -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - if (tkMacOSXUseCompatibilityMetrics) { - bounds.size.height += 3; - } -#endif - } + + DrawParams* dpPtr = &mbPtr->drawParams; + pixmap = (Pixmap)Tk_WindowId(tkwin); + + + if (butPtr->image != None) { + Tk_SizeOfImage(butPtr->image, &width, &height); + haveImage = 1; + } else if (butPtr->bitmap != None) { + Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); + haveImage = 1; } - width = lround(bounds.size.width); - height = lround(bounds.size.height); -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS - if (tkMacOSXUseCompatibilityMetrics) { - macButtonPtr->fix = fixForStyle(style); - width -= boundsFixes[macButtonPtr->fix].trimW; - height -= boundsFixes[macButtonPtr->fix].trimH; + + imageWidth = width; + imageHeight = height; + + if (mbPtr->drawinfo.state == kThemeStatePressed) { + /* Offset bitmaps by a bit when the button is pressed. */ + pressed = 1; } -#endif + + haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); + if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { + int x = 0; + int y = 0; + textXOffset = 0; + textYOffset = 0; + fullWidth = 0; + fullHeight = 0; - if (haveImage || haveCompound) { - if (mbPtr->width > 0) { - width = mbPtr->width; - } - if (mbPtr->height > 0) { - height = mbPtr->height; + switch ((enum compound) butPtr->compound) { + case COMPOUND_TOP: + case COMPOUND_BOTTOM: { + /* Image is above or below text */ + if (butPtr->compound == COMPOUND_TOP) { + textYOffset = height + butPtr->padY; + } else { + imageYOffset = butPtr->textHeight + butPtr->padY; + } + fullHeight = height + butPtr->textHeight + butPtr->padY; + fullWidth = (width > butPtr->textWidth ? width : + butPtr->textWidth); + textXOffset = (fullWidth - butPtr->textWidth)/2; + imageXOffset = (fullWidth - width)/2; + break; + } + case COMPOUND_LEFT: + case COMPOUND_RIGHT: { + /* + * Image is left or right of text + */ + + if (butPtr->compound == COMPOUND_LEFT) { + textXOffset = width + butPtr->padX - 2; + } else { + imageXOffset = butPtr->textWidth + butPtr->padX; + } + fullWidth = butPtr->textWidth + butPtr->padX + width; + fullHeight = (height > butPtr->textHeight ? height : + butPtr->textHeight); + textYOffset = (fullHeight - butPtr->textHeight)/2; + imageYOffset = (fullHeight - height)/2; + break; + } + case COMPOUND_CENTER: { + /* + * Image and text are superimposed + */ + + fullWidth = (width > butPtr->textWidth ? width : + butPtr->textWidth); + fullHeight = (height > butPtr->textHeight ? height : + butPtr->textHeight); + textXOffset = (fullWidth - butPtr->textWidth)/2; + imageXOffset = (fullWidth - width)/2; + textYOffset = (fullHeight - butPtr->textHeight)/2; + imageYOffset = (fullHeight - height)/2; + break; + } + case COMPOUND_NONE: {break;} } + + TkComputeAnchor(butPtr->anchor, tkwin, + butPtr->padX + butPtr->borderWidth, + butPtr->padY + butPtr->borderWidth, + fullWidth, fullHeight, &x, &y); + imageXOffset += x; + imageYOffset += y; + textYOffset -= 1; + + if (butPtr->image != NULL) { + Tk_RedrawImage(butPtr->image, 0, 0, width, + height, pixmap, imageXOffset, imageYOffset); + } else { + XSetClipOrigin(butPtr->display, dpPtr->gc, + imageXOffset, imageYOffset); + XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc, + 0, 0, (unsigned int) width, (unsigned int) height, + imageXOffset, imageYOffset, 1); + XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); + } + + Tk_DrawTextLayout(butPtr->display, pixmap, + dpPtr->gc, butPtr->textLayout, + x + textXOffset, y + textYOffset, 0, -1); + Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc, + butPtr->textLayout, + x + textXOffset, y + textYOffset, + butPtr->underline); } else { - if (mbPtr->width > 0) { - int avgWidth = Tk_TextWidth(mbPtr->tkfont, "0", 1); - width = mbPtr->width * avgWidth; + if (haveImage) { + int x = 0; + int y; + TkComputeAnchor(butPtr->anchor, tkwin, + butPtr->padX + butPtr->borderWidth, + butPtr->padY + butPtr->borderWidth, + width, height, &x, &y); + imageXOffset += x; + imageYOffset += y; + + if (butPtr->image != NULL) { + Tk_RedrawImage(butPtr->image, 0, 0, width, height, + pixmap, imageXOffset, imageYOffset); + } else { + XSetClipOrigin(butPtr->display, dpPtr->gc, x, y); + XCopyPlane(butPtr->display, butPtr->bitmap, + pixmap, dpPtr->gc, + 0, 0, (unsigned int) width, + (unsigned int) height, + imageXOffset, imageYOffset, 1); + XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); + } + } else { + /*Move x back by six pixels to give the menubutton arrows room.*/ + int x = 0; + int y; + textXOffset = 6; + TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, + butPtr->textWidth, butPtr->textHeight, &x, &y); + Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, + butPtr->textLayout, x - textXOffset, y, 0, -1); + y += butPtr->textHeight/2; + } + } +} + + + +/* + *-------------------------------------------------------------- + * + * TkMacOSXDrawMenuButton -- + * + * This function draws the tk menubutton using Mac controls + * In addition, this code may apply custom colors passed + * in the TkMenubutton. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +static void +TkMacOSXDrawMenuButton( + MacMenuButton *mbPtr, /* Mac menubutton. */ + GC gc, /* The GC we are drawing into - needed for + * the bevel button */ + Pixmap pixmap) /* The pixmap we are drawing into - needed + * for the bevel button */ + +{ + TkMenuButton * butPtr = ( TkMenuButton *)mbPtr; + TkWindow * winPtr; + HIRect cntrRect; + TkMacOSXDrawingContext dc; + DrawParams* dpPtr = &mbPtr->drawParams; + int useNewerHITools = 1; + + winPtr = (TkWindow *)butPtr->tkwin; + + TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); + + cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin),Tk_Height(butPtr->tkwin)); + + cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset); + + + if (useNewerHITools == 1) { + HIRect hirec; + HIRect contHIRec; + static HIThemeButtonDrawInfo hiinfo; + Rect contRect; + + MenuButtonBackgroundDrawCB((MacMenuButton*) mbPtr, 32, true); + + if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { + return; } - if (mbPtr->height > 0) { - Tk_FontMetrics fm; - Tk_GetFontMetrics(mbPtr->tkfont, &fm); - height = mbPtr->height * fm.linespace; + + hiinfo.version = 0; + hiinfo.state = mbPtr->drawinfo.state; + hiinfo.kind = mbPtr->btnkind; + hiinfo.value = mbPtr->drawinfo.value; + hiinfo.adornment = mbPtr->drawinfo.adornment; + hiinfo.animation.time.current = CFAbsoluteTimeGetCurrent(); + if (hiinfo.animation.time.start == 0) { + hiinfo.animation.time.start = hiinfo.animation.time.current; + } + + HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); + + TkMacOSXRestoreDrawingContext(&dc); + + MenuButtonContentDrawCB( mbPtr->btnkind, &mbPtr->drawinfo, (MacMenuButton *)mbPtr, 32, true); + } else { + if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { + return; } + + + TkMacOSXRestoreDrawingContext(&dc); } - if (!haveImage || haveCompound) { - width += 2*mbPtr->padX; - height += 2*mbPtr->padY; - } - if (mbPtr->highlightWidth < 0) { - mbPtr->highlightWidth = 0; + mbPtr->lastdrawinfo = mbPtr->drawinfo; +} + +/* + *-------------------------------------------------------------- + * + * MenuButtonBackgroundDrawCB -- + * + * This function draws the background that + * lies under checkboxes and radiobuttons. + * + * Results: + * None. + * + * Side effects: + * The background gets updated to the current color. + * + *-------------------------------------------------------------- + */ +static void +MenuButtonBackgroundDrawCB ( + MacMenuButton *ptr, + SInt16 depth, + Boolean isColorDev) +{ + TkMenuButton* butPtr = (TkMenuButton*)ptr; + Tk_Window tkwin = butPtr->tkwin; + Pixmap pixmap; + if (tkwin == NULL || !Tk_IsMapped(tkwin)) { + return; } - if (haveImage) { - mbPtr->inset = mbPtr->highlightWidth; - width += 2*mbPtr->borderWidth; - height += 2*mbPtr->borderWidth; - } else { - mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth; + pixmap = (Pixmap)Tk_WindowId(tkwin); + + Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); +} + +/* + *-------------------------------------------------------------- + * + * MenuButtonContentDrawCB -- + * + * This function draws the label and image for the button. + * + * Results: + * None. + * + * Side effects: + * The content of the button gets updated. + * + *-------------------------------------------------------------- + */ +static void +MenuButtonContentDrawCB ( + ThemeButtonKind kind, + const HIThemeButtonDrawInfo *drawinfo, + MacMenuButton *ptr, + SInt16 depth, + Boolean isColorDev) +{ + TkMenuButton *butPtr = (TkMenuButton *)ptr; + Tk_Window tkwin = butPtr->tkwin; + Rect bounds; + + if (tkwin == NULL || !Tk_IsMapped(tkwin)) { + return; } - Tk_GeometryRequest(mbPtr->tkwin, width + 2 * mbPtr->inset, - height + 2 * mbPtr->inset); - Tk_SetInternalBorder(mbPtr->tkwin, mbPtr->inset); -#ifdef TK_MAC_DEBUG_MENUBUTTON - TKLog(@"menubutton %s bounds %@ titleRect %@ width %d height %d inset %d borderWidth %d", - ((TkWindow *)mbPtr->tkwin)->pathName, NSStringFromRect(bounds), - NSStringFromRect(titleRect), width, height, mbPtr->inset, - mbPtr->borderWidth); -#endif + MacDrawable *macWin = (MacDrawable *) Tk_WindowId(tkwin); + + DrawMenuButtonImageAndText( butPtr); } /* @@ -428,7 +716,7 @@ TkpComputeMenuButtonGeometry( * None. * * Side effects: - * When activation state changes, it is redisplayed. + * When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ @@ -438,27 +726,124 @@ MenuButtonEventProc( ClientData clientData, /* Information about window. */ XEvent *eventPtr) /* Information about event. */ { - TkMenuButton *mbPtr = (TkMenuButton *) clientData; + TkMenuButton *buttonPtr = (TkMenuButton *) clientData; + MacMenuButton *mbPtr = (MacMenuButton *) clientData; + + if (eventPtr->type == ActivateNotify + || eventPtr->type == DeactivateNotify) { + if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) { + return; + } + if (eventPtr->type == ActivateNotify) { + mbPtr->flags |= ACTIVE; + } else { + mbPtr->flags &= ~ACTIVE; + } + if ((buttonPtr->flags & REDRAW_PENDING) == 0) { + Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) buttonPtr); + buttonPtr->flags |= REDRAW_PENDING; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXComputeMenuButtonParams -- + * + * This procedure computes the various parameters used + * when creating a Carbon Appearance control. + * These are determined by the various tk button parameters + * + * Results: + * None. + * + * Side effects: + * Sets the btnkind and drawinfo parameters + * + *---------------------------------------------------------------------- + */ + +static void +TkMacOSXComputeMenuButtonParams(TkMenuButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo *drawinfo) +{ + MacMenuButton *mbPtr = (MacMenuButton *)butPtr; - if (!mbPtr->tkwin || !Tk_IsMapped(mbPtr->tkwin)) { - return; + if (butPtr->image || butPtr->bitmap) { + /* TODO: allow for Small and Mini menubuttons. */ + *btnkind = kThemePopupButton; + } else { + if (!butPtr->text || !*butPtr->text) { + *btnkind = kThemeArrowButton; + } else { + *btnkind = kThemePopupButton; + } } - switch (eventPtr->type) { - case ActivateNotify: - case DeactivateNotify: - if (!(mbPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr); - mbPtr->flags |= REDRAW_PENDING; + + drawinfo->value = kThemeButtonOff; + + if ((mbPtr->flags & FIRST_DRAW) != 0) { + mbPtr->flags &= ~FIRST_DRAW; + if (Tk_MacOSXIsAppInFront()) { + mbPtr->flags |= ACTIVE; } - break; } + + drawinfo->state = kThemeStateInactive; + if ((mbPtr->flags & ACTIVE) == 0) { + if (butPtr->state == STATE_DISABLED) { + drawinfo->state = kThemeStateUnavailableInactive; + } else { + drawinfo->state = kThemeStateInactive; + } + } else if (butPtr->state == STATE_DISABLED) { + drawinfo->state = kThemeStateUnavailable; + } else { + drawinfo->state = kThemeStateActive; + } + + drawinfo->adornment = kThemeAdornmentNone; + if (butPtr->highlightWidth >= 3) { + if ((butPtr->flags & GOT_FOCUS)) { + drawinfo->adornment |= kThemeAdornmentFocus; + } + } + drawinfo->adornment |= kThemeAdornmentArrowDoubleArrow; } /* - * Local Variables: - * mode: objc - * c-basic-offset: 4 - * fill-column: 79 - * coding: utf-8 - * End: + *---------------------------------------------------------------------- + * + * TkMacOSXComputeMenuButtonDrawParams -- + * + * This procedure computes the various parameters used + * when drawing a button + * These are determined by the various tk button parameters + * + * Results: + * 1 if control will be used, 0 otherwise. + * + * Side effects: + * Sets the button draw parameters + * + *---------------------------------------------------------------------- */ + +static int +TkMacOSXComputeMenuButtonDrawParams(TkMenuButton * butPtr, DrawParams * dpPtr) +{ + dpPtr->hasImageOrBitmap = ((butPtr->image != NULL) + || (butPtr->bitmap != None)); + dpPtr->border = butPtr->normalBorder; + if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { + dpPtr->gc = butPtr->disabledGC; + } else if (butPtr->state == STATE_ACTIVE) { + dpPtr->gc = butPtr->activeTextGC; + dpPtr->border = butPtr->activeBorder; + } else { + dpPtr->gc = butPtr->normalTextGC; + } + + return 1; +} + diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index adc7106..3664850 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -180,9 +180,6 @@ MODULE_SCOPE CGFloat tkMacOSXZeroScreenHeight; MODULE_SCOPE CGFloat tkMacOSXZeroScreenTop; MODULE_SCOPE int tkMacOSXGCEnabled; MODULE_SCOPE long tkMacOSXMacOSXVersion; -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS -MODULE_SCOPE int tkMacOSXUseCompatibilityMetrics; -#endif /* * Prototypes for TkMacOSXRegion.c. -- cgit v0.12 From bcde7b5b7afb793a7300bd511a37b78a87c25267 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Fri, 30 Jan 2015 15:27:00 +0000 Subject: Scrolling is now working at an acceptable level; using Unix bindings to drive scrolling in Tk window, and just requiring Mac HITheme scrollbar to re-draw itself --- library/scrlbar.tcl | 4 +- macosx/tkMacOSXInit.c | 9 +- macosx/tkMacOSXScrlbr.c | 794 +++++++++++++++++++----------------------------- 3 files changed, 317 insertions(+), 490 deletions(-) diff --git a/library/scrlbar.tcl b/library/scrlbar.tcl index 1f8c7d2..688d40a 100644 --- a/library/scrlbar.tcl +++ b/library/scrlbar.tcl @@ -14,8 +14,8 @@ # The code below creates the default class bindings for scrollbars. #------------------------------------------------------------------------- -# Standard Motif bindings: -if {[tk windowingsystem] eq "x11"} { +# Standard Motif bindings: +if {[tk windowingsystem] eq "x11" || [tk windowingsystem] eq "aqua"} { bind Scrollbar { if {$tk_strictMotif} { diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index a807dfa..219efd1 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -1,5 +1,5 @@ /* - * tkMacOSXInit.c -- + * tkMacOSXInit.c -- * * This file contains Mac OS X -specific interpreter initialization * functions. @@ -31,7 +31,7 @@ static char scriptPath[PATH_MAX + 1] = ""; int tkMacOSXGCEnabled = 0; long tkMacOSXMacOSXVersion = 0; -#pragma mark TKApplication(TKInit) +#pragma mark TKApplication(TKInit) #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 #define NSTextInputContextKeyboardSelectionDidChangeNotification @"NSTextInputContextKeyboardSelectionDidChangeNotification" @@ -53,10 +53,6 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt - (void) _setupWindowNotifications; @end -@interface TKApplication(TKScrlbr) -- (void) _setupScrollBarNotifications; -@end - @interface TKApplication(TKMenus) - (void) _setupMenus; @end @@ -108,7 +104,6 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt selector:@selector(_postedNotification:) name:nil object:nil]; #endif [self _setupWindowNotifications]; - [self _setupScrollBarNotifications]; [self _setupApplicationNotifications]; } diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index 405558b..afb8e52 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -1,5 +1,5 @@ /* - * tkMacOSXScrollbar.c -- + * tkMacOSXScrollbar.c -- * * This file implements the Macintosh specific portion of the scrollbar * widget. @@ -7,79 +7,24 @@ * Copyright (c) 1996 by Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen - * + * Copyright (c) 2015 Kevin Walzer/WordTech Commununications LLC. * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -#include "tkMacOSXPrivate.h" +#include "tkInt.h" #include "tkScrollbar.h" +#include "tkMacOSXPrivate.h" -/* -#ifdef TK_MAC_DEBUG -#define TK_MAC_DEBUG_SCROLLBAR -#endif -*/ - -NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); - -/* - * A subclass of NSScroller with sanity checking: - * - * NSScrollers created by Tk will have their tag set to a pointer to the - * TkScrollbar which manages the NSScroller. This allows an NSScroller to be - * aware of the state of its Tk parent. This subclass overrides the drawRect - * method so that it will not draw itself if the widget is completely outside - * of its container. - */ - -@interface TkNSScroller: NSScroller --(void) drawRect:(NSRect)dirtyRect; - -@end - -@implementation TkNSScroller - - - (void)drawRect:(NSRect)dirtyRect - { - NSInteger tag = [self tag]; - if ( tag != -1) { - TkScrollbar *scrollPtr = (TkScrollbar *)tag; - MacDrawable* macWin = (MacDrawable *)scrollPtr; - Tk_Window tkwin = scrollPtr->tkwin; - NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); - /* Do not draw if the widget is misplaced or unmapped. */ - if ( NSIsEmptyRect(Tkframe) || - ! macWin->winPtr->flags & TK_MAPPED || - ! NSEqualRects(Tkframe, [self frame]) - ) { - return; - } - - /* - * Do not draw if the widget is completely outside of its parent. - */ - if (tkwin) { - int parent_height = Tk_Height(Tk_Parent(tkwin)); - int widget_height = Tk_Height(tkwin); - int y = Tk_Y(tkwin); - if ( y > parent_height || y + widget_height < 0 ) { - return; - } - - int parent_width = Tk_Width(Tk_Parent(tkwin)); - int widget_width = Tk_Width(tkwin); - int x = Tk_X(tkwin); - if (x > parent_width || x + widget_width < 0) { - return; - } - } - } - [super drawRect:dirtyRect]; - } -@end +#define MIN_SCROLLBAR_VALUE 0 +/*Borrowed from ttkMacOSXTheme.c to provide appropriate scaling of scrollbar values.*/ +#ifdef __LP64__ +#define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum)) +#else +#define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum)) +#endif /* __LP64__ */ /* @@ -87,33 +32,15 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); */ typedef struct MacScrollbar { - TkScrollbar info; - TkNSScroller *scroller; - int variant; + TkScrollbar information; /* Generic scrollbar info. */ + GC troughGC; /* For drawing trough. */ + GC copyGC; /* Used for copying from pixmap onto screen. */ } MacScrollbar; -typedef struct ScrollbarMetrics { - SInt32 width, minThumbHeight; - int minHeight, topArrowHeight, bottomArrowHeight; - NSControlSize controlSize; -} ScrollbarMetrics; - -static ScrollbarMetrics metrics[2] = { - {15, 54, 26, 14, 14, NSRegularControlSize}, /* kThemeScrollBarMedium */ - {11, 40, 20, 10, 10, NSSmallControlSize}, /* kThemeScrollBarSmall */ -}; - /* - * Declarations for functions defined in this file. - */ - -static void UpdateScrollbarMetrics(void); -static void ScrollbarEventProc(ClientData clientData, - XEvent *eventPtr); - - -/* - * The class procedure table for the scrollbar widget. + * The class procedure table for the scrollbar widget. All fields except size + * are left initialized to NULL, which should happen automatically since the + * variable is declared at this scope. */ const Tk_ClassProcs tkpScrollbarProcs = { @@ -122,151 +49,38 @@ const Tk_ClassProcs tkpScrollbarProcs = { NULL, /* createProc */ NULL /* modalProc */ }; - -#pragma mark TKApplication(TKScrlbr) - -#define NSAppleAquaScrollBarVariantChanged @"AppleAquaScrollBarVariantChanged" - -@implementation TKApplication(TKScrlbr) -- (void) tkScroller: (TkNSScroller *) scroller -{ - NSScrollerPart hitPart = [scroller hitPart]; - TkScrollbar *scrollPtr = (TkScrollbar *)[scroller tag]; - Tcl_DString cmdString; - Tcl_Interp *interp; - int result; - - if (!scrollPtr || !scrollPtr->command || !scrollPtr->commandSize || - hitPart == NSScrollerNoPart) { - return; - } - Tcl_DStringInit(&cmdString); - Tcl_DStringAppend(&cmdString, scrollPtr->command, - scrollPtr->commandSize); - switch (hitPart) { - case NSScrollerKnob: - case NSScrollerKnobSlot: { - char valueString[TCL_DOUBLE_SPACE]; - - Tcl_PrintDouble(NULL, [scroller doubleValue] * - (1.0 - [scroller knobProportion]), valueString); - Tcl_DStringAppendElement(&cmdString, "moveto"); - Tcl_DStringAppendElement(&cmdString, valueString); - break; - } - case NSScrollerDecrementLine: - case NSScrollerIncrementLine: - Tcl_DStringAppendElement(&cmdString, "scroll"); - Tcl_DStringAppendElement(&cmdString, - (hitPart == NSScrollerDecrementLine) ? "-1" : "1"); - Tcl_DStringAppendElement(&cmdString, "unit"); - break; - case NSScrollerDecrementPage: - case NSScrollerIncrementPage: - Tcl_DStringAppendElement(&cmdString, "scroll"); - Tcl_DStringAppendElement(&cmdString, - (hitPart == NSScrollerDecrementPage) ? "-1" : "1"); - Tcl_DStringAppendElement(&cmdString, "page"); - break; - } - interp = scrollPtr->interp; - Tcl_Preserve(interp); - Tcl_Preserve(scrollPtr); - result = Tcl_EvalEx(interp, Tcl_DStringValue(&cmdString), - Tcl_DStringLength(&cmdString), TCL_EVAL_GLOBAL); - if (result != TCL_OK && result != TCL_CONTINUE && result != TCL_BREAK) { - Tcl_AddErrorInfo(interp, "\n (scrollbar command)"); - Tcl_BackgroundException(interp, result); - } - Tcl_Release(scrollPtr); - Tcl_Release(interp); - Tcl_DStringFree(&cmdString); -#ifdef TK_MAC_DEBUG_SCROLLBAR - TKLog(@"scroller %s value %f knobProportion %f", - ((TkWindow *)scrollPtr->tkwin)->pathName, [scroller doubleValue], - [scroller knobProportion]); -#endif -} -- (void) scrollBarVariantChanged: (NSNotification *) notification -{ -#ifdef TK_MAC_DEBUG_NOTIFICATIONS - TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); -#endif - UpdateScrollbarMetrics(); -} +/*Information on scrollbar layout, metrics, and draw info.*/ +typedef struct ScrollbarMetrics { + SInt32 width, minThumbHeight; + int minHeight, topArrowHeight, bottomArrowHeight; + NSControlSize controlSize; +} ScrollbarMetrics; -- (void) _setupScrollBarNotifications -{ - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; +static ScrollbarMetrics metrics[2] = { + {15, 54, 26, 14, 14, NSRegularControlSize}, /* kThemeScrollBarMedium */ + {11, 40, 20, 10, 10, NSSmallControlSize}, /* kThemeScrollBarSmall */ +}; -#define observe(n, s) [nc addObserver:self selector:@selector(s) name:(n) object:nil] - observe(NSAppleAquaScrollBarVariantChanged, scrollBarVariantChanged:); -#undef observe +HIThemeTrackDrawInfo info = { + .version = 0, + .min = 0.0, + .max = 100.0, + .attributes = kThemeTrackShowThumb, + .kind = kThemeScrollBarMedium, +}; - UpdateScrollbarMetrics(); -} -@end -#pragma mark - - /* - *---------------------------------------------------------------------- - * - * UpdateScrollbarMetrics -- - * - * This function retrieves the current system metrics for a scrollbar. - * - * Results: - * None. - * - * Side effects: - * Updates the geometry cache info for all scrollbars. - * - *---------------------------------------------------------------------- + * Forward declarations for procedures defined later in this file: */ -static void -UpdateScrollbarMetrics(void) -{ - const short height = 100, width = 50; - HIThemeTrackDrawInfo info = { - .version = 0, - .bounds = {{0, 0}, {width, height}}, - .min = 0, - .max = 1, - .value = 0, - .attributes = kThemeTrackShowThumb, - .enableState = kThemeTrackActive, - .trackInfo.scrollbar = {.viewsize = 1, .pressState = 0}, - }; - CGRect bounds; - - ChkErr(GetThemeMetric, kThemeMetricScrollBarWidth, &metrics[0].width); - ChkErr(GetThemeMetric, kThemeMetricScrollBarMinThumbHeight, - &metrics[0].minThumbHeight); - info.kind = kThemeScrollBarMedium; - ChkErr(HIThemeGetTrackDragRect, &info, &bounds); - metrics[0].topArrowHeight = bounds.origin.y; - metrics[0].bottomArrowHeight = height - (bounds.origin.y + - bounds.size.height); - metrics[0].minHeight = metrics[0].minThumbHeight + - metrics[0].topArrowHeight + metrics[0].bottomArrowHeight; - ChkErr(GetThemeMetric, kThemeMetricSmallScrollBarWidth, &metrics[1].width); - ChkErr(GetThemeMetric, kThemeMetricSmallScrollBarMinThumbHeight, - &metrics[1].minThumbHeight); - info.kind = kThemeScrollBarSmall; - ChkErr(HIThemeGetTrackDragRect, &info, &bounds); - metrics[1].topArrowHeight = bounds.origin.y; - metrics[1].bottomArrowHeight = height - (bounds.origin.y + - bounds.size.height); - metrics[1].minHeight = metrics[1].minThumbHeight + - metrics[1].topArrowHeight + metrics[1].bottomArrowHeight; - - sprintf(tkDefScrollbarWidth, "%d", (int)(metrics[0].width)); -} - +static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr); +static int ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr); +static void UpdateControlValues(TkScrollbar *scrollPtr); + + /* *---------------------------------------------------------------------- * @@ -285,41 +99,19 @@ UpdateScrollbarMetrics(void) TkScrollbar * TkpCreateScrollbar( - Tk_Window tkwin) + Tk_Window tkwin) { - MacScrollbar *scrollPtr = ckalloc(sizeof(MacScrollbar)); - scrollPtr->scroller = nil; - Tk_CreateEventHandler(tkwin, StructureNotifyMask|FocusChangeMask| - ActivateMask|ExposureMask, ScrollbarEventProc, scrollPtr); - return (TkScrollbar *) scrollPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TkpDestroyScrollbar -- - * - * Free data structures associated with the scrollbar control. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ + static int initialized = 0; + MacScrollbar *scrollPtr = ckalloc(sizeof(MacScrollbar)); -void -TkpDestroyScrollbar( - TkScrollbar *scrollPtr) -{ - MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; - TkNSScroller *scroller = macScrollPtr->scroller; - [scroller setTag:(NSInteger)-1]; + scrollPtr->troughGC = None; + scrollPtr->copyGC = None; + TkWindow *winPtr = (TkWindow *)tkwin; - TkMacOSXMakeCollectableAndRelease(macScrollPtr->scroller); + Tk_CreateEventHandler(tkwin,ExposureMask|StructureNotifyMask|FocusChangeMask|ButtonPressMask|VisibilityChangeMask, ScrollbarEventProc, scrollPtr); + + return (TkScrollbar *) scrollPtr; } /* @@ -328,8 +120,8 @@ TkpDestroyScrollbar( * TkpDisplayScrollbar -- * * This procedure redraws the contents of a scrollbar window. It is - * invoked as a do-when-idle handler, so it only runs when there's nothing - * else for the application to do. + * invoked as a do-when-idle handler, so it only runs when there's + * nothing else for the application to do. * * Results: * None. @@ -342,95 +134,67 @@ TkpDestroyScrollbar( void TkpDisplayScrollbar( - ClientData clientData) /* Information about window. */ + ClientData clientData) /* Information about window. */ { - TkScrollbar *scrollPtr = clientData; + register TkScrollbar *scrollPtr = (TkScrollbar *) clientData; + register Tk_Window tkwin = scrollPtr->tkwin; + + + if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { + return; + } + MacScrollbar *macScrollPtr = clientData; - TkNSScroller *scroller = macScrollPtr->scroller; - Tk_Window tkwin = scrollPtr->tkwin; TkWindow *winPtr = (TkWindow *) tkwin; MacDrawable *macWin = (MacDrawable *) winPtr->window; TkMacOSXDrawingContext dc; NSView *view = TkMacOSXDrawableView(macWin); CGFloat viewHeight = [view bounds].size.height; CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, - .ty = viewHeight}; - NSRect frame; - double knobProportion = scrollPtr->lastFraction - scrollPtr->firstFraction; + .ty = viewHeight}; + scrollPtr->flags &= ~REDRAW_PENDING; if (!scrollPtr->tkwin || !Tk_IsMapped(tkwin) || !view || - !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { - return; + !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { + return; } + CGContextConcatCTM(dc.context, t); + + /*Draw Unix-style scroll trough to provide rect for native scrollbar.*/ if (scrollPtr->highlightWidth != 0) { - GC fgGC, bgGC; - - bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin); - if (scrollPtr->flags & GOT_FOCUS) { - fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin); - } else { - fgGC = bgGC; - } - TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth, - (Pixmap) macWin); - } - Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, - scrollPtr->highlightWidth, scrollPtr->highlightWidth, - Tk_Width(tkwin) - 2*scrollPtr->highlightWidth, - Tk_Height(tkwin) - 2*scrollPtr->highlightWidth, - scrollPtr->borderWidth, scrollPtr->relief); - Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, - scrollPtr->inset, scrollPtr->inset, - Tk_Width(tkwin) - 2*scrollPtr->inset, - Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT); - if ([scroller superview] != view) { - [view addSubview:scroller]; + GC fgGC, bgGC; + + bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin); + if (scrollPtr->flags & GOT_FOCUS) { + fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin); + } else { + fgGC = bgGC; + } + TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth, + (Pixmap) macWin); } - frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin), - Tk_Height(tkwin)); - frame = NSInsetRect(frame, scrollPtr->inset, scrollPtr->inset); - frame.origin.y = viewHeight - (frame.origin.y + frame.size.height); - NSWindow *w = [view window]; - //This uses a private API call that is no longer needed on systems >= 10.7. - #if 0 - if ([w showsResizeIndicator]) { - NSRect growBox = [view convertRect:[w _growBoxRect] fromView:nil]; - - if (NSIntersectsRect(growBox, frame)) { - if (scrollPtr->vertical) { - CGFloat y = frame.origin.y; + Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, + scrollPtr->highlightWidth, scrollPtr->highlightWidth, + Tk_Width(tkwin) - 2*scrollPtr->highlightWidth, + Tk_Height(tkwin) - 2*scrollPtr->highlightWidth, + scrollPtr->borderWidth, scrollPtr->relief); + Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, + scrollPtr->inset, scrollPtr->inset, + Tk_Width(tkwin) - 2*scrollPtr->inset, + Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT); - frame.origin.y = growBox.origin.y + growBox.size.height; - frame.size.height -= frame.origin.y - y; - } else { - frame.size.width = growBox.origin.x - frame.origin.x; - } - TkMacOSXSetScrollbarGrow(winPtr, true); - } - } - #endif - if (!NSEqualRects(frame, [scroller frame])) { - [scroller setFrame:frame]; - } - [scroller setEnabled:(knobProportion < 1.0 && - (scrollPtr->vertical ? frame.size.height : frame.size.width) > - metrics[macScrollPtr->variant].minHeight)]; - // [scroller setEnabled: YES]; - [scroller setDoubleValue:scrollPtr->firstFraction / (1.0 - knobProportion)]; - [scroller setKnobProportion:knobProportion]; - [scroller displayRectIgnoringOpacity:[scroller bounds]]; + /*Update values and draw in native rect.*/ + UpdateControlValues(scrollPtr); + HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); TkMacOSXRestoreDrawingContext(&dc); - #ifdef TK_MAC_DEBUG_SCROLLBAR - TKLog(@"scroller %s frame %@ width %d height %d", - ((TkWindow *)scrollPtr->tkwin)->pathName, NSStringFromRect(frame), - Tk_Width(tkwin), Tk_Height(tkwin)); - #endif + + scrollPtr->flags &= ~REDRAW_PENDING; } - + /* *---------------------------------------------------------------------- * @@ -449,123 +213,106 @@ TkpDisplayScrollbar( *---------------------------------------------------------------------- */ -void +extern void TkpComputeScrollbarGeometry( - register TkScrollbar *scrollPtr) - /* Scrollbar whose geometry may have - * changed. */ + register TkScrollbar *scrollPtr) +/* Scrollbar whose geometry may have + * changed. */ { - MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; - TkNSScroller *scroller = macScrollPtr->scroller; + int width, height, variant, fieldLength; if (scrollPtr->highlightWidth < 0) { - scrollPtr->highlightWidth = 0; + scrollPtr->highlightWidth = 0; } scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth; - width = Tk_Width(scrollPtr->tkwin) - 2 * scrollPtr->inset; - height = Tk_Height(scrollPtr->tkwin) - 2 * scrollPtr->inset; - variant = ((scrollPtr->vertical ? width : height) < metrics[0].width) ? - 1 : 0; - macScrollPtr->variant = variant; - if (scroller) { - NSSize size = [scroller frame].size; - - if ((size.width > size.height) ^ !scrollPtr->vertical) { - /* - * Orientation changed, need new scroller. - */ - - if ([scroller superview]) { - [scroller removeFromSuperviewWithoutNeedingDisplay]; - } - TkMacOSXMakeCollectableAndRelease(scroller); - } - } - if (!scroller) { - if ((width > height) ^ !scrollPtr->vertical) { - /* -[NSScroller initWithFrame:] determines horizontalness for the - * lifetime of the scroller via isHoriz = (width > height) */ - if (scrollPtr->vertical) { - width = height; - } else if (width > 1) { - height = width - 1; - } else { - height = 1; - width = 2; - } - } - scroller = [[TkNSScroller alloc] initWithFrame: - NSMakeRect(0, 0, width, height)]; - macScrollPtr->scroller = TkMacOSXMakeUncollectable(scroller); - [scroller setAction:@selector(tkScroller:)]; - [scroller setTarget:NSApp]; - [scroller setTag:(NSInteger)scrollPtr]; - } - [[scroller cell] setControlSize:metrics[variant].controlSize]; - + variant = ((scrollPtr->vertical ? Tk_Width(scrollPtr->tkwin) : + Tk_Height(scrollPtr->tkwin)) - 2 * scrollPtr->inset + < metrics[0].width) ? 1 : 0; scrollPtr->arrowLength = (metrics[variant].topArrowHeight + - metrics[variant].bottomArrowHeight) / 2; + metrics[variant].bottomArrowHeight) / 2; fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin) - : Tk_Width(scrollPtr->tkwin)) - - 2 * (scrollPtr->arrowLength + scrollPtr->inset); + : Tk_Width(scrollPtr->tkwin)) + - 2 * (scrollPtr->arrowLength + scrollPtr->inset); if (fieldLength < 0) { - fieldLength = 0; + fieldLength = 0; } scrollPtr->sliderFirst = fieldLength * scrollPtr->firstFraction; scrollPtr->sliderLast = fieldLength * scrollPtr->lastFraction; /* - * Adjust the slider so that some piece of it is always displayed in the - * scrollbar and so that it has at least a minimal width (so it can be - * grabbed with the mouse). + * Adjust the slider so that some piece of it is always + * displayed in the scrollbar and so that it has at least + * a minimal width (so it can be grabbed with the mouse). */ if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) { - scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth; + scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth; } if (scrollPtr->sliderFirst < 0) { - scrollPtr->sliderFirst = 0; + scrollPtr->sliderFirst = 0; } if (scrollPtr->sliderLast < (scrollPtr->sliderFirst + - metrics[variant].minThumbHeight)) { - scrollPtr->sliderLast = scrollPtr->sliderFirst + - metrics[variant].minThumbHeight; + metrics[variant].minThumbHeight)) { + scrollPtr->sliderLast = scrollPtr->sliderFirst + + metrics[variant].minThumbHeight; } if (scrollPtr->sliderLast > fieldLength) { - scrollPtr->sliderLast = fieldLength; + scrollPtr->sliderLast = fieldLength; } scrollPtr->sliderFirst += scrollPtr->inset + - metrics[variant].topArrowHeight; + metrics[variant].topArrowHeight; scrollPtr->sliderLast += scrollPtr->inset + - metrics[variant].bottomArrowHeight; + metrics[variant].bottomArrowHeight; /* - * Register the desired geometry for the window (leave enough space for - * the two arrows plus a minimum-size slider, plus border around the whole - * window, if any). Then arrange for the window to be redisplayed. + * Register the desired geometry for the window (leave enough space + * for the two arrows plus a minimum-size slider, plus border around + * the whole window, if any). Then arrange for the window to be + * redisplayed. */ if (scrollPtr->vertical) { - Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width + - 2 * scrollPtr->inset, 2 * (scrollPtr->arrowLength + - scrollPtr->borderWidth + scrollPtr->inset) + - metrics[variant].minThumbHeight); + Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width + 2 * scrollPtr->inset, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics[variant].minThumbHeight); } else { - Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength + - scrollPtr->borderWidth + scrollPtr->inset) + - metrics[variant].minThumbHeight, scrollPtr->width + - 2 * scrollPtr->inset); + Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics[variant].minThumbHeight, scrollPtr->width + 2 * scrollPtr->inset); } Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset); -#ifdef TK_MAC_DEBUG_SCROLLBAR - TKLog(@"scroller %s bounds %@ width %d height %d inset %d borderWidth %d", - ((TkWindow *)scrollPtr->tkwin)->pathName, - NSStringFromRect([scroller bounds]), - width, height, scrollPtr->inset, scrollPtr->borderWidth); -#endif + } - + +/* + *---------------------------------------------------------------------- + * + * TkpDestroyScrollbar -- + * + * Free data structures associated with the scrollbar control. + * + * Results: + * None. + * + * Side effects: + * Frees the GCs associated with the scrollbar. + * + *---------------------------------------------------------------------- + */ + +void +TkpDestroyScrollbar( + TkScrollbar *scrollPtr) +{ + MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr; + + if (macScrollPtr->troughGC != None) { + Tk_FreeGC(scrollPtr->display, macScrollPtr->troughGC); + } + if (macScrollPtr->copyGC != None) { + Tk_FreeGC(scrollPtr->display, macScrollPtr->copyGC); + } + + macScrollPtr=NULL; +} + /* *---------------------------------------------------------------------- * @@ -579,19 +326,20 @@ TkpComputeScrollbarGeometry( * None. * * Side effects: - * None. + * Configuration info may get changed. * *---------------------------------------------------------------------- */ void TkpConfigureScrollbar( - register TkScrollbar *scrollPtr) - /* Information about widget; may or may not - * already have values for some fields. */ + register TkScrollbar *scrollPtr) +/* Information about widget; may or may not + * already have values for some fields. */ { + } - + /* *-------------------------------------------------------------- * @@ -616,30 +364,159 @@ TkpScrollbarPosition( /* Scrollbar widget record. */ int x, int y) /* Coordinates within scrollPtr's window. */ { - TkNSScroller *scroller = ((MacScrollbar *) scrollPtr)->scroller; - MacDrawable *macWin = (MacDrawable *) - ((TkWindow *) scrollPtr->tkwin)->window; - NSView *view = TkMacOSXDrawableView(macWin); - switch ([scroller testPart:NSMakePoint(macWin->xOff + x, - [view bounds].size.height - (macWin->yOff + y))]) { - case NSScrollerDecrementLine: + /*Using code from tkUnixScrlbr.c because Unix scroll bindings are driving the display at the script level. All the Mac scrollbar has to do is re-draw itself.*/ + + int length, width, tmp; + register const int inset = scrollPtr->inset; + + if (scrollPtr->vertical) { + length = Tk_Height(scrollPtr->tkwin); + width = Tk_Width(scrollPtr->tkwin); + } else { + tmp = x; + x = y; + y = tmp; + length = Tk_Width(scrollPtr->tkwin); + width = Tk_Height(scrollPtr->tkwin); + } + + if (x=width-inset || y=length-inset) { + return OUTSIDE; + } + + /* + * All of the calculations in this procedure mirror those in + * TkpDisplayScrollbar. Be sure to keep the two consistent. + */ + + if (y < inset + scrollPtr->arrowLength) { return TOP_ARROW; - case NSScrollerDecrementPage: + } + if (y < scrollPtr->sliderFirst) { return TOP_GAP; - case NSScrollerKnob: + } + if (y < scrollPtr->sliderLast) { return SLIDER; - case NSScrollerIncrementPage: - return BOTTOM_GAP; - case NSScrollerIncrementLine: + } + if (y >= length - (scrollPtr->arrowLength + inset)) { return BOTTOM_ARROW; - case NSScrollerKnobSlot: - case NSScrollerNoPart: - default: - return OUTSIDE; } + return BOTTOM_GAP; } - + +/* + *-------------------------------------------------------------- + * + * UpdateControlValues -- + * + * This procedure updates the Macintosh scrollbar control to display the + * values defined by the Tk scrollbar. This is the key interface to the Mac-native * scrollbar; the Unix bindings drive scrolling in the Tk window and all the Mac + * scrollbar has to do is redraw itself. + * + * Results: + * None. + * + * Side effects: + * The Macintosh control is updated. + * + *-------------------------------------------------------------- + */ + +static void +UpdateControlValues( + TkScrollbar *scrollPtr) /* Scrollbar data struct. */ +{ + + Tk_Window tkwin = scrollPtr->tkwin; + MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin); + double dViewSize; + HIRect contrlRect; + int variant, active; + short width, height; + + NSView *view = TkMacOSXDrawableView(macWin); + CGFloat viewHeight = [view bounds].size.height; + NSRect frame; + frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin), + Tk_Height(tkwin)); + frame = NSInsetRect(frame, scrollPtr->inset, scrollPtr->inset); + frame.origin.y = viewHeight - (frame.origin.y + frame.size.height); + + contrlRect = NSRectToCGRect(frame); + info.bounds = contrlRect; + + width = contrlRect.size.width; + height = contrlRect.size.height; + + variant = contrlRect.size.width < metrics[0].width ? 1 : 0; + + /* + * Ensure we set scrollbar control bounds only once all size adjustments + * have been computed. + */ + + info.bounds = contrlRect; + if (!scrollPtr->vertical) { + info.attributes |= kThemeTrackHorizontal; + } + + /* + * Given the Tk parameters for the fractions of the start and end of the + * thumb, the following calculation determines the location for the + * Macintosh thumb. The Aqua scroll control works as follows. The + * scrollbar's value is the position of the left (or top) side of the view + * area in the content area being scrolled. The maximum value of the + * control is therefore the dimension of the content area less the size of + * the view area. + */ + + double maximum = 100, factor; + factor = RangeToFactor(maximum); + dViewSize = (scrollPtr->lastFraction - scrollPtr->firstFraction) + * factor; + info.max = MIN_SCROLLBAR_VALUE + + factor - dViewSize; + info.trackInfo.scrollbar.viewsize = dViewSize; + if (scrollPtr->vertical) { + info.value = info.max - factor * scrollPtr->firstFraction; + } else { + info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction; + } + + if((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0) + || height <= metrics[variant].minHeight) { + info.enableState = kThemeTrackHideTrack; + } else { + info.enableState = kThemeTrackActive; + info.attributes = kThemeTrackShowThumb | kThemeTrackThumbRgnIsNotGhost; + } + +} + +/* + *-------------------------------------------------------------- + * + * ScrollbarPress -- + * + * This procedure is invoked in response to events. + * Enters a modal loop to handle scrollbar interactions. + * + *-------------------------------------------------------------- + */ + +static int +ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr) +{ + + if (eventPtr->type == ButtonPress) { + UpdateControlValues(scrollPtr); + return TCL_OK; + } +} + + + /* *-------------------------------------------------------------- * @@ -660,8 +537,8 @@ TkpScrollbarPosition( static void ScrollbarEventProc( - ClientData clientData, /* Information about window. */ - XEvent *eventPtr) /* Information about event. */ + ClientData clientData, /* Information about window. */ + XEvent *eventPtr) /* Information about event. */ { TkScrollbar *scrollPtr = clientData; @@ -673,55 +550,10 @@ ScrollbarEventProc( case DeactivateNotify: TkScrollbarEventuallyRedraw(scrollPtr); break; + case ButtonPress: + ScrollbarPress(clientData, eventPtr); + break; default: TkScrollbarEventProc(clientData, eventPtr); } } - - -/* - *---------------------------------------------------------------------- - * - * TkMacOSXGetScrollFrame -- - * - * Computes a frame for an NSScroller that will correspond to where - * Tk thinks the scroller is located. - * - * Results: - * Returns an NSRect describing a frame for an NSScrollbar. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ -NSRect TkMacOSXGetScrollFrame( - TkScrollbar *scrlPtr) -{ - MacScrollbar *macscrlPtr = (MacScrollbar *) scrlPtr; - Tk_Window tkwin = scrlPtr->tkwin; - TkWindow *winPtr = (TkWindow *) tkwin; - if (tkwin) { - MacDrawable *macWin = (MacDrawable *) winPtr->window; - NSView *view = TkMacOSXDrawableView(macWin); - CGFloat viewHeight = [view bounds].size.height; - NSRect frame = NSMakeRect(macWin->xOff, macWin->yOff, - Tk_Width(tkwin), Tk_Height(tkwin)); - - frame.origin.y = viewHeight - (frame.origin.y + frame.size.height); - return frame; - } else { - return NSZeroRect; - } -} - - - -/* - * Local Variables: - * mode: objc - * c-basic-offset: 4 - * fill-column: 79 - * coding: utf-8 - * End: - */ -- cgit v0.12 From 0547516d16dcfe830857541e6be7c9316bfe8a61 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 2 Feb 2015 09:50:46 +0000 Subject: Remove unnecessary end-of-line spacing --- generic/ttk/ttkGenStubs.tcl | 6 ++-- library/button.tcl | 4 +-- library/choosedir.tcl | 4 +-- library/clrpick.tcl | 22 ++++++------ library/comdlg.tcl | 6 ++-- library/console.tcl | 8 ++--- library/dialog.tcl | 2 +- library/entry.tcl | 4 +-- library/fontchooser.tcl | 2 +- library/mkpsenc.tcl | 6 ++-- library/msgbox.tcl | 6 ++-- library/palette.tcl | 10 +++--- library/scrlbar.tcl | 2 +- library/spinbox.tcl | 4 +-- library/tearoff.tcl | 2 +- library/tk.tcl | 8 ++--- library/unsupported.tcl | 2 +- library/xmfbox.tcl | 28 ++++++++-------- macosx/tkMacOSXButton.c | 66 ++++++++++++++++++------------------ macosx/tkMacOSXInit.c | 4 +-- macosx/tkMacOSXMenubutton.c | 82 ++++++++++++++++++++++----------------------- macosx/tkMacOSXScrlbr.c | 36 ++++++++++---------- 22 files changed, 157 insertions(+), 157 deletions(-) diff --git a/generic/ttk/ttkGenStubs.tcl b/generic/ttk/ttkGenStubs.tcl index 034f405..56ba2fa 100644 --- a/generic/ttk/ttkGenStubs.tcl +++ b/generic/ttk/ttkGenStubs.tcl @@ -12,7 +12,7 @@ # # SOURCE: tcl/tools/genStubs.tcl, revision 1.44 # -# CHANGES: +# CHANGES: # + Second argument to "declare" is used as a status guard # instead of a platform guard. # + Allow trailing semicolon in function declarations @@ -678,7 +678,7 @@ proc genStubs::addGuard {status text} { set upName [string toupper $libraryName] switch -- $status { - current { + current { # No change } deprecated { @@ -691,7 +691,7 @@ proc genStubs::addGuard {status text} { puts stderr "Unrecognized status code $status" } } - return $text + return $text } proc genStubs::ifdeffed {macro text} { diff --git a/library/button.tcl b/library/button.tcl index c48515a..b2bafb2 100644 --- a/library/button.tcl +++ b/library/button.tcl @@ -17,7 +17,7 @@ #------------------------------------------------------------------------- if {[tk windowingsystem] eq "aqua"} { - + bind Radiobutton { tk::ButtonEnter %W } @@ -144,7 +144,7 @@ bind Radiobutton { if {"win32" eq [tk windowingsystem]} { ######################### -# Windows implementation +# Windows implementation ######################### # ::tk::ButtonEnter -- diff --git a/library/choosedir.tcl b/library/choosedir.tcl index c0ab326..68dd9b0 100644 --- a/library/choosedir.tcl +++ b/library/choosedir.tcl @@ -122,7 +122,7 @@ proc ::tk::dialog::file::chooseDir:: {args} { # Return value to user # - + return $Priv(selectFilePath) } @@ -164,7 +164,7 @@ proc ::tk::dialog::file::chooseDir::Config {dataName argList} { if {$data(-title) eq ""} { set data(-title) "[mc "Choose Directory"]" } - + # Stub out the -multiple value for the dialog; it doesn't make sense for # choose directory dialogs, but we have to have something there because we # share so much code with the file dialogs. diff --git a/library/clrpick.tcl b/library/clrpick.tcl index 3772a30..600be16 100644 --- a/library/clrpick.tcl +++ b/library/clrpick.tcl @@ -12,7 +12,7 @@ # # (1): Find out how many free colors are left in the colormap and # don't allocate too many colors. -# (2): Implement HSV color selection. +# (2): Implement HSV color selection. # # Make sure namespaces exist @@ -54,11 +54,11 @@ proc ::tk::dialog::color:: {args} { set data(BARS_WIDTH) 160 # PLGN_WIDTH is the number of pixels wide of the triangular selection - # polygon. This also results in the definition of the padding on the + # polygon. This also results in the definition of the padding on the # left and right sides which is half of PLGN_WIDTH. Make this number even. set data(PLGN_HEIGHT) 10 - # PLGN_HEIGHT is the height of the selection polygon and the height of the + # PLGN_HEIGHT is the height of the selection polygon and the height of the # selection rectangle at the bottom of the color bar. No restrictions. set data(PLGN_WIDTH) 10 @@ -328,7 +328,7 @@ proc ::tk::dialog::color::BuildDialog {w} { # Sets the current selection of the dialog box # proc ::tk::dialog::color::SetRGBValue {w color} { - upvar ::tk::dialog::color::[winfo name $w] data + upvar ::tk::dialog::color::[winfo name $w] data set data(red,intensity) [lindex $color 0] set data(green,intensity) [lindex $color 1] @@ -368,7 +368,7 @@ proc ::tk::dialog::color::RgbToX {w color} { } # ::tk::dialog::color::DrawColorScale -- -# +# # Draw color scale is called whenever the size of one of the color # scale canvases is changed. # @@ -507,7 +507,7 @@ proc ::tk::dialog::color::RedrawColorBars {w colorChanged} { upvar ::tk::dialog::color::[winfo name $w] data switch $colorChanged { - red { + red { DrawColorScale $w green DrawColorScale $w blue } @@ -537,7 +537,7 @@ proc ::tk::dialog::color::RedrawColorBars {w colorChanged} { # Handles a mousedown button event over the selector polygon. # Adds the bindings for moving the mouse while the button is # pressed. Sets the binding for the button-release event. -# +# # Params: sel is the selector canvas window, color is the color of the strip. # proc ::tk::dialog::color::StartMove {w sel color x delta {dontMove 0}} { @@ -549,7 +549,7 @@ proc ::tk::dialog::color::StartMove {w sel color x delta {dontMove 0}} { } # ::tk::dialog::color::MoveSelector -- -# +# # Moves the polygon selector so that its middle point has the same # x value as the specified x. If x is outside the bounds [0,255], # the selector is set to the closest endpoint. @@ -583,7 +583,7 @@ proc ::tk::dialog::color::MoveSelector {w sel color x delta} { # x is the x-coord of the mouse. # proc ::tk::dialog::color::ReleaseMouse {w sel color x delta} { - upvar ::tk::dialog::color::[winfo name $w] data + upvar ::tk::dialog::color::[winfo name $w] data set x [MoveSelector $w $sel $color $x $delta] @@ -602,7 +602,7 @@ proc ::tk::dialog::color::ResizeColorBars {w} { upvar ::tk::dialog::color::[winfo name $w] data if { - ($data(BARS_WIDTH) < $data(NUM_COLORBARS)) || + ($data(BARS_WIDTH) < $data(NUM_COLORBARS)) || (($data(BARS_WIDTH) % $data(NUM_COLORBARS)) != 0) } then { set data(BARS_WIDTH) $data(NUM_COLORBARS) @@ -660,7 +660,7 @@ proc ::tk::dialog::color::HandleRGBEntry {w} { SetRGBValue $w "$data(red,intensity) \ $data(green,intensity) $data(blue,intensity)" -} +} # mouse cursor enters a color bar # diff --git a/library/comdlg.tcl b/library/comdlg.tcl index f89754c..18df8a6 100644 --- a/library/comdlg.tcl +++ b/library/comdlg.tcl @@ -180,7 +180,7 @@ proc ::tk::FocusGroup_Destroy {t w} { if {$t eq $w} { unset Priv(fg,$t) - unset Priv(focus,$t) + unset Priv(focus,$t) foreach name [array names FocusIn $t,*] { unset FocusIn($name) @@ -277,7 +277,7 @@ proc ::tk::FDGetFileTypes {string} { continue } - # Validate each macType. This is to agree with the + # Validate each macType. This is to agree with the # behaviour of TkGetFileFilters(). This list may be # empty. foreach macType [lindex $t 2] { @@ -286,7 +286,7 @@ proc ::tk::FDGetFileTypes {string} { "bad Macintosh file type \"$macType\"" } } - + set name "$label \(" set sep "" set doAppend 1 diff --git a/library/console.tcl b/library/console.tcl index e93a39d..566140f 100644 --- a/library/console.tcl +++ b/library/console.tcl @@ -311,7 +311,7 @@ proc ::tk::ConsoleHistory {cmd} { # ::tk::ConsolePrompt -- # This procedure draws the prompt. If tcl_prompt1 or tcl_prompt2 -# exists in the main interpreter it will be called to generate the +# exists in the main interpreter it will be called to generate the # prompt. Otherwise, a hard coded default prompt is printed. # # Arguments: @@ -781,7 +781,7 @@ proc ::tk::console::TagProc w { # c2 - second char of pair # # Calls: ::tk::console::Blink - + proc ::tk::console::MatchPair {w c1 c2 {lim 1.0}} { if {!$::tk::console::magicKeys} { return @@ -836,7 +836,7 @@ proc ::tk::console::MatchPair {w c1 c2 {lim 1.0}} { # w - console text widget # # Calls: ::tk::console::Blink - + proc ::tk::console::MatchQuote {w {lim 1.0}} { if {!$::tk::console::magicKeys} { return @@ -971,7 +971,7 @@ proc ::tk::console::Expand {w {type ""}} { # # Returns: list containing longest unique match followed by all the # possible further matches - + proc ::tk::console::ExpandPathname str { set pwd [EvalAttached pwd] if {[catch {EvalAttached [list cd [file dirname $str]]} err opt]} { diff --git a/library/dialog.tcl b/library/dialog.tcl index 6a9babb..22c4dd3 100644 --- a/library/dialog.tcl +++ b/library/dialog.tcl @@ -149,7 +149,7 @@ proc ::tk_dialog {w title text bitmap default args} { # so we know how big it wants to be, then center the window in the # display (Motif style) and de-iconify it. - ::tk::PlaceWindow $w + ::tk::PlaceWindow $w tkwait visibility $w # 7. Set a grab and claim the focus too. diff --git a/library/entry.tcl b/library/entry.tcl index f28547e..c8422dc 100644 --- a/library/entry.tcl +++ b/library/entry.tcl @@ -69,8 +69,8 @@ bind Entry <> { } bind Entry <> { - %W selection range 0 end - %W icursor end + %W selection range 0 end + %W icursor end } # Standard Motif bindings: diff --git a/library/fontchooser.tcl b/library/fontchooser.tcl index 8b3f87e..8f91ade 100644 --- a/library/fontchooser.tcl +++ b/library/fontchooser.tcl @@ -105,7 +105,7 @@ proc ::tk::fontchooser::Configure {args} { "bad option \"$option\": must be\ -command, -font, -parent, -title or -visible" } - + set cache [dict create -parent $S(-parent) -title $S(-title) \ -font $S(-font) -command $S(-command)] set r [tclParseConfigSpec [namespace which -variable S] $specs "" $args] diff --git a/library/mkpsenc.tcl b/library/mkpsenc.tcl index 50224eb..b3fd13d 100644 --- a/library/mkpsenc.tcl +++ b/library/mkpsenc.tcl @@ -1163,11 +1163,11 @@ namespace eval ::tk { 0 exch 0 exch { dup type /stringtype eq - { stringwidth } { + { stringwidth } { currentfont /Encoding get exch 1 exch put (\001) - stringwidth + stringwidth } - ifelse + ifelse exch 3 1 roll add 3 1 roll add exch } forall } diff --git a/library/msgbox.tcl b/library/msgbox.tcl index 10e91f1..939928d 100644 --- a/library/msgbox.tcl +++ b/library/msgbox.tcl @@ -137,7 +137,7 @@ proc ::tk::MessageBox {args} { # # The default value of the title is space (" ") not the empty string - # because for some window managers, a + # because for some window managers, a # wm title .foo "" # causes the window title to be "foo" instead of the empty string. # @@ -175,7 +175,7 @@ proc ::tk::MessageBox {args} { } switch -- $data(-type) { - abortretryignore { + abortretryignore { set names [list abort retry ignore] set labels [list &Abort &Retry &Ignore] set cancel abort @@ -218,7 +218,7 @@ proc ::tk::MessageBox {args} { lappend buttons [list $name -text [mc $lab]] } - # If no default button was specified, the default default is the + # If no default button was specified, the default default is the # first button (Bug: 2218). if {$data(-default) eq ""} { diff --git a/library/palette.tcl b/library/palette.tcl index 924dd61..9cecf5b 100644 --- a/library/palette.tcl +++ b/library/palette.tcl @@ -100,7 +100,7 @@ proc ::tk_setPalette {args} { set new(troughColor) $darkerBg } - # let's make one of each of the widgets so we know what the + # let's make one of each of the widgets so we know what the # defaults are currently for this platform. toplevel .___tk_set_palette wm withdraw .___tk_set_palette @@ -113,12 +113,12 @@ proc ::tk_setPalette {args} { } # Walk the widget hierarchy, recoloring all existing windows. - # The option database must be set according to what we do here, - # but it breaks things if we set things in the database while + # The option database must be set according to what we do here, + # but it breaks things if we set things in the database while # we are changing colors...so, ::tk::RecolorTree now returns the # option database changes that need to be made, and they # need to be evalled here to take effect. - # We have to walk the whole widget tree instead of just + # We have to walk the whole widget tree instead of just # relying on the widgets we've created above to do the work # because different extensions may provide other kinds # of widgets that we don't currently know about, so we'll @@ -144,7 +144,7 @@ proc ::tk_setPalette {args} { # ::tk::RecolorTree -- # This procedure changes the colors in a window and all of its # descendants, according to information provided by the colors -# argument. This looks at the defaults provided by the option +# argument. This looks at the defaults provided by the option # database, if it exists, and if not, then it looks at the default # value of the widget itself. # diff --git a/library/scrlbar.tcl b/library/scrlbar.tcl index 688d40a..e17442f 100644 --- a/library/scrlbar.tcl +++ b/library/scrlbar.tcl @@ -14,7 +14,7 @@ # The code below creates the default class bindings for scrollbars. #------------------------------------------------------------------------- -# Standard Motif bindings: +# Standard Motif bindings: if {[tk windowingsystem] eq "x11" || [tk windowingsystem] eq "aqua"} { bind Scrollbar { diff --git a/library/spinbox.tcl b/library/spinbox.tcl index 641584d..4d94420 100644 --- a/library/spinbox.tcl +++ b/library/spinbox.tcl @@ -74,8 +74,8 @@ bind Spinbox <> { } bind Spinbox <> { - %W selection range 0 end - %W icursor end + %W selection range 0 end + %W icursor end } # Standard Motif bindings: diff --git a/library/tearoff.tcl b/library/tearoff.tcl index 6da2a0f..b500023 100644 --- a/library/tearoff.tcl +++ b/library/tearoff.tcl @@ -150,7 +150,7 @@ proc ::tk::MenuDup {src dst type} { set tags [bindtags $src] set srcLen [string length $src] - + # Copy tags to x, replacing each substring of src with dst. while {[set index [string first $src $tags]] != -1} { diff --git a/library/tk.tcl b/library/tk.tcl index b7d85c4..4a53f99 100644 --- a/library/tk.tcl +++ b/library/tk.tcl @@ -302,7 +302,7 @@ tk::ScreenChanged [winfo screen .] proc ::tk::EventMotifBindings {n1 dummy dummy} { upvar $n1 name - + if {$name} { set op delete } else { @@ -328,7 +328,7 @@ proc ::tk::EventMotifBindings {n1 dummy dummy} { } #---------------------------------------------------------------------- -# Define common dialogs on platforms where they are not implemented +# Define common dialogs on platforms where they are not implemented # using compiled code. #---------------------------------------------------------------------- @@ -543,7 +543,7 @@ proc ::tk::CancelRepeat {} { # ::tk::TabToWindow -- # This procedure moves the focus to the given widget. -# It sends a <> virtual event to the previous focus window, +# It sends a <> virtual event to the previous focus window, # if any, before changing the focus, and a <> event # to the new focus window afterwards. # @@ -571,7 +571,7 @@ proc ::tk::UnderlineAmpersand {text} { return [list [string map {\ufeff {}} $s] $idx] } -# ::tk::SetAmpText -- +# ::tk::SetAmpText -- # Given widget path and text with "magic ampersands", sets -text and # -underline options for the widget # diff --git a/library/unsupported.tcl b/library/unsupported.tcl index 2c68e78..b5f404a 100644 --- a/library/unsupported.tcl +++ b/library/unsupported.tcl @@ -16,7 +16,7 @@ namespace eval ::tk::unsupported { # Map from the old global names of Tk private commands to their # new namespace-encapsulated names. - variable PrivateCommands + variable PrivateCommands array set PrivateCommands { tkButtonAutoInvoke ::tk::ButtonAutoInvoke tkButtonDown ::tk::ButtonDown diff --git a/library/xmfbox.tcl b/library/xmfbox.tcl index 0578361..aa66f7f 100644 --- a/library/xmfbox.tcl +++ b/library/xmfbox.tcl @@ -27,7 +27,7 @@ namespace eval ::tk::dialog::file {} # When -multiple is set to 0, this returns the absolute pathname # of the selected file. (NOTE: This is not the same as a single # element list.) -# +# # When -multiple is set to > 0, this returns a Tcl list of absolute # pathnames. The argument for -multiple is ignored, but for consistency # with Windows it defines the maximum amount of memory to allocate for @@ -505,7 +505,7 @@ proc ::tk::MotifFDialog_InterpFilter {w} { if {[file pathtype $text] eq "relative"} { set relative 1 } elseif {$badTilde} { - set relative 1 + set relative 1 } if {$relative} { @@ -552,7 +552,7 @@ proc ::tk::MotifFDialog_Update {w} { $data(sEnt) delete 0 end $data(sEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \ $data(selectFile)] - + MotifFDialog_LoadFiles $w } @@ -626,7 +626,7 @@ proc ::tk::MotifFDialog_LoadFiles {w} { # w The pathname of the dialog box. # # Results: -# None. +# None. proc ::tk::MotifFDialog_BrowseDList {w} { upvar ::tk::dialog::file::[winfo name $w] data @@ -672,7 +672,7 @@ proc ::tk::MotifFDialog_BrowseDList {w} { # w The pathname of the dialog box. # # Results: -# None. +# None. proc ::tk::MotifFDialog_ActivateDList {w} { upvar ::tk::dialog::file::[winfo name $w] data @@ -720,7 +720,7 @@ proc ::tk::MotifFDialog_ActivateDList {w} { # w The pathname of the dialog box. # # Results: -# None. +# None. proc ::tk::MotifFDialog_BrowseFList {w} { upvar ::tk::dialog::file::[winfo name $w] data @@ -740,9 +740,9 @@ proc ::tk::MotifFDialog_BrowseFList {w} { $data(fEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \ $data(filter)] $data(fEnt) xview end - - # if it's a multiple selection box, just put in the filenames - # otherwise put in the full path as usual + + # if it's a multiple selection box, just put in the filenames + # otherwise put in the full path as usual $data(sEnt) delete 0 end if {$data(-multiple) != 0} { $data(sEnt) insert 0 $data(selectFile) @@ -762,7 +762,7 @@ proc ::tk::MotifFDialog_BrowseFList {w} { # w The pathname of the dialog box. # # Results: -# None. +# None. proc ::tk::MotifFDialog_ActivateFList {w} { upvar ::tk::dialog::file::[winfo name $w] data @@ -788,7 +788,7 @@ proc ::tk::MotifFDialog_ActivateFList {w} { # w The pathname of the dialog box. # # Results: -# None. +# None. proc ::tk::MotifFDialog_ActivateFEnt {w} { upvar ::tk::dialog::file::[winfo name $w] data @@ -803,7 +803,7 @@ proc ::tk::MotifFDialog_ActivateFEnt {w} { # ::tk::MotifFDialog_ActivateSEnt -- # # This procedure is called when the user presses Return inside -# the "selection" entry. It sets the ::tk::Priv(selectFilePath) +# the "selection" entry. It sets the ::tk::Priv(selectFilePath) # variable so that the vwait loop in tk::MotifFDialog will be # terminated. # @@ -811,7 +811,7 @@ proc ::tk::MotifFDialog_ActivateFEnt {w} { # w The pathname of the dialog box. # # Results: -# None. +# None. proc ::tk::MotifFDialog_ActivateSEnt {w} { variable ::tk::Priv @@ -930,7 +930,7 @@ proc ::tk::ListBoxKeyAccel_Unset {w} { # key The key which the user just pressed. # # Results: -# None. +# None. proc ::tk::ListBoxKeyAccel_Key {w key} { variable ::tk::Priv diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 6cb4f56..a88cad0 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -7,8 +7,8 @@ * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * Copyright 2001, Apple Computer, Inc. * Copyright (c) 2006-2007 Daniel A. Steffen - * Copyright 2007 Revar Desmera. - * Copyright 2015 Kevin Walzer/WordTech Communications LLC. + * Copyright 2007 Revar Desmera. + * Copyright 2015 Kevin Walzer/WordTech Communications LLC. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -230,7 +230,7 @@ TkpDisplayButton( } else { /* Draw the native portion of the buttons. */ TkMacOSXDrawButton(macButtonPtr, dpPtr->gc, pixmap); - + /* Draw highlight border, if needed. */ if (butPtr->highlightWidth < 3) { needhighlight = 1; @@ -264,7 +264,7 @@ TkpDisplayButton( * *---------------------------------------------------------------------- */ - + void TkpComputeButtonGeometry( TkButton *butPtr) /* Button whose geometry may have changed. */ @@ -311,7 +311,7 @@ TkpComputeButtonGeometry( width = butPtr->width; width += 0; break; - } + } } if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) { @@ -384,7 +384,7 @@ TkpComputeButtonGeometry( } else { width = txtWidth; height = txtHeight; - + if (butPtr->width > 0) { width = butPtr->width * avgWidth; } @@ -396,7 +396,7 @@ TkpComputeButtonGeometry( width += 2 * butPtr->padX; height += 2 * butPtr->padY; - + /* Need special handling for radiobuttons and checkbuttons: the text is drawn right on top of the button unless we expand the width. This is not perfect; some radiobuttons may render on top anyway. Need to find a better solution to calculate average text width.*/ switch (butPtr->type) { case TYPE_RADIO_BUTTON: @@ -406,7 +406,7 @@ TkpComputeButtonGeometry( width += 50; break; } - + /* * Now figure out the size of the border decorations for the button. */ @@ -490,7 +490,7 @@ static void DrawButtonImageAndText( TkButton* butPtr) { - + MacButton *mbPtr = (MacButton*)butPtr; Tk_Window tkwin = butPtr->tkwin; Pixmap pixmap; @@ -515,7 +515,7 @@ DrawButtonImageAndText( DrawParams* dpPtr = &mbPtr->drawParams; pixmap = (Pixmap)Tk_WindowId(tkwin); - + if (butPtr->image != None) { Tk_SizeOfImage(butPtr->image, &width, &height); haveImage = 1; @@ -531,7 +531,7 @@ DrawButtonImageAndText( /* Offset bitmaps by a bit when the button is pressed. */ pressed = 1; } - + haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { int x; @@ -542,7 +542,7 @@ DrawButtonImageAndText( fullHeight = 0; switch ((enum compound) butPtr->compound) { - case COMPOUND_TOP: + case COMPOUND_TOP: case COMPOUND_BOTTOM: { /* Image is above or below text */ if (butPtr->compound == COMPOUND_TOP) { @@ -559,10 +559,10 @@ DrawButtonImageAndText( } case COMPOUND_LEFT: case COMPOUND_RIGHT: { - /* - * Image is left or right of text + /* + * Image is left or right of text */ - + if (butPtr->compound == COMPOUND_LEFT) { textXOffset = width + butPtr->padX; } else { @@ -576,10 +576,10 @@ DrawButtonImageAndText( break; } case COMPOUND_CENTER: { - /* - * Image and text are superimposed + /* + * Image and text are superimposed */ - + fullWidth = (width > butPtr->textWidth ? width : butPtr->textWidth); fullHeight = (height > butPtr->textHeight ? height : @@ -633,11 +633,11 @@ DrawButtonImageAndText( XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); } - Tk_DrawTextLayout(butPtr->display, pixmap, + Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1); Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc, - butPtr->textLayout, + butPtr->textLayout, x + textXOffset, y + textYOffset, butPtr->underline); } else { @@ -647,7 +647,7 @@ DrawButtonImageAndText( TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX + butPtr->borderWidth, butPtr->padY + butPtr->borderWidth, - width, height, &x, &y); + width, height, &x, &y); if (dpPtr->relief == TK_RELIEF_SUNKEN) { x += dpPtr->offset; y += dpPtr->offset; @@ -661,9 +661,9 @@ DrawButtonImageAndText( } imageXOffset += x; imageYOffset += y; - + if (butPtr->image != NULL) { - + if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, @@ -702,7 +702,7 @@ DrawButtonImageAndText( butPtr->textWidth, butPtr->textHeight, &x, &y); Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, x, y, 0, -1); - } + } break; case TYPE_BUTTON: case TYPE_LABEL: @@ -757,7 +757,7 @@ DrawButtonImageAndText( * Draw the border and traversal highlight last. This way, if the * button's contents overflow they'll be covered up by the border. */ - + if (dpPtr->relief != TK_RELIEF_FLAT) { int inset = butPtr->highlightWidth; Tk_Draw3DRectangle(tkwin, pixmap, dpPtr->border, inset, inset, @@ -765,7 +765,7 @@ DrawButtonImageAndText( butPtr->borderWidth, dpPtr->relief); } } - + } @@ -803,7 +803,7 @@ TkpDestroyButton( * TkMacOSXDrawButton -- * * This function draws the tk button using Mac controls - * In addition, this code may apply custom colors passed + * In addition, this code may apply custom colors passed * in the TkButton. * * Results: @@ -829,13 +829,13 @@ TkMacOSXDrawButton( TkMacOSXDrawingContext dc; DrawParams* dpPtr = &mbPtr->drawParams; int useNewerHITools = 1; - + winPtr = (TkWindow *)butPtr->tkwin; TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin),Tk_Height(butPtr->tkwin)); - + cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset); if (useNewerHITools == 1) { @@ -847,7 +847,7 @@ TkMacOSXDrawButton( if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { return; } - + if (mbPtr->btnkind == kThemePushButton) { /* @@ -874,14 +874,14 @@ TkMacOSXDrawButton( HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); TkMacOSXRestoreDrawingContext(&dc); - + ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, (MacButton *)mbPtr, 32, true); } else { if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { return; } - + TkMacOSXRestoreDrawingContext(&dc); } mbPtr->lastdrawinfo = mbPtr->drawinfo; @@ -1111,7 +1111,7 @@ TkMacOSXComputeButtonParams( } else { drawinfo->value = kThemeButtonOff; } - + if ((mbPtr->flags & FIRST_DRAW) != 0) { mbPtr->flags &= ~FIRST_DRAW; if (Tk_MacOSXIsAppInFront()) { diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index 219efd1..6a881d3 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -1,5 +1,5 @@ /* - * tkMacOSXInit.c -- + * tkMacOSXInit.c -- * * This file contains Mac OS X -specific interpreter initialization * functions. @@ -31,7 +31,7 @@ static char scriptPath[PATH_MAX + 1] = ""; int tkMacOSXGCEnabled = 0; long tkMacOSXMacOSXVersion = 0; -#pragma mark TKApplication(TKInit) +#pragma mark TKApplication(TKInit) #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 #define NSTextInputContextKeyboardSelectionDidChangeNotification @"NSTextInputContextKeyboardSelectionDidChangeNotification" diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index a1c3138..71ad803 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -7,8 +7,8 @@ * Copyright (c) 1996 by Sun Microsystems, Inc. * Copyright 2001, Apple Computer, Inc. * Copyright (c) 2006-2007 Daniel A. Steffen - * Copyright 2007 Revar Desmera. - * Copyright 2015 Kevin Walzer/WordTech Communications LLC. + * Copyright 2007 Revar Desmera. + * Copyright 2015 Kevin Walzer/WordTech Communications LLC. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -138,12 +138,12 @@ TkpDisplayMenuButton( pixmap = (Pixmap) Tk_WindowId(tkwin); TkMacOSXComputeMenuButtonDrawParams(butPtr, dpPtr); - - /* + + /* * set up clipping region. Make sure the we are using the port - * for this button, or we will set the wrong window's clip. + * for this button, or we will set the wrong window's clip. */ - + TkMacOSXSetUpClippingRgn(pixmap); /* Draw the native portion of the buttons. */ @@ -214,7 +214,7 @@ TkpComputeMenuButtonGeometry(butPtr) /* * First figure out the size of the contents of the button. */ - + width = 0; height = 0; txtWidth = 0; @@ -255,36 +255,36 @@ TkpComputeMenuButtonGeometry(butPtr) switch ((enum compound) butPtr->compound) { case COMPOUND_TOP: case COMPOUND_BOTTOM: { - /* - * Image is above or below text + /* + * Image is above or below text */ - + height += txtHeight + butPtr->padY; width = (width > txtWidth ? width : txtWidth); break; } case COMPOUND_LEFT: case COMPOUND_RIGHT: { - /* - * Image is left or right of text + /* + * Image is left or right of text */ - + width += txtWidth + butPtr->padX; height = (height > txtHeight ? height : txtHeight); break; } case COMPOUND_CENTER: { - /* - * Image and text are superimposed + /* + * Image and text are superimposed */ - + width = (width > txtWidth ? width : txtWidth); height = (height > txtHeight ? height : txtHeight); break; } case COMPOUND_NONE: {break;} } - + if (butPtr->width > 0) { width = butPtr->width; } @@ -316,11 +316,11 @@ TkpComputeMenuButtonGeometry(butPtr) /*Add padding for button arrows.*/ width += 22; - + /* * Now figure out the size of the border decorations for the button. */ - + if (butPtr->highlightWidth < 0) { butPtr->highlightWidth = 0; } @@ -351,7 +351,7 @@ TkpComputeMenuButtonGeometry(butPtr) /* Pad to fill difference between content bounds and button bounds. */ paddingx = tmpRect.origin.x - contBounds.origin.x; paddingy = tmpRect.origin.y - contBounds.origin.y; - + if (paddingx > 0) { width += paddingx; } @@ -406,7 +406,7 @@ DrawMenuButtonImageAndText( if (tkwin == NULL || !Tk_IsMapped(tkwin)) { return; } - + DrawParams* dpPtr = &mbPtr->drawParams; pixmap = (Pixmap)Tk_WindowId(tkwin); @@ -426,7 +426,7 @@ DrawMenuButtonImageAndText( /* Offset bitmaps by a bit when the button is pressed. */ pressed = 1; } - + haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { int x = 0; @@ -437,7 +437,7 @@ DrawMenuButtonImageAndText( fullHeight = 0; switch ((enum compound) butPtr->compound) { - case COMPOUND_TOP: + case COMPOUND_TOP: case COMPOUND_BOTTOM: { /* Image is above or below text */ if (butPtr->compound == COMPOUND_TOP) { @@ -454,10 +454,10 @@ DrawMenuButtonImageAndText( } case COMPOUND_LEFT: case COMPOUND_RIGHT: { - /* - * Image is left or right of text + /* + * Image is left or right of text */ - + if (butPtr->compound == COMPOUND_LEFT) { textXOffset = width + butPtr->padX - 2; } else { @@ -471,10 +471,10 @@ DrawMenuButtonImageAndText( break; } case COMPOUND_CENTER: { - /* - * Image and text are superimposed + /* + * Image and text are superimposed */ - + fullWidth = (width > butPtr->textWidth ? width : butPtr->textWidth); fullHeight = (height > butPtr->textHeight ? height : @@ -508,11 +508,11 @@ DrawMenuButtonImageAndText( XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); } - Tk_DrawTextLayout(butPtr->display, pixmap, + Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1); Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc, - butPtr->textLayout, + butPtr->textLayout, x + textXOffset, y + textYOffset, butPtr->underline); } else { @@ -522,10 +522,10 @@ DrawMenuButtonImageAndText( TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX + butPtr->borderWidth, butPtr->padY + butPtr->borderWidth, - width, height, &x, &y); + width, height, &x, &y); imageXOffset += x; imageYOffset += y; - + if (butPtr->image != NULL) { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); @@ -552,7 +552,7 @@ DrawMenuButtonImageAndText( } } - + /* *-------------------------------------------------------------- @@ -560,7 +560,7 @@ DrawMenuButtonImageAndText( * TkMacOSXDrawMenuButton -- * * This function draws the tk menubutton using Mac controls - * In addition, this code may apply custom colors passed + * In addition, this code may apply custom colors passed * in the TkMenubutton. * * Results: @@ -578,7 +578,7 @@ TkMacOSXDrawMenuButton( * the bevel button */ Pixmap pixmap) /* The pixmap we are drawing into - needed * for the bevel button */ - + { TkMenuButton * butPtr = ( TkMenuButton *)mbPtr; TkWindow * winPtr; @@ -588,11 +588,11 @@ TkMacOSXDrawMenuButton( int useNewerHITools = 1; winPtr = (TkWindow *)butPtr->tkwin; - + TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin),Tk_Height(butPtr->tkwin)); - + cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset); @@ -628,7 +628,7 @@ TkMacOSXDrawMenuButton( if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { return; } - + TkMacOSXRestoreDrawingContext(&dc); } @@ -781,7 +781,7 @@ TkMacOSXComputeMenuButtonParams(TkMenuButton * butPtr, ThemeButtonKind* btnkind, } drawinfo->value = kThemeButtonOff; - + if ((mbPtr->flags & FIRST_DRAW) != 0) { mbPtr->flags &= ~FIRST_DRAW; if (Tk_MacOSXIsAppInFront()) { @@ -832,7 +832,7 @@ TkMacOSXComputeMenuButtonParams(TkMenuButton * butPtr, ThemeButtonKind* btnkind, static int TkMacOSXComputeMenuButtonDrawParams(TkMenuButton * butPtr, DrawParams * dpPtr) { - dpPtr->hasImageOrBitmap = ((butPtr->image != NULL) + dpPtr->hasImageOrBitmap = ((butPtr->image != NULL) || (butPtr->bitmap != None)); dpPtr->border = butPtr->normalBorder; if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index afb8e52..fbf268b 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -1,5 +1,5 @@ /* - * tkMacOSXScrollbar.c -- + * tkMacOSXScrollbar.c -- * * This file implements the Macintosh specific portion of the scrollbar * widget. @@ -34,7 +34,7 @@ typedef struct MacScrollbar { TkScrollbar information; /* Generic scrollbar info. */ GC troughGC; /* For drawing trough. */ - GC copyGC; /* Used for copying from pixmap onto screen. */ + GC copyGC; /* Used for copying from pixmap onto screen. */ } MacScrollbar; /* @@ -110,7 +110,7 @@ TkpCreateScrollbar( TkWindow *winPtr = (TkWindow *)tkwin; Tk_CreateEventHandler(tkwin,ExposureMask|StructureNotifyMask|FocusChangeMask|ButtonPressMask|VisibilityChangeMask, ScrollbarEventProc, scrollPtr); - + return (TkScrollbar *) scrollPtr; } @@ -153,7 +153,7 @@ TkpDisplayScrollbar( CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, .ty = viewHeight}; - + scrollPtr->flags &= ~REDRAW_PENDING; if (!scrollPtr->tkwin || !Tk_IsMapped(tkwin) || !view || !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { @@ -187,11 +187,11 @@ TkpDisplayScrollbar( Tk_Width(tkwin) - 2*scrollPtr->inset, Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT); - /*Update values and draw in native rect.*/ + /*Update values and draw in native rect.*/ UpdateControlValues(scrollPtr); HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); TkMacOSXRestoreDrawingContext(&dc); - + scrollPtr->flags &= ~REDRAW_PENDING; } @@ -278,7 +278,7 @@ TkpComputeScrollbarGeometry( Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics[variant].minThumbHeight, scrollPtr->width + 2 * scrollPtr->inset); } Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset); - + } /* @@ -366,7 +366,7 @@ TkpScrollbarPosition( { /*Using code from tkUnixScrlbr.c because Unix scroll bindings are driving the display at the script level. All the Mac scrollbar has to do is re-draw itself.*/ - + int length, width, tmp; register const int inset = scrollPtr->inset; @@ -411,8 +411,8 @@ TkpScrollbarPosition( * UpdateControlValues -- * * This procedure updates the Macintosh scrollbar control to display the - * values defined by the Tk scrollbar. This is the key interface to the Mac-native * scrollbar; the Unix bindings drive scrolling in the Tk window and all the Mac - * scrollbar has to do is redraw itself. + * values defined by the Tk scrollbar. This is the key interface to the Mac-native * scrollbar; the Unix bindings drive scrolling in the Tk window and all the Mac + * scrollbar has to do is redraw itself. * * Results: * None. @@ -427,12 +427,12 @@ static void UpdateControlValues( TkScrollbar *scrollPtr) /* Scrollbar data struct. */ { - + Tk_Window tkwin = scrollPtr->tkwin; MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin); double dViewSize; HIRect contrlRect; - int variant, active; + int variant, active; short width, height; NSView *view = TkMacOSXDrawableView(macWin); @@ -445,22 +445,22 @@ UpdateControlValues( contrlRect = NSRectToCGRect(frame); info.bounds = contrlRect; - + width = contrlRect.size.width; height = contrlRect.size.height; variant = contrlRect.size.width < metrics[0].width ? 1 : 0; - + /* * Ensure we set scrollbar control bounds only once all size adjustments * have been computed. - */ + */ info.bounds = contrlRect; if (!scrollPtr->vertical) { info.attributes |= kThemeTrackHorizontal; } - + /* * Given the Tk parameters for the fractions of the start and end of the * thumb, the following calculation determines the location for the @@ -483,7 +483,7 @@ UpdateControlValues( } else { info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction; } - + if((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0) || height <= metrics[variant].minHeight) { info.enableState = kThemeTrackHideTrack; @@ -510,7 +510,7 @@ ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr) { if (eventPtr->type == ButtonPress) { - UpdateControlValues(scrollPtr); + UpdateControlValues(scrollPtr); return TCL_OK; } } -- cgit v0.12 From fe0cd754c4dd4321b720ede30723f30c0e9aa3d5 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Mon, 2 Feb 2015 14:21:08 +0000 Subject: Remove Mac-specific idle handler in tkTextDisp.c that caused delay in text redraw during scrolling; no longer needed --- generic/tkTextDisp.c | 9 --------- macosx/tkMacOSXWindowEvent.c | 1 - 2 files changed, 10 deletions(-) diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 3c98178..b75a152 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -3997,15 +3997,6 @@ DisplayText( UpdateDisplayInfo(textPtr); dInfoPtr->dLinesInvalidated = 0; -#ifdef MAC_OSX_TK - /* - * Make sure that unmapped subwindows really have been unmapped. - * If the unmap request is pending as an idle request, the window - * can get redrawn on top of the widget. - */ - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} -#endif - /* * See if it's possible to bring some parts of the screen up-to-date by * scrolling (copying from other parts of the screen). We have to be diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 63df797..e1a0f6f 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -849,7 +849,6 @@ ExposeRestrictProc( [super viewWillDraw]; } - - (BOOL) preservesContentDuringLiveResize { return YES; -- cgit v0.12 From 61ec8df7283ae0dd02dcf86b8b6d3b20e2a79fb8 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Wed, 11 Feb 2015 01:56:56 +0000 Subject: Adjust metrics in buttons to remove extraneous padding in Cocoa checkbuttons with images --- macosx/tkMacOSXButton.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index a88cad0..adefd4a 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -305,7 +305,7 @@ TkpComputeButtonGeometry( break; case TYPE_CHECK_BUTTON: width = butPtr->width; - width += 50; + width += 0; break; case TYPE_BUTTON: width = butPtr->width; -- cgit v0.12 From 5e99e8f1798e3e4e6e44876a1a8f3accf103cb40 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 12 Feb 2015 01:37:26 +0000 Subject: Further refinement of checkbutton metrics in Cocoa --- macosx/tkMacOSXButton.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index adefd4a..a88cad0 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -305,7 +305,7 @@ TkpComputeButtonGeometry( break; case TYPE_CHECK_BUTTON: width = butPtr->width; - width += 0; + width += 50; break; case TYPE_BUTTON: width = butPtr->width; -- cgit v0.12 From 0fbb8acc98156cf4e37dd61a8b5b0e5a53166d7d Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 12 Feb 2015 01:56:28 +0000 Subject: Further refinement of button metrics in Cocoa --- macosx/tkMacOSXButton.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index a88cad0..5763e5f 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -309,7 +309,7 @@ TkpComputeButtonGeometry( break; case TYPE_BUTTON: width = butPtr->width; - width += 0; + width += 30; break; } } -- cgit v0.12 From 242f5ce00786bcf2d55fb118e81c349aabc05ef0 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 12 Feb 2015 02:53:19 +0000 Subject: Further refinement of button metrics in Cocoa --- macosx/tkMacOSXButton.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 5763e5f..a88cad0 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -309,7 +309,7 @@ TkpComputeButtonGeometry( break; case TYPE_BUTTON: width = butPtr->width; - width += 30; + width += 0; break; } } -- cgit v0.12 From 739a187e538263927f4d621b2cf4c59c5753f291 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 12 Feb 2015 15:30:59 +0000 Subject: Cleaner implementation of metrics for radiobuttons and checkbuttons under Cocoa; still a bit of extra padding required, but only when absolutely necessary --- macosx/tkMacOSXButton.c | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 51656ee..d676641 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -296,24 +296,6 @@ TkpComputeButtonGeometry( haveImage = 1; } - /*Tk Aqua can't handle metrics for radiobuttons and checkbuttons with images unless they are set first. These are derived from experimentation.*/ - if (haveImage && !haveText) { - switch (butPtr->type) { - case TYPE_RADIO_BUTTON: - width = butPtr->width; - width +=50; - break; - case TYPE_CHECK_BUTTON: - width = butPtr->width; - width += 50; - break; - case TYPE_BUTTON: - width = butPtr->width; - width += 0; - break; - } - } - if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) { Tk_FreeTextLayout(butPtr->textLayout); butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, @@ -397,13 +379,34 @@ TkpComputeButtonGeometry( height += 2 * butPtr->padY; - /* Need special handling for radiobuttons and checkbuttons: the text is drawn right on top of the button unless we expand the width. This is not perfect; some radiobuttons may render on top anyway. Need to find a better solution to calculate average text width.*/ + /* Need special handling for radiobuttons and checkbuttons: + the text and images is drawn right on top of the button unless + we expand the width. This is not perfect; some radiobuttons may render + on top anyway. + */ switch (butPtr->type) { case TYPE_RADIO_BUTTON: - width += 50; + /*Pad radiobutton by 50 to ensure image does not draw right over + radiobutton on left.*/ + if (butPtr->image != None) { + width += 50; + } else if (butPtr->bitmap != None) { + width +=50; + } else { + /*If just text, just add width of string.*/ + width += txtWidth; + } break; case TYPE_CHECK_BUTTON: - width += 50; + /*No padding required here.*/ + if (butPtr->image != None) { + width += 0; + } else if (butPtr->bitmap != None) { + width +=0; + } else { + /*If just text, just add width of string.*/ + width += txtWidth; + } break; } @@ -417,6 +420,7 @@ TkpComputeButtonGeometry( butPtr->inset = 0; butPtr->inset += butPtr->highlightWidth; + if (TkMacOSXComputeButtonDrawParams(butPtr,&drawParams)) { @@ -471,6 +475,7 @@ TkpComputeButtonGeometry( } /* +/* *---------------------------------------------------------------------- * * DrawButtonImageAndText -- -- cgit v0.12 From e6c243fdce70320e6a12d97dea20f3a6b9ae056c Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 12 Feb 2015 16:01:13 +0000 Subject: Limit hard-coded padding in Cocoa buttons to radiobuttons indicatorOn --- macosx/tkMacOSXButton.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index d676641..bf55634 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -386,12 +386,20 @@ TkpComputeButtonGeometry( */ switch (butPtr->type) { case TYPE_RADIO_BUTTON: - /*Pad radiobutton by 50 to ensure image does not draw right over - radiobutton on left.*/ + /*Pad radiobutton by 50 if indicatorOn to ensure image does not draw + right over radiobutton on left.*/ if (butPtr->image != None) { - width += 50; + if (butPtr->indicatorOn) { + width += 50; + } else { + width += 0; + } } else if (butPtr->bitmap != None) { - width +=50; + if (butPtr->indicatorOn) { + width += 50; + } else { + width += 0; + } } else { /*If just text, just add width of string.*/ width += txtWidth; -- cgit v0.12 From ce09f5af77e6e4b657ced3de19725e633bd170de Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 12 Feb 2015 16:15:10 +0000 Subject: Apply same padding fix to Cocoa checkbuttons --- macosx/tkMacOSXButton.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index bf55634..5d01ce9 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -406,11 +406,20 @@ TkpComputeButtonGeometry( } break; case TYPE_CHECK_BUTTON: - /*No padding required here.*/ + /*Pad checkbutton by 50 if indicatorOn to ensure image does not draw + right over radiobutton on left.*/ if (butPtr->image != None) { - width += 0; + if (butPtr->indicatorOn) { + width += 50; + } else { + width += 0; + } } else if (butPtr->bitmap != None) { - width +=0; + if (butPtr->indicatorOn) { + width += 50; + } else { + width += 0; + } } else { /*If just text, just add width of string.*/ width += txtWidth; -- cgit v0.12 From fce4e2afdd1b452d67d62e8bff171a23b5c386d7 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Fri, 13 Feb 2015 01:42:44 +0000 Subject: Final adjustment of checkbutton flags in Cocoa --- macosx/tkMacOSXButton.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 5d01ce9..4112316 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -421,8 +421,8 @@ TkpComputeButtonGeometry( width += 0; } } else { - /*If just text, just add width of string.*/ - width += txtWidth; + /*If just text, hard-code width of 30. Text renders unevenly otherwise.*/ + width += 30; } break; } -- cgit v0.12 From 237afd75300fd2b491666698252f655fd1ececdb Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 14 Feb 2015 01:22:19 +0000 Subject: Remove calls during window resize notification that cause crash on Cocoa --- macosx/tkMacOSXWindowEvent.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index e1a0f6f..cf8d9a6 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -80,10 +80,6 @@ extern NSString *opaqueTag; NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); - /*Disable drawing until window is resized removes flicker and drawing artifacts;necessary after removal of private API.*/ - NSDisableScreenUpdates(); - [ [w contentView] setHidden:YES]; - if (winPtr) { WmInfo *wmPtr = winPtr->wmInfoPtr; NSRect bounds = [w frame]; @@ -111,8 +107,6 @@ extern NSString *opaqueTag; } TkGenWMConfigureEvent((Tk_Window) winPtr, x, y, width, height, flags); } - [[w contentView] setHidden:NO]; - NSEnableScreenUpdates(); } - (void) windowExpanded: (NSNotification *) notification @@ -845,8 +839,7 @@ ExposeRestrictProc( -(void) viewWillDraw { - - [super viewWillDraw]; + [super viewWillDraw]; } - (BOOL) preservesContentDuringLiveResize @@ -856,10 +849,10 @@ ExposeRestrictProc( - (void)viewWillStartLiveResize { - NSDisableScreenUpdates(); - [super viewWillStartLiveResize]; - [self setNeedsDisplay:NO]; - [self setHidden:YES]; + NSDisableScreenUpdates(); + [super viewWillStartLiveResize]; + [self setNeedsDisplay:NO]; + [self setHidden:YES]; } -- cgit v0.12 From 760c682c426b6ad44b6812ce3521c76be97f6afe Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sun, 15 Feb 2015 18:30:17 +0000 Subject: Better alingment of notebook tabs in Cocoa; thanks to Marc Culler for patch --- macosx/ttkMacOSXTheme.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c index 3f507b0..cfa6ef9 100644 --- a/macosx/ttkMacOSXTheme.c +++ b/macosx/ttkMacOSXTheme.c @@ -294,22 +294,12 @@ static Ttk_StateTable TabPositionTable[] = { * TP30000359-TPXREF116> */ - -int TAB_HEIGHT = 0; -int TAB_OVERLAP = 0; - static void TabElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { - TAB_HEIGHT = 10; - TAB_OVERLAP = 10; - /*Different metrics on 10.10/Yosemite.*/ - if (MAC_OS_X_VERSION_MIN_REQUIRED > 100000) { - TAB_OVERLAP = 5; - } - *heightPtr = TAB_HEIGHT + TAB_OVERLAP - 1; - + *heightPtr = kThemeMetricLargeTabHeight; + *paddingPtr = Ttk_MakePadding(0, 0, 0, 2); } static void TabElementDraw( @@ -327,7 +317,6 @@ static void TabElementDraw( .position = Ttk_StateTableLookup(TabPositionTable, state), }; - bounds.size.height += TAB_OVERLAP; BEGIN_DRAWING(d) ChkErr(HIThemeDrawTab, &bounds, &info, dc.context, HIOrientation, NULL); END_DRAWING @@ -365,8 +354,8 @@ static void PaneElementDraw( .adornment = kHIThemeTabPaneAdornmentNormal, }; - bounds.origin.y -= TAB_OVERLAP; - bounds.size.height += TAB_OVERLAP; + bounds.origin.y -= kThemeMetricTabFrameOverlap; + bounds.size.height += kThemeMetricTabFrameOverlap; BEGIN_DRAWING(d) ChkErr(HIThemeDrawTabPane, &bounds, &info, dc.context, HIOrientation); END_DRAWING -- cgit v0.12 From f42135af43cbfe956ace49e21ee8d1896ae2e54b Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sun, 15 Feb 2015 18:54:23 +0000 Subject: Remove Mac-specific display timer from tkTextDisp.c; no longer needed --- generic/tkTextDisp.c | 43 +------------------------------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 9c0dcf9..01ec22d 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -3933,30 +3933,6 @@ TkTextUpdateOneLine( * *---------------------------------------------------------------------- */ -#ifdef MAC_OSX_TK -static void -RedisplayText( - ClientData clientData ) -{ - register TkText *textPtr = (TkText *) clientData; - TextDInfo *dInfoPtr = textPtr->dInfoPtr; - TkRegion damageRegion; - XRectangle rectangle; - - if (dInfoPtr == NULL) { - return; - } - damageRegion = TkCreateRegion(); - rectangle.x = 0; - rectangle.y = 0; - rectangle.width = dInfoPtr->maxX; - rectangle.height = dInfoPtr->maxY; - TkUnionRectWithRegion(&rectangle, damageRegion, damageRegion); - - TextInvalidateRegion(textPtr, damageRegion); - DisplayText(clientData); -} -#endif static void DisplayText( @@ -3971,9 +3947,7 @@ DisplayText( int bottomY = 0; /* Initialization needed only to stop compiler * warnings. */ Tcl_Interp *interp; -#ifdef MAC_OSX_TK - Tcl_TimerToken macRefreshTimer = NULL; -#endif + if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { /* @@ -4167,21 +4141,6 @@ DisplayText( damageRgn)) { TextInvalidateRegion(textPtr, damageRgn); -#ifdef MAC_OSX_TK - - /* - * On OS X large scrolls sometimes leave garbage on the screen. - * This attempts to clean it up by redisplaying the Text window - * after 200 milliseconds. - */ - if ( abs(y-oldY) > 14 ) { - Tcl_DeleteTimerHandler(macRefreshTimer); - macRefreshTimer = Tcl_CreateTimerHandler(200, - RedisplayText, - clientData); - } -#endif - } numCopies++; TkDestroyRegion(damageRgn); -- cgit v0.12 From b307cb001af410e26d360f9f9b9658449e267853 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Mon, 16 Feb 2015 20:19:42 +0000 Subject: Major fix for HITheme button metrics; thanks to Marc Culler for patch. --- macosx/tkMacOSXButton.c | 437 ++++++++++++++++++++--------------------------- macosx/tkMacOSXDefault.h | 36 ++-- macosx/ttkMacOSXTheme.c | 3 +- 3 files changed, 201 insertions(+), 275 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 4112316..cfd338b 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -9,6 +9,7 @@ * Copyright (c) 2006-2007 Daniel A. Steffen * Copyright 2007 Revar Desmera. * Copyright 2015 Kevin Walzer/WordTech Communications LLC. + * Copyright 2015 Marc Culler. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -89,10 +90,10 @@ static void ButtonContentDrawCB (const HIRect *bounds, ThemeButtonKind kind, const HIThemeButtonDrawInfo *info, MacButton *ptr, SInt16 depth, Boolean isColorDev); static void ButtonEventProc(ClientData clientData, XEvent *eventPtr); -static void TkMacOSXComputeButtonParams (TkButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo* drawinfo); +static void TkMacOSXComputeButtonParams (TkButton * butPtr, ThemeButtonKind* btnkind, + HIThemeButtonDrawInfo* drawinfo); static int TkMacOSXComputeButtonDrawParams (TkButton * butPtr, DrawParams * dpPtr); -static void TkMacOSXDrawButton (MacButton *butPtr, - GC gc, Pixmap pixmap); +static void TkMacOSXDrawButton (MacButton *butPtr, GC gc, Pixmap pixmap); static void DrawButtonImageAndText(TkButton* butPtr); static void PulseDefaultButtonProc(ClientData clientData); @@ -269,8 +270,8 @@ void TkpComputeButtonGeometry( TkButton *butPtr) /* Button whose geometry may have changed. */ { - int width, height, avgWidth, haveImage = 0, haveText = 0; - int txtWidth, txtHeight; + int width = 0, height = 0, charWidth = 1, haveImage = 0, haveText = 0; + int txtWidth = 0, txtHeight = 0; MacButton *mbPtr = (MacButton*)butPtr; Tk_FontMetrics fm; DrawParams drawParams; @@ -279,15 +280,30 @@ TkpComputeButtonGeometry( * First figure out the size of the contents of the button. */ - width = 0; - height = 0; - txtWidth = 0; - txtHeight = 0; - avgWidth = 0; - TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); - butPtr->indicatorSpace = 0; + /* + * If the indicator is on, get its size. + */ + + if ( butPtr->indicatorOn ) { + switch (butPtr->type) { + case TYPE_RADIO_BUTTON: + GetThemeMetric(kThemeMetricRadioButtonWidth, &butPtr->indicatorDiameter); + break; + case TYPE_CHECK_BUTTON: + GetThemeMetric(kThemeMetricCheckBoxWidth, &butPtr->indicatorDiameter); + break; + default: + break; + } + /* Allow 2px extra space next to the indicator. */ + butPtr->indicatorSpace = butPtr->indicatorDiameter + 2; + } else { + butPtr->indicatorSpace = 0; + butPtr->indicatorDiameter = 0; + } + if (butPtr->image != NULL) { Tk_SizeOfImage(butPtr->image, &width, &height); haveImage = 1; @@ -304,19 +320,12 @@ TkpComputeButtonGeometry( txtWidth = butPtr->textWidth; txtHeight = butPtr->textHeight; - avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); + charWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); Tk_GetFontMetrics(butPtr->tkfont, &fm); haveText = (txtWidth != 0 && txtHeight != 0); } - /* - * If the button is compound (ie, it shows both an image and text), - * the new geometry is a combination of the image and text geometry. - * We only honor the compound bit if the button has both text and an - * image, because otherwise it is not really a compound button. - */ - - if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { + if (haveImage && haveText) { /* Image and Text */ switch ((enum compound) butPtr->compound) { case COMPOUND_TOP: case COMPOUND_BOTTOM: @@ -344,89 +353,30 @@ TkpComputeButtonGeometry( width = (width > txtWidth ? width : txtWidth); height = (height > txtHeight ? height : txtHeight); break; - case COMPOUND_NONE: + default: break; } - if (butPtr->width > 0) { - width = butPtr->width; - } - if (butPtr->height > 0) { - height = butPtr->height; - } - - } else if (haveImage) { + width += butPtr->indicatorSpace; - if (butPtr->width > 0) { - width = butPtr->width; - } - if (butPtr->height > 0) { - height = butPtr->height; - } + } else if (haveImage) { /* Image only */ + width = butPtr->width > 0 ? butPtr->width : width + butPtr->indicatorSpace; + height = butPtr->height > 0 ? butPtr->height : height; - } else { - width = txtWidth; + } else { /* Text only */ + width = txtWidth + butPtr->indicatorSpace; height = txtHeight; - if (butPtr->width > 0) { - width = butPtr->width * avgWidth; + width = butPtr->width * charWidth; } if (butPtr->height > 0) { height = butPtr->height * fm.linespace; } } + /* Add padding */ width += 2 * butPtr->padX; height += 2 * butPtr->padY; - - /* Need special handling for radiobuttons and checkbuttons: - the text and images is drawn right on top of the button unless - we expand the width. This is not perfect; some radiobuttons may render - on top anyway. - */ - switch (butPtr->type) { - case TYPE_RADIO_BUTTON: - /*Pad radiobutton by 50 if indicatorOn to ensure image does not draw - right over radiobutton on left.*/ - if (butPtr->image != None) { - if (butPtr->indicatorOn) { - width += 50; - } else { - width += 0; - } - } else if (butPtr->bitmap != None) { - if (butPtr->indicatorOn) { - width += 50; - } else { - width += 0; - } - } else { - /*If just text, just add width of string.*/ - width += txtWidth; - } - break; - case TYPE_CHECK_BUTTON: - /*Pad checkbutton by 50 if indicatorOn to ensure image does not draw - right over radiobutton on left.*/ - if (butPtr->image != None) { - if (butPtr->indicatorOn) { - width += 50; - } else { - width += 0; - } - } else if (butPtr->bitmap != None) { - if (butPtr->indicatorOn) { - width += 50; - } else { - width += 0; - } - } else { - /*If just text, hard-code width of 30. Text renders unevenly otherwise.*/ - width += 30; - } - break; - } - /* * Now figure out the size of the border decorations for the button. */ @@ -438,45 +388,39 @@ TkpComputeButtonGeometry( butPtr->inset = 0; butPtr->inset += butPtr->highlightWidth; - if (TkMacOSXComputeButtonDrawParams(butPtr,&drawParams)) { - - HIRect tmpRect; - HIRect contBounds; + HIRect contBounds; int paddingx = 0; int paddingy = 0; - tmpRect = CGRectMake(0, 0, width, height); - - - HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds); - + tmpRect = CGRectMake(0, 0, width, height); + HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds); /* If the content region has a minimum height, match it. */ if (height < contBounds.size.height) { - height = contBounds.size.height; + height = contBounds.size.height; } /* If the content region has a minimum width, match it. */ if (width < contBounds.size.width) { - width = contBounds.size.width; + width = contBounds.size.width; } /* Pad to fill difference between content bounds and button bounds. */ - paddingx = tmpRect.origin.x - contBounds.origin.x; - paddingy = tmpRect.origin.y - contBounds.origin.y; + paddingx = contBounds.origin.x; + paddingy = contBounds.origin.y; if (paddingx > 0) { - width += paddingx; + //width += paddingx; } if (paddingy > 0) { - height += paddingy; + //height += paddingy; } if (height < paddingx - 4) { /* can't have buttons much shorter than button side diameter. */ height = paddingx - 4; - } + } } else { height += butPtr->borderWidth*2; @@ -488,7 +432,6 @@ TkpComputeButtonGeometry( Tk_GeometryRequest(butPtr->tkwin, width, height); Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); - } /* @@ -553,8 +496,8 @@ DrawButtonImageAndText( pressed = 1; } - haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); - if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { + haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); + if (haveImage && haveText) { /* Image and Text */ int x; int y; textXOffset = 0; @@ -563,60 +506,64 @@ DrawButtonImageAndText( fullHeight = 0; switch ((enum compound) butPtr->compound) { - case COMPOUND_TOP: - case COMPOUND_BOTTOM: { - /* Image is above or below text */ - if (butPtr->compound == COMPOUND_TOP) { - textYOffset = height + butPtr->padY; - } else { - imageYOffset = butPtr->textHeight + butPtr->padY; - } - fullHeight = height + butPtr->textHeight + butPtr->padY; - fullWidth = (width > butPtr->textWidth ? width : - butPtr->textWidth); - textXOffset = (fullWidth - butPtr->textWidth)/2; - imageXOffset = (fullWidth - width)/2; - break; - } - case COMPOUND_LEFT: - case COMPOUND_RIGHT: { - /* - * Image is left or right of text - */ - - if (butPtr->compound == COMPOUND_LEFT) { - textXOffset = width + butPtr->padX; - } else { - imageXOffset = butPtr->textWidth + butPtr->padX; - } - fullWidth = butPtr->textWidth + butPtr->padX + width; - fullHeight = (height > butPtr->textHeight ? height : + case COMPOUND_TOP: + case COMPOUND_BOTTOM: { + /* Image is above or below text */ + if (butPtr->compound == COMPOUND_TOP) { + textYOffset = height + butPtr->padY; + } else { + imageYOffset = butPtr->textHeight + butPtr->padY; + } + fullHeight = height + butPtr->textHeight + butPtr->padY; + fullWidth = (width > butPtr->textWidth ? width : + butPtr->textWidth); + textXOffset = (fullWidth - butPtr->textWidth)/2; + imageXOffset = (fullWidth - width)/2; + break; + } + case COMPOUND_LEFT: + case COMPOUND_RIGHT: { + /* + * Image is left or right of text + */ + + if (butPtr->compound == COMPOUND_LEFT) { + textXOffset = width + butPtr->padX; + } else { + imageXOffset = butPtr->textWidth + butPtr->padX; + } + fullWidth = butPtr->textWidth + butPtr->padX + width; + fullHeight = (height > butPtr->textHeight ? height : butPtr->textHeight); - textYOffset = (fullHeight - butPtr->textHeight)/2; - imageYOffset = (fullHeight - height)/2; - break; - } - case COMPOUND_CENTER: { - /* - * Image and text are superimposed - */ - - fullWidth = (width > butPtr->textWidth ? width : - butPtr->textWidth); - fullHeight = (height > butPtr->textHeight ? height : + textYOffset = (fullHeight - butPtr->textHeight)/2; + imageYOffset = (fullHeight - height)/2; + break; + } + case COMPOUND_CENTER: { + /* + * Image and text are superimposed + */ + + fullWidth = (width > butPtr->textWidth ? width : + butPtr->textWidth); + fullHeight = (height > butPtr->textHeight ? height : butPtr->textHeight); - textXOffset = (fullWidth - butPtr->textWidth)/2; - imageXOffset = (fullWidth - width)/2; - textYOffset = (fullHeight - butPtr->textHeight)/2; - imageYOffset = (fullHeight - height)/2; - break; - } - case COMPOUND_NONE: {break;} - } + textXOffset = (fullWidth - butPtr->textWidth)/2; + imageXOffset = (fullWidth - width)/2; + textYOffset = (fullHeight - butPtr->textHeight)/2; + imageYOffset = (fullHeight - height)/2; + break; + } + default: + break; + } + TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX + butPtr->borderWidth, butPtr->padY + butPtr->borderWidth, - fullWidth, fullHeight, &x, &y); + fullWidth + butPtr->indicatorSpace, fullHeight, &x, &y); + x += butPtr->indicatorSpace; + if (dpPtr->relief == TK_RELIEF_SUNKEN) { x += dpPtr->offset; y += dpPtr->offset; @@ -633,27 +580,27 @@ DrawButtonImageAndText( textYOffset -= 1; if (butPtr->image != NULL) { - if ((butPtr->selectImage != NULL) && - (butPtr->flags & SELECTED)) { - Tk_RedrawImage(butPtr->selectImage, 0, 0, - width, height, pixmap, imageXOffset, imageYOffset); - } else if ((butPtr->tristateImage != NULL) && - (butPtr->flags & TRISTATED)) { - Tk_RedrawImage(butPtr->tristateImage, 0, 0, - width, height, pixmap, imageXOffset, imageYOffset); - } else { - Tk_RedrawImage(butPtr->image, 0, 0, width, - height, pixmap, imageXOffset, imageYOffset); - } + if ((butPtr->selectImage != NULL) && + (butPtr->flags & SELECTED)) { + Tk_RedrawImage(butPtr->selectImage, 0, 0, + width, height, pixmap, imageXOffset, imageYOffset); + } else if ((butPtr->tristateImage != NULL) && + (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, + width, height, pixmap, imageXOffset, imageYOffset); + } else { + Tk_RedrawImage(butPtr->image, 0, 0, width, + height, pixmap, imageXOffset, imageYOffset); + } } else { - XSetClipOrigin(butPtr->display, dpPtr->gc, - imageXOffset, imageYOffset); - XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc, - 0, 0, (unsigned int) width, (unsigned int) height, - imageXOffset, imageYOffset, 1); - XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); + XSetClipOrigin(butPtr->display, dpPtr->gc, + imageXOffset, imageYOffset); + XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc, + 0, 0, (unsigned int) width, (unsigned int) height, + imageXOffset, imageYOffset, 1); + XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); } - + Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1); @@ -661,82 +608,61 @@ DrawButtonImageAndText( butPtr->textLayout, x + textXOffset, y + textYOffset, butPtr->underline); - } else { - if (haveImage) { - int x = 0; - int y; - TkComputeAnchor(butPtr->anchor, tkwin, - butPtr->padX + butPtr->borderWidth, - butPtr->padY + butPtr->borderWidth, - width, height, &x, &y); - if (dpPtr->relief == TK_RELIEF_SUNKEN) { - x += dpPtr->offset; - y += dpPtr->offset; - } else if (dpPtr->relief == TK_RELIEF_RAISED) { - x -= dpPtr->offset; - y -= dpPtr->offset; - } - if (pressed) { - x += dpPtr->offset; - y += dpPtr->offset; - } - imageXOffset += x; - imageYOffset += y; - - if (butPtr->image != NULL) { - - if ((butPtr->selectImage != NULL) && - (butPtr->flags & SELECTED)) { - Tk_RedrawImage(butPtr->selectImage, 0, 0, width, - height, pixmap, imageXOffset, imageYOffset); - } else if ((butPtr->tristateImage != NULL) && - (butPtr->flags & TRISTATED)) { - Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, - height, pixmap, imageXOffset, imageYOffset); - } else { - Tk_RedrawImage(butPtr->image, 0, 0, width, height, - pixmap, imageXOffset, imageYOffset); - } - } else { - XSetClipOrigin(butPtr->display, dpPtr->gc, x, y); - XCopyPlane(butPtr->display, butPtr->bitmap, - pixmap, dpPtr->gc, - 0, 0, (unsigned int) width, - (unsigned int) height, - imageXOffset, imageYOffset, 1); - XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); - } - } else { - /*Adequate padding / offset for text in various buttons.*/ - int x = 0; - int y; - switch (butPtr->type) { - case TYPE_RADIO_BUTTON: - case TYPE_CHECK_BUTTON: - if (butPtr->indicatorOn) { - TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, - butPtr->textWidth, butPtr->textHeight, &x, &y); - Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, - butPtr->textLayout, x + 20, y, 0, -1); - } else { - TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, - butPtr->textWidth, butPtr->textHeight, &x, &y); - Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, - butPtr->textLayout, x, y, 0, -1); - } - break; - case TYPE_BUTTON: - case TYPE_LABEL: - TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, - butPtr->textWidth, butPtr->textHeight, &x, &y); - Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, - butPtr->textLayout, x, y, 0, -1); - y += butPtr->textHeight/2; - break; + } else if (haveImage) { /* Image only */ + int x = 0; + int y; + TkComputeAnchor(butPtr->anchor, tkwin, + butPtr->padX + butPtr->borderWidth, + butPtr->padY + butPtr->borderWidth, + width + butPtr->indicatorSpace, + height, &x, &y); + x += butPtr->indicatorSpace; + if (dpPtr->relief == TK_RELIEF_SUNKEN) { + x += dpPtr->offset; + y += dpPtr->offset; + } else if (dpPtr->relief == TK_RELIEF_RAISED) { + x -= dpPtr->offset; + y -= dpPtr->offset; + } + if (pressed) { + x += dpPtr->offset; + y += dpPtr->offset; + } + imageXOffset += x; + imageYOffset += y; + + if (butPtr->image != NULL) { + + if ((butPtr->selectImage != NULL) && + (butPtr->flags & SELECTED)) { + Tk_RedrawImage(butPtr->selectImage, 0, 0, width, + height, pixmap, imageXOffset, imageYOffset); + } else if ((butPtr->tristateImage != NULL) && + (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, + height, pixmap, imageXOffset, imageYOffset); + } else { + Tk_RedrawImage(butPtr->image, 0, 0, width, height, + pixmap, imageXOffset, imageYOffset); } + } else { + XSetClipOrigin(butPtr->display, dpPtr->gc, x, y); + XCopyPlane(butPtr->display, butPtr->bitmap, + pixmap, dpPtr->gc, + 0, 0, (unsigned int) width, + (unsigned int) height, + imageXOffset, imageYOffset, 1); + XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); } - } - + } else { /* Text only */ + int x, y; + TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, + butPtr->textWidth + butPtr->indicatorSpace, + butPtr->textHeight, &x, &y); + x += butPtr->indicatorSpace; + Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, + x, y, 0, -1); + } /* * If the button is disabled with a stipple rather than a special @@ -855,7 +781,10 @@ TkMacOSXDrawButton( TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); - cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin),Tk_Height(butPtr->tkwin)); + cntrRect = CGRectMake(winPtr->privatePtr->xOff, + winPtr->privatePtr->yOff, + Tk_Width(butPtr->tkwin), + Tk_Height(butPtr->tkwin)); cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset); @@ -892,10 +821,8 @@ TkMacOSXDrawButton( hiinfo.animation.time.start = hiinfo.animation.time.current; } - HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); - + HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); TkMacOSXRestoreDrawingContext(&dc); - ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, (MacButton *)mbPtr, 32, true); } else { @@ -1232,8 +1159,6 @@ TkMacOSXComputeButtonDrawParams( /* * Override the relief specified for the button if this is a * checkbutton or radiobutton and there's no indicator. - * However, don't do this in the presence of Appearance, since - * then the bevel button will take care of the relief. */ dpPtr->relief = butPtr->relief; diff --git a/macosx/tkMacOSXDefault.h b/macosx/tkMacOSXDefault.h index 8565cdb..e95560f 100644 --- a/macosx/tkMacOSXDefault.h +++ b/macosx/tkMacOSXDefault.h @@ -16,9 +16,9 @@ #ifndef _TKMACDEFAULT #define _TKMACDEFAULT -#ifndef TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS -#define TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS 1 -#endif +//#ifndef TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS +//#define TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS 1 +//#endif /* * The definitions below provide symbolic names for the default colors. @@ -72,12 +72,12 @@ #define DEF_BUTTON_HIGHLIGHT_BG_MONO DEF_BUTTON_BG_MONO #define DEF_BUTTON_HIGHLIGHT "systemButtonFrame" #define DEF_LABEL_HIGHLIGHT_WIDTH "0" -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS -#define DEF_BUTTON_HIGHLIGHT_WIDTH "4" -#define DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM "1" -#else +//#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS +//#define DEF_BUTTON_HIGHLIGHT_WIDTH "4" +//#define DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM "1" +//#else #define DEF_BUTTON_HIGHLIGHT_WIDTH "1" -#endif +//#endif #define DEF_BUTTON_IMAGE ((char *) NULL) #define DEF_BUTTON_INDICATOR "1" #define DEF_BUTTON_JUSTIFY "center" @@ -85,19 +85,19 @@ #define DEF_BUTTON_ON_VALUE "1" #define DEF_BUTTON_TRISTATE_VALUE "" #define DEF_BUTTON_OVER_RELIEF "" -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS -#define DEF_BUTTON_PADX "12" -#define DEF_BUTTON_PADX_NOCM "1" -#else +//#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS +//#define DEF_BUTTON_PADX "12" +//#define DEF_BUTTON_PADX_NOCM "1" +//#else #define DEF_BUTTON_PADX "1" -#endif +//#endif #define DEF_LABCHKRAD_PADX "1" -#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS -#define DEF_BUTTON_PADY "3" -#define DEF_BUTTON_PADY_NOCM "1" -#else +//#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS +//#define DEF_BUTTON_PADY "3" +//#define DEF_BUTTON_PADY_NOCM "1" +//#else #define DEF_BUTTON_PADY "1" -#endif +//#endif #define DEF_LABCHKRAD_PADY "1" #define DEF_BUTTON_RELIEF "flat" #define DEF_LABCHKRAD_RELIEF "flat" diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c index cfa6ef9..4753a40 100644 --- a/macosx/ttkMacOSXTheme.c +++ b/macosx/ttkMacOSXTheme.c @@ -298,8 +298,9 @@ static void TabElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { - *heightPtr = kThemeMetricLargeTabHeight; + *heightPtr = GetThemeMetric(kThemeMetricLargeTabHeight, heightPtr); *paddingPtr = Ttk_MakePadding(0, 0, 0, 2); + } static void TabElementDraw( -- cgit v0.12 From 442c33b72b0c586709b2961fbbb27bfcc6ee4406 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Mon, 16 Feb 2015 22:06:24 +0000 Subject: Cleanup of bounds in button code. --- macosx/tkMacOSXButton.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index cfd338b..1a54514 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -410,12 +410,6 @@ TkpComputeButtonGeometry( /* Pad to fill difference between content bounds and button bounds. */ paddingx = contBounds.origin.x; paddingy = contBounds.origin.y; - if (paddingx > 0) { - //width += paddingx; - } - if (paddingy > 0) { - //height += paddingy; - } if (height < paddingx - 4) { /* can't have buttons much shorter than button side diameter. */ -- cgit v0.12 From 63a54a006cb15d7d4d9a7c1f6feb701e14adb9a7 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Wed, 18 Feb 2015 03:31:05 +0000 Subject: Fine-tune display during resize events; now shows resize in progress but does not redraw contentview until done --- macosx/tkMacOSXWindowEvent.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index cf8d9a6..5556464 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -844,12 +844,11 @@ ExposeRestrictProc( - (BOOL) preservesContentDuringLiveResize { - return YES; + return NO; } - (void)viewWillStartLiveResize { - NSDisableScreenUpdates(); [super viewWillStartLiveResize]; [self setNeedsDisplay:NO]; [self setHidden:YES]; @@ -859,7 +858,6 @@ ExposeRestrictProc( - (void)viewDidEndLiveResize { - NSEnableScreenUpdates(); [self setHidden:NO]; [self setNeedsDisplay:YES]; [super setNeedsDisplay:YES]; -- cgit v0.12 From 677891bbd4da362beec2afb9f93af915600182dd Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 19 Feb 2015 02:27:03 +0000 Subject: Restore live resize to Cocoa with reduced flickering; addresses most serious issue of Cocoa drawing while preserving user expectations for display during window resize; thanks to Marc Culler for extensive patch --- macosx/tkMacOSXDraw.c | 18 +++------- macosx/tkMacOSXWindowEvent.c | 81 +++++++++++++++++++------------------------- 2 files changed, 40 insertions(+), 59 deletions(-) diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 2f65517..fa99b14 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -1510,14 +1510,6 @@ TkScrollWindow( /* Scroll the rectangle. */ [view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)]; - - /* Redisplay the scrolled area; hide to reduce flicker after removal of private API calls. */ - [view setHidden:YES]; - [view displayRect:scrollDst]; - [view setHidden:NO]; - - - } } @@ -1862,9 +1854,9 @@ TkpClipDrawableToRect( macDraw->drawRgn = NULL; } if (width >= 0 && height >= 0) { - CGRect drawRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff, + CGRect clipRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff, width, height); - HIShapeRef drawRgn = HIShapeCreateWithRect(&drawRect); + HIShapeRef drawRgn = HIShapeCreateWithRect(&clipRect); if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) { TkMacOSXUpdateClipRgn(macDraw->winPtr); @@ -1877,9 +1869,9 @@ TkpClipDrawableToRect( macDraw->drawRgn = drawRgn; } if (view && view != [NSView focusView] && [view lockFocusIfCanDraw]) { - drawRect.origin.y = [view bounds].size.height - - (drawRect.origin.y + drawRect.size.height); - NSRectClip(NSRectFromCGRect(drawRect)); + clipRect.origin.y = [view bounds].size.height - + (clipRect.origin.y + clipRect.size.height); + NSRectClip(NSRectFromCGRect(clipRect)); macDraw->flags |= TK_FOCUSED_VIEW; } } else { diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 5556464..5d89105 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -6,6 +6,8 @@ * * Copyright 2001-2009, Apple Inc. * Copyright (c) 2005-2009 Daniel A. Steffen + * Copyright (c) 2015 Kevin Walzer/WordTech Communications LLC. + * Copyright (c) 2015 Marc Culler. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -760,19 +762,29 @@ Tk_MacOSXIsAppInFront(void) #import /* - * Custom content view for Tk NSWindows, containing standard NSView subviews. - * The goal is to emulate X11-style drawing in response to Expose events: - * during the normal AppKit drawing cycle, we supress drawing of all subviews - * and instead send Expose events about the subviews that would be redrawn. + * Custom content view for use in Tk NSWindows. + * + * Since Tk handles all drawing of widgets, we only use the AppKit event loop + * as a source of input events. To do this, we overload the NSView drawRect + * method with a method which generates Expose events for Tk but does no + * drawing. The redrawing operations are then done when Tk processes these + * events. + * + * Earlier versions of Mac Tk used subclasses of NSView, e.g. NSButton, as the + * basis for Tk widgets. These would then appear as subviews of the + * TKContentView. To prevent the AppKit from redrawing and corrupting the Tk + * Widgets it was necessary to use Apple private API calls. In order to avoid + * using private API calls, the NSView-based widgets have been replaced with + * normal Tk widgets which draw themselves as native widgets by using the + * HITheme API. + * */ @interface TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect; - (void) generateExposeEvents: (HIMutableShapeRef) shape; -- (BOOL) preservesContentDuringLiveResize; -- (void) viewWillStartLiveResize; - (void) viewDidEndLiveResize; -- (void) viewWillDraw; +- (void) tkToolbarButton: (id) sender; - (BOOL) isOpaque; - (BOOL) wantsDefaultClipping; - (BOOL) acceptsFirstResponder; @@ -793,12 +805,10 @@ ExposeRestrictProc( ? TK_PROCESS_EVENT : TK_DEFER_EVENT); } - @implementation TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect { - const NSRect *rectsBeingDrawn; NSInteger rectsBeingDrawnCount; @@ -811,7 +821,6 @@ ExposeRestrictProc( NSCompositeSourceOver); #endif - CGFloat height = [self bounds].size.height; HIMutableShapeRef drawShape = HIShapeCreateMutable(); @@ -831,37 +840,18 @@ ExposeRestrictProc( } CFRelease(drawShape); - -} - - -/*Provide more fine-grained control over resizing of content to reduce flicker after removal of private API's.*/ - --(void) viewWillDraw -{ - [super viewWillDraw]; -} - -- (BOOL) preservesContentDuringLiveResize -{ - return NO; -} - -- (void)viewWillStartLiveResize -{ - [super viewWillStartLiveResize]; - [self setNeedsDisplay:NO]; - [self setHidden:YES]; } +/* + * As insurance against bugs that might cause layout glitches during a live + * resize, we redraw the window at the end of the resize operation. + */ - (void)viewDidEndLiveResize { - - [self setHidden:NO]; - [self setNeedsDisplay:YES]; - [super setNeedsDisplay:YES]; - [super viewDidEndLiveResize]; + NSRect bounds = NSRectFromCGRect([self bounds]); + HIShapeRef shape = HIShapeCreateWithRect(&bounds); + [self generateExposeEvents: shape]; } @@ -884,15 +874,16 @@ ExposeRestrictProc( ![[NSRunLoop currentRunLoop] currentMode] && Tcl_GetServiceMode() != TCL_SERVICE_NONE) { /* - * Ensure there are no pending idle-time redraws that could prevent the - * just posted Expose events from generating new redraws. + * Ensure there are no pending idle-time redraws that could + * prevent the just posted Expose events from generating + * new redraws. */ while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} /* - * For smoother drawing, process Expose events and resulting redraws - * immediately instead of at idle time. + * For smoother drawing, process Expose events and resulting + * redraws immediately instead of at idle time. */ ClientData oldArg; @@ -909,7 +900,10 @@ ExposeRestrictProc( } -/*This is no-op on 10.7 and up because Apple has removed this widget, but leaving here for backwards compatibility.*/ +/* + * This is no-op on 10.7 and up because Apple has removed this widget, + * but we are leaving it here for backwards compatibility. + */ - (void) tkToolbarButton: (id) sender { #ifdef TK_MAC_DEBUG_EVENTS @@ -937,11 +931,6 @@ ExposeRestrictProc( Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL); } -- (void) setFrameSize: (NSSize) newSize -{ - [super setFrameSize:newSize]; -} - - (BOOL) isOpaque { NSWindow *w = [self window]; -- cgit v0.12 From 6af93817c23f883b7eae04ae854ef9076911800d Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 19 Feb 2015 15:57:42 +0000 Subject: Fix for Cocoa scrollbar appearance on 10.6 --- macosx/tkMacOSXScrlbr.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index 1fd931a..7370ff5 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -186,7 +186,15 @@ TkpDisplayScrollbar( /*Update values and draw in native rect.*/ UpdateControlValues(scrollPtr); +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 + if (scrollPtr->vertical) { + HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); + } else { + HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationInverted); + } +#else HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); +#endif TkMacOSXRestoreDrawingContext(&dc); scrollPtr->flags &= ~REDRAW_PENDING; -- cgit v0.12 From 8fd2c76d00d04abda00bcefb2817feb924da7bfe Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 19 Feb 2015 16:02:44 +0000 Subject: Add padding to HITheme menubuttons --- macosx/tkMacOSXMenubutton.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index d1ce553..a85e572 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -539,10 +539,10 @@ DrawMenuButtonImageAndText( XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); } } else { - /*Move x back by six pixels to give the menubutton arrows room.*/ + /*Move x back by eight pixels to give the menubutton arrows room.*/ int x = 0; int y; - textXOffset = 6; + textXOffset = 8; TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, butPtr->textWidth, butPtr->textHeight, &x, &y); Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, -- cgit v0.12 From fdcfa0f0bcbffc5d51687d791e1377ade0577138 Mon Sep 17 00:00:00 2001 From: dgp Date: Sun, 22 Feb 2015 00:39:12 +0000 Subject: [ab6dab8393] OBOE in loop termination made corrupt dash lines in ps output. --- generic/tkCanvUtil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tkCanvUtil.c b/generic/tkCanvUtil.c index 23c73e5..cbbc2b4 100644 --- a/generic/tkCanvUtil.c +++ b/generic/tkCanvUtil.c @@ -1432,7 +1432,7 @@ Tk_CanvasPsOutline( char *p = ptr; converted = Tcl_ObjPrintf("%d", *p++ & 0xff); - for (i = dash->number-1 ; i>=0 ; i--) { + for (i = dash->number-1 ; i>0 ; i--) { Tcl_AppendPrintfToObj(converted, " %d", *p++ & 0xff); } Tcl_AppendObjToObj(psObj, converted); -- cgit v0.12 From d1e97b3f659b03bad25cadb33011ff325b3b43a9 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sun, 22 Feb 2015 18:03:22 +0000 Subject: Fix for CGRect/NSRect confusion --- macosx/tkMacOSXWindowEvent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 5d89105..5f782c5 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -849,7 +849,7 @@ ExposeRestrictProc( - (void)viewDidEndLiveResize { - NSRect bounds = NSRectFromCGRect([self bounds]); + HIRect bounds = NSRectToCGRect([self bounds]); HIShapeRef shape = HIShapeCreateWithRect(&bounds); [self generateExposeEvents: shape]; -- cgit v0.12 From 1e6d643e0b824c406714369b6342fe6a505bb42b Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 26 Feb 2015 17:16:36 +0000 Subject: Bump to 8.6.4. --- README | 2 +- generic/tk.h | 4 ++-- library/tk.tcl | 2 +- unix/configure | 14 +++++++------- unix/configure.in | 2 +- unix/tk.spec | 2 +- win/configure | 2 +- win/configure.in | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README b/README index 04034fb..1470c04 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ README: Tk - This is the Tk 8.6.3 source distribution. + This is the Tk 8.6.4 source distribution. http://sourceforge.net/projects/tcl/files/Tcl/ You can get any source release of Tk from the URL above. diff --git a/generic/tk.h b/generic/tk.h index bd3c4f1..4a655a4 100644 --- a/generic/tk.h +++ b/generic/tk.h @@ -75,10 +75,10 @@ extern "C" { #define TK_MAJOR_VERSION 8 #define TK_MINOR_VERSION 6 #define TK_RELEASE_LEVEL TCL_FINAL_RELEASE -#define TK_RELEASE_SERIAL 3 +#define TK_RELEASE_SERIAL 4 #define TK_VERSION "8.6" -#define TK_PATCH_LEVEL "8.6.3" +#define TK_PATCH_LEVEL "8.6.4" /* * A special definition used to allow this header file to be included from diff --git a/library/tk.tcl b/library/tk.tcl index 4a53f99..da619e6 100644 --- a/library/tk.tcl +++ b/library/tk.tcl @@ -13,7 +13,7 @@ # Insist on running with compatible version of Tcl package require Tcl 8.6 # Verify that we have Tk binary and script components from the same release -package require -exact Tk 8.6.3 +package require -exact Tk 8.6.4 # Create a ::tk namespace namespace eval ::tk { diff --git a/unix/configure b/unix/configure index 7d4a3e4..21a053e 100755 --- a/unix/configure +++ b/unix/configure @@ -1338,7 +1338,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu TK_VERSION=8.6 TK_MAJOR_VERSION=8 TK_MINOR_VERSION=6 -TK_PATCH_LEVEL=".3" +TK_PATCH_LEVEL=".4" VERSION=${TK_VERSION} LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv" @@ -9755,7 +9755,7 @@ ac_x_header_dirs=' /usr/openwin/share/include' if test "$ac_x_includes" = no; then - # Guess where to find include files, by looking for Xlib.h. + # Guess where to find include files, by looking for Intrinsic.h. # First, try using that file with no special directory specified. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ @@ -9763,7 +9763,7 @@ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include +#include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 @@ -9790,7 +9790,7 @@ else sed 's/^/| /' conftest.$ac_ext >&5 for ac_dir in $ac_x_header_dirs; do - if test -r "$ac_dir/X11/Xlib.h"; then + if test -r "$ac_dir/X11/Intrinsic.h"; then ac_x_includes=$ac_dir break fi @@ -9804,18 +9804,18 @@ if test "$ac_x_libraries" = no; then # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS - LIBS="-lX11 $LIBS" + LIBS="-lXt $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include +#include int main () { -XrmInitialize () +XtMalloc (0) ; return 0; } diff --git a/unix/configure.in b/unix/configure.in index ba1f077..26aadfd 100644 --- a/unix/configure.in +++ b/unix/configure.in @@ -25,7 +25,7 @@ m4_ifdef([SC_USE_CONFIG_HEADERS], [ TK_VERSION=8.6 TK_MAJOR_VERSION=8 TK_MINOR_VERSION=6 -TK_PATCH_LEVEL=".3" +TK_PATCH_LEVEL=".4" VERSION=${TK_VERSION} LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv" diff --git a/unix/tk.spec b/unix/tk.spec index 3b40820..af982f7 100644 --- a/unix/tk.spec +++ b/unix/tk.spec @@ -4,7 +4,7 @@ Name: tk Summary: Tk graphical toolkit for the Tcl scripting language. -Version: 8.6.3 +Version: 8.6.4 Release: 2 License: BSD Group: Development/Languages diff --git a/win/configure b/win/configure index 0504f70..8b7ae07 100755 --- a/win/configure +++ b/win/configure @@ -1312,7 +1312,7 @@ SHELL=/bin/sh TK_VERSION=8.6 TK_MAJOR_VERSION=8 TK_MINOR_VERSION=6 -TK_PATCH_LEVEL=".3" +TK_PATCH_LEVEL=".4" VER=$TK_MAJOR_VERSION$TK_MINOR_VERSION #------------------------------------------------------------------------ diff --git a/win/configure.in b/win/configure.in index ce49151..709b97f 100644 --- a/win/configure.in +++ b/win/configure.in @@ -14,7 +14,7 @@ SHELL=/bin/sh TK_VERSION=8.6 TK_MAJOR_VERSION=8 TK_MINOR_VERSION=6 -TK_PATCH_LEVEL=".3" +TK_PATCH_LEVEL=".4" VER=$TK_MAJOR_VERSION$TK_MINOR_VERSION #------------------------------------------------------------------------ -- cgit v0.12 From 72bd27b3f888e8f1d2b24c5b637f421746dce9a8 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 28 Feb 2015 02:59:12 +0000 Subject: Fix for 5824a992df, images not displaying in Cocoa in label with sunken relief --- macosx/tkMacOSXButton.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 790f5de..5c5aa9e 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -610,13 +610,6 @@ DrawButtonImageAndText( width + butPtr->indicatorSpace, height, &x, &y); x += butPtr->indicatorSpace; - if (dpPtr->relief == TK_RELIEF_SUNKEN) { - x += dpPtr->offset; - y += dpPtr->offset; - } else if (dpPtr->relief == TK_RELIEF_RAISED) { - x -= dpPtr->offset; - y -= dpPtr->offset; - } if (pressed) { x += dpPtr->offset; y += dpPtr->offset; -- cgit v0.12 From 127a4774975912ff1895ce5674a6f9debf950f7f Mon Sep 17 00:00:00 2001 From: ashok Date: Mon, 2 Mar 2015 08:56:23 +0000 Subject: Deleted Win95/98-specific documentation as those platforms have long been unsupported. --- doc/bind.n | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/doc/bind.n b/doc/bind.n index de4502e..d189376 100644 --- a/doc/bind.n +++ b/doc/bind.n @@ -205,9 +205,7 @@ always routed to the window that currently has focus. When the event is received you can use the \fB%D\fR substitution to get the \fIdelta\fR field for the event, which is a integer value describing how the mouse wheel has moved. The smallest value for which the -system will report is defined by the OS. On Windows 95 & 98 machines -this value is at least 120 before it is reported. However, higher -resolution devices may be available in the future. The sign of the +system will report is defined by the OS. The sign of the value determines which direction your widget should scroll. Positive values should scroll up and negative values should scroll down. .IP "\fBKeyPress\fR, \fBKeyRelease\fR" 5 @@ -527,9 +525,7 @@ The \fIborder_width\fR field from the event. Valid only for .IP \fB%D\fR 5 This reports the \fIdelta\fR value of a \fBMouseWheel\fR event. The \fIdelta\fR value represents the rotation units the mouse wheel has -been moved. On Windows 95 & 98 systems the smallest value for the -delta is 120. Future systems may support higher resolution values for -the delta. The sign of the value represents the direction the mouse +been moved. The sign of the value represents the direction the mouse wheel was scrolled. .IP \fB%E\fR 5 The \fIsend_event\fR field from the event. Valid for all event types. -- cgit v0.12 From 8f2c82167e603251867c131570d24ba7e4c4e507 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 5 Mar 2015 15:55:30 +0000 Subject: Fix for keyboard modifier events, thanks to Trevor Williams for patch --- macosx/tkMacOSXKeyboard.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/macosx/tkMacOSXKeyboard.c b/macosx/tkMacOSXKeyboard.c index 54f99d3..7ac087d 100644 --- a/macosx/tkMacOSXKeyboard.c +++ b/macosx/tkMacOSXKeyboard.c @@ -734,7 +734,8 @@ TkpGetKeySym( */ if (eventPtr->xany.send_event == -1) { - int modifier = eventPtr->xkey.keycode; + + int modifier = eventPtr->xkey.keycode & NSDeviceIndependentModifierFlagsMask; if (modifier == NSCommandKeyMask) { return XK_Meta_L; -- cgit v0.12 From a64d781bd75343dc8033771af67a56bb3b8a87f7 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 5 Mar 2015 16:05:04 +0000 Subject: update changes --- changes | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/changes b/changes index a6373fd..81be9f1 100644 --- a/changes +++ b/changes @@ -7145,3 +7145,25 @@ Many revisions to better support a Cygwin environment (nijtmans) 2014-11-07 (bug)[3529885] [scale] handling of negative resolution (vogel) --- Released 8.6.3, November 12, 2014 --- http://core.tcl.tk/tk/ for details + +2014-11-14 (bug)[d43a10] shimmer-related crash in [tk_getOpenFile] (nadkarni) + +2014-11-23 (bug)[1c0d6e] Win build trouble with SIGDN (keene) + +2014-12-03 (bug)[4a0451] [tk_getOpenFile] result (nadkarni) + +2014-12-13 fix header files installation on OS X (houben) + +2015-01-02 (bug) Stop bit loss in [winfo id] on 64-bit Cocoa (porter) + +2015-02-06 (bug) several fixes to elided context in [text] (vogel) + +2015-02-06 (new feature)[TIP 433] %M binding substitution (mistachkin) + *** POTENTIAL INCOMPATIBILITY *** + +2015-02-22 (bug)[ab6dab] corrupt dashed lines in postscript (porter) + +Tk Cocoa 2.0: App Store enabled (walzer,culler,desmera,owen,nyberg,reincke) + *** POTENTIAL INCOMPATIBILITY *** + +--- Released 8.6.4, March 12, 2015 --- http://core.tcl.tk/tk/ for details -- cgit v0.12 From 7c79a335a5383d7bfd8f6a42f36f5fbd5380e944 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Fri, 6 Mar 2015 02:44:38 +0000 Subject: Fix for crash in deleted toplevels when not removed from Cocoa window menu; thanks to Marc Culler for patch --- macosx/tkMacOSXWm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 73ab21c..4f7b066 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -784,6 +784,7 @@ TkWmDeadWindow( if (window && !Tk_IsEmbedded(winPtr) ) { [[window parentWindow] removeChildWindow:window]; + [window setExcludedFromWindowsMenu:YES]; [window close]; TkMacOSXUnregisterMacWindow(window); if (winPtr->window) { -- cgit v0.12 From bc88269ae8c842090cd2d539e0122e820217a9c8 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Tue, 10 Mar 2015 14:38:20 +0000 Subject: Fix for crash when image is dealloc'ed prematurely in Cocoa --- macosx/tkMacOSXDraw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index fa99b14..328f905 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -148,7 +148,8 @@ BitmapRepFromDrawableRect( cg_image = CGBitmapContextCreateImage( (CGContextRef) cg_context); sub_cg_image = CGImageCreateWithImageInRect(cg_image, image_rect); if ( sub_cg_image ) { - bitmap_rep = [[NSBitmapImageRep alloc] autorelease]; + /*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/ + bitmap_rep = [NSBitmapImageRep alloc]; [bitmap_rep initWithCGImage:sub_cg_image]; } if ( cg_image ) { @@ -162,7 +163,8 @@ BitmapRepFromDrawableRect( width,height); if ( [view lockFocusIfCanDraw] ) { - bitmap_rep = [[NSBitmapImageRep alloc] autorelease]; + /*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/ + bitmap_rep = [NSBitmapImageRep alloc]; bitmap_rep = [bitmap_rep initWithFocusedViewRect:view_rect]; [view unlockFocus]; } else { -- cgit v0.12 From 6d849d232afb87840ffe3c1f9055e400e0907a63 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sun, 15 Mar 2015 20:22:13 +0000 Subject: Wish now launches in front when called from command line, and focus -force works correctly; thanks to Marc Culler for patch --- macosx/tkMacOSXMenu.c | 10 +++++++--- macosx/tkMacOSXSubwindows.c | 6 ++++-- macosx/tkMacOSXWindowEvent.c | 4 ++-- macosx/tkMacOSXWm.c | 39 +++++++++++++++++++++++++-------------- 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 85e1d6c..ecdf1ab 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -830,11 +830,16 @@ TkpSetWindowMenuBar( * Puts the menu associated with a window into the menubar. Should only * be called when the window is in front. * + * This is a no-op on all other platforms. On OS X it is a no-op when + * passed a NULL menuName or a nonexistent menuName, with an exception + * for the first call in a new interpreter. In that special case, passing a + * NULL menuName installs the default menu. + * * Results: * None. * * Side effects: - * The menubar is changed. + * The menubar may be changed. * *---------------------------------------------------------------------- */ @@ -843,8 +848,7 @@ void TkpSetMainMenubar( Tcl_Interp *interp, /* The interpreter of the application */ Tk_Window tkwin, /* The frame we are setting up */ - const char *menuName) /* The name of the menu to put in front. If - * NULL, use the default menu bar. */ + const char *menuName) /* The name of the menu to put in front. */ { static Tcl_Interp *currentInterp = NULL; TKMenu *menu = nil; diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 1a71746..ee9167b 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -149,8 +149,10 @@ XMapWindow( if (Tk_IsTopLevel(macWin->winPtr)) { if (!Tk_IsEmbedded(macWin->winPtr)) { NSWindow *win = TkMacOSXDrawableWindow(window); - - [win makeKeyAndOrderFront:NSApp]; + [NSApp activateIgnoringOtherApps:YES]; + if ( [win canBecomeKeyWindow] ) { + [win makeKeyAndOrderFront:NSApp]; + } [win windowRef]; TkMacOSXApplyWindowAttributes(macWin->winPtr, win); } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 5f782c5..3e2a437 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -48,7 +48,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification; #endif #endif -extern NSString *opaqueTag; +extern BOOL opaqueTag; @implementation TKApplication(TKWindowEvent) @@ -935,7 +935,7 @@ ExposeRestrictProc( { NSWindow *w = [self window]; - if (opaqueTag != NULL) { + if (opaqueTag) { return YES; } else { diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 4f7b066..d81e8d6 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -53,7 +53,7 @@ /*Objects for use in setting background color and opacity of window.*/ NSColor *colorName = NULL; -NSString *opaqueTag = NULL; +BOOL opaqueTag = FALSE; static const struct { const UInt64 validAttrs, defaultAttrs, forceOnAttrs, forceOffAttrs; @@ -786,13 +786,18 @@ TkWmDeadWindow( [[window parentWindow] removeChildWindow:window]; [window setExcludedFromWindowsMenu:YES]; [window close]; - TkMacOSXUnregisterMacWindow(window); - if (winPtr->window) { - ((MacDrawable *) winPtr->window)->view = nil; - } - TkMacOSXMakeCollectableAndRelease(wmPtr->window); + TkMacOSXUnregisterMacWindow(window); + if (winPtr->window) { + ((MacDrawable *) winPtr->window)->view = nil; + } + TkMacOSXMakeCollectableAndRelease(wmPtr->window); + /* Activate the highest window left on the screen. */ + NSArray *windows = [NSApp orderedWindows]; + NSWindow *front = [windows objectAtIndex:0]; + if ( front && [front canBecomeKeyWindow] ) { + [front makeKeyAndOrderFront:NSApp]; + } } - ckfree(wmPtr); winPtr->wmInfoPtr = NULL; } @@ -5117,7 +5122,7 @@ TkUnsupported1ObjCmd( colorName = [NSColor clearColor]; //use systemTransparent in Tk scripts to match } if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*opacity*")) { - opaqueTag = @"YES"; + opaqueTag = YES; } } @@ -5508,7 +5513,7 @@ TkMacOSXMakeRealWindowExist( [window setBackgroundColor: colorName]; } - if (opaqueTag != NULL) { + if (opaqueTag) { #ifdef TK_GOT_AT_LEAST_SNOW_LEOPARD [window setOpaque: opaqueTag]; #else @@ -5916,15 +5921,21 @@ TkpChangeFocus( * didn't originally belong to topLevelPtr's * application. */ { - /* - * We don't really need to do anything on the Mac. Tk will keep all this - * state for us. - */ - if (winPtr->atts.override_redirect) { return 0; } + if (Tk_IsTopLevel(winPtr) && !Tk_IsEmbedded(winPtr) ){ + NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); + TkWmRestackToplevel(winPtr, Above, NULL); + if (force ) { + [NSApp activateIgnoringOtherApps:YES]; + } + if ( win && [win canBecomeKeyWindow] ) { + [win makeKeyAndOrderFront:NSApp]; + } + } + /* * Remember the current serial number for the X server and issue a dummy * server request. This marks the position at which we changed the focus, -- cgit v0.12 From c76fcabd431431b1acfc9d4113781872fcc9fe9b Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 00:44:51 +0000 Subject: Remove garbage collections calls as GC is no longer supported on OS X; thanks to Marc Culler for patch --- macosx/tkMacOSXCursor.c | 5 +++-- macosx/tkMacOSXFont.c | 5 +++-- macosx/tkMacOSXInit.c | 2 -- macosx/tkMacOSXMenu.c | 24 +++++++++++++++--------- macosx/tkMacOSXNotify.c | 10 +++------- macosx/tkMacOSXPrivate.h | 18 ------------------ macosx/tkMacOSXWm.c | 22 +++++++++++----------- macosx/tkMacOSXXStubs.c | 3 +-- 8 files changed, 36 insertions(+), 53 deletions(-) diff --git a/macosx/tkMacOSXCursor.c b/macosx/tkMacOSXCursor.c index 53c2cd2..b6394b7 100644 --- a/macosx/tkMacOSXCursor.c +++ b/macosx/tkMacOSXCursor.c @@ -344,7 +344,7 @@ FindCursorByName( macCursor = [[NSCursor alloc] initWithImage:image hotSpot:hotSpot]; [image release]; } - macCursorPtr->macCursor = TkMacOSXMakeUncollectable(macCursor); + macCursorPtr->macCursor = macCursor; } /* @@ -454,7 +454,8 @@ TkpFreeCursor( { TkMacOSXCursor *macCursorPtr = (TkMacOSXCursor *) cursorPtr; - TkMacOSXMakeCollectableAndRelease(macCursorPtr->macCursor); + [macCursorPtr->macCursor release]; + macCursorPtr->macCursor = NULL; if (macCursorPtr == gCurrentCursor) { gCurrentCursor = NULL; } diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c index 4c8ac30..45a68f7 100644 --- a/macosx/tkMacOSXFont.c +++ b/macosx/tkMacOSXFont.c @@ -293,7 +293,7 @@ InitFont( [NSNumber numberWithInt:fmPtr->fixed ? 0 : 1], NSLigatureAttributeName, [NSNumber numberWithDouble:kern], NSKernAttributeName, nil]; - fontPtr->nsAttributes = TkMacOSXMakeUncollectableAndRetain(nsAttributes); + fontPtr->nsAttributes = [nsAttributes retain]; #undef nCh } @@ -557,7 +557,8 @@ TkpDeleteFont( { MacFont *fontPtr = (MacFont *) tkFontPtr; - TkMacOSXMakeCollectableAndRelease(fontPtr->nsAttributes); + [fontPtr->nsAttributes release]; + fontPtr->nsAttributes = NULL; CFRelease(fontPtr->nsFont); /* Either a CTFontRef or a CFRetained NSFont */ } diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index 6a881d3..e861089 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -28,7 +28,6 @@ static char tkLibPath[PATH_MAX + 1] = ""; static char scriptPath[PATH_MAX + 1] = ""; -int tkMacOSXGCEnabled = 0; long tkMacOSXMacOSXVersion = 0; #pragma mark TKApplication(TKInit) @@ -258,7 +257,6 @@ TkpInit( if (!pool) { pool = [NSAutoreleasePool new]; } - tkMacOSXGCEnabled = ([NSGarbageCollector defaultCollector] != nil); [[NSUserDefaults standardUserDefaults] registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index ecdf1ab..9f14f47 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -496,8 +496,7 @@ TkpNewMenu( * platform structure for. */ { TKMenu *menu = [[TKMenu alloc] initWithTkMenu:menuPtr]; - menuPtr->platformData = (TkMenuPlatformData) - TkMacOSXMakeUncollectable(menu); + menuPtr->platformData = (TkMenuPlatformData) menu; CheckForSpecialMenu(menuPtr); return TCL_OK; } @@ -522,7 +521,10 @@ void TkpDestroyMenu( TkMenu *menuPtr) /* The common menu structure */ { - TkMacOSXMakeCollectableAndRelease(menuPtr->platformData); + NSMenu* nsmenu = (NSMenu*)(menuPtr->platformData); + + [nsmenu release]; + menuPtr->platformData = NULL; } /* @@ -555,8 +557,7 @@ TkpMenuNewEntry( } else { menuItem = [menu newTkMenuItem:mePtr]; } - mePtr->platformEntryData = (TkMenuPlatformEntryData) - TkMacOSXMakeUncollectable(menuItem); + mePtr->platformEntryData = (TkMenuPlatformEntryData) menuItem; /* * Caller TkMenuEntry() already did this same insertion into the generic @@ -720,16 +721,21 @@ void TkpDestroyMenuEntry( TkMenuEntry *mePtr) { + NSMenuItem *menuItem; + TKMenu *menu; + NSInteger index; + if (mePtr->platformEntryData && mePtr->menuPtr->platformData) { - TKMenu *menu = (TKMenu *) mePtr->menuPtr->platformData; - NSMenuItem *menuItem = (NSMenuItem *) mePtr->platformEntryData; - NSInteger index = [menu indexOfItem:menuItem]; + menu = (TKMenu *) mePtr->menuPtr->platformData; + menuItem = (NSMenuItem *) mePtr->platformEntryData; + index = [menu indexOfItem:menuItem]; if (index > -1) { [menu removeItemAtIndex:index]; } + [menuItem release]; + mePtr->platformEntryData = NULL; } - TkMacOSXMakeCollectableAndRelease(mePtr->platformEntryData); } /* diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 3e0dfde..ab68931 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -234,8 +234,7 @@ TkMacOSXEventsSetupProc( dequeue:YES]; if (currentEvent) { - tsdPtr->currentEvent = - TkMacOSXMakeUncollectableAndRetain(currentEvent); + tsdPtr->currentEvent = [currentEvent retain]; } } if (tsdPtr->currentEvent) { @@ -273,8 +272,8 @@ TkMacOSXEventsCheckProc( TSD_INIT(); if (tsdPtr->currentEvent) { - currentEvent = TkMacOSXMakeCollectableAndAutorelease( - tsdPtr->currentEvent); + currentEvent = tsdPtr->currentEvent; + [currentEvent autorelease]; } do { modalSession = TkMacOSXGetModalSession(); @@ -288,9 +287,6 @@ TkMacOSXEventsCheckProc( } [currentEvent retain]; pool = [NSAutoreleasePool new]; - if (tkMacOSXGCEnabled) { - objc_clear_stack(0); - } if (![NSApp tkProcessEvent:currentEvent]) { [currentEvent release]; currentEvent = nil; diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 3664850..2de3673 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -144,23 +144,6 @@ } /* - * Macros for GC - */ - -#define TkMacOSXMakeUncollectable(x) ({ id o = (id)(x); \ - if (o) { if(tkMacOSXGCEnabled) CFRetain(o); } o; }) -#define TkMacOSXMakeUncollectableAndRetain(x) ({ id o = (id)(x); \ - if (o) { if(tkMacOSXGCEnabled) CFRetain(o); else [o retain]; } o; }) -#define TkMacOSXMakeCollectable(x) ({ id o = (id)(x); \ - if (o) { x = nil; if (tkMacOSXGCEnabled) CFRelease(o); } o; }) -#define TkMacOSXMakeCollectableAndRelease(x) ({ id o = (id)(x); \ - if (o) { x = nil; if (tkMacOSXGCEnabled) CFRelease(o); \ - else [o release]; } o; }) -#define TkMacOSXMakeCollectableAndAutorelease(x) ({ id o = (id)(x); \ - if (o) { x = nil; if (tkMacOSXGCEnabled) CFRelease(o); \ - else [o autorelease]; } o; }) - -/* * Structure encapsulating current drawing environment. */ @@ -178,7 +161,6 @@ typedef struct TkMacOSXDrawingContext { MODULE_SCOPE CGFloat tkMacOSXZeroScreenHeight; MODULE_SCOPE CGFloat tkMacOSXZeroScreenTop; -MODULE_SCOPE int tkMacOSXGCEnabled; MODULE_SCOPE long tkMacOSXMacOSXVersion; /* diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 429d7aa..fc61c7f 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -786,17 +786,18 @@ TkWmDeadWindow( [[window parentWindow] removeChildWindow:window]; [window setExcludedFromWindowsMenu:YES]; [window close]; - TkMacOSXUnregisterMacWindow(window); - if (winPtr->window) { - ((MacDrawable *) winPtr->window)->view = nil; + TkMacOSXUnregisterMacWindow(window); + if (winPtr->window) { + ((MacDrawable *) winPtr->window)->view = nil; } - TkMacOSXMakeCollectableAndRelease(wmPtr->window); - /* Activate the highest window left on the screen. */ - NSArray *windows = [NSApp orderedWindows]; - NSWindow *front = [windows objectAtIndex:0]; - if ( front && [front canBecomeKeyWindow] ) { - [front makeKeyAndOrderFront:NSApp]; - } + [window release]; + wmPtr->window = NULL; + /* Activate the highest window left on the screen. */ + NSArray *windows = [NSApp orderedWindows]; + NSWindow *front = [windows objectAtIndex:0]; + if ( front && [front canBecomeKeyWindow] ) { + [front makeKeyAndOrderFront:NSApp]; + } } ckfree(wmPtr); winPtr->wmInfoPtr = NULL; @@ -5486,7 +5487,6 @@ TkMacOSXMakeRealWindowExist( if (!window) { Tcl_Panic("couldn't allocate new Mac window"); } - TkMacOSXMakeUncollectable(window); TKContentView *contentView = [[TKContentView alloc] initWithFrame:NSZeroRect]; [window setContentView:contentView]; diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c index b16b582..e03260f 100644 --- a/macosx/tkMacOSXXStubs.c +++ b/macosx/tkMacOSXXStubs.c @@ -177,8 +177,7 @@ TkpOpenDisplay( display->proto_minor_version = [[cgVers objectAtIndex:2] integerValue]; } if (!vendor[0]) { - snprintf(vendor, sizeof(vendor), "Apple AppKit %s %g", - ([NSGarbageCollector defaultCollector] ? "GC" : "RR"), + snprintf(vendor, sizeof(vendor), "Apple AppKit %g", NSAppKitVersionNumber); } display->vendor = vendor; -- cgit v0.12 From 4f6c1ad7943f8c595d9d539a6c6c33c96832554b Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 00:57:14 +0000 Subject: Cleanup and improvement of tracking of native windows in Cocoa; thanks to Marc Culler for patch --- macosx/tkMacOSXEvent.c | 33 ++++++++++--------- macosx/tkMacOSXKeyEvent.c | 8 +++-- macosx/tkMacOSXMouseEvent.c | 21 +++++------- macosx/tkMacOSXWm.c | 79 +++++++++++++++++++++------------------------ 4 files changed, 66 insertions(+), 75 deletions(-) diff --git a/macosx/tkMacOSXEvent.c b/macosx/tkMacOSXEvent.c index ea262ff..365dc9b 100644 --- a/macosx/tkMacOSXEvent.c +++ b/macosx/tkMacOSXEvent.c @@ -31,18 +31,19 @@ enum { NSEvent *processedEvent = theEvent; NSEventType type = [theEvent type]; NSInteger subtype; - NSUInteger flags; switch ((NSInteger)type) { case NSAppKitDefined: subtype = [theEvent subtype]; switch (subtype) { + /* Ignored at the moment. */ case NSApplicationActivatedEventType: break; case NSApplicationDeactivatedEventType: break; case NSWindowExposedEventType: + break; case NSScreenChangedEventType: break; case NSWindowMovedEventType: @@ -53,13 +54,12 @@ enum { default: break; } - break; + break; /* AppkitEvent. Return theEvent */ case NSKeyUp: case NSKeyDown: case NSFlagsChanged: - flags = [theEvent modifierFlags]; processedEvent = [self tkProcessKeyEvent:theEvent]; - break; + break; /* Key event. Return the processed event. */ case NSLeftMouseDown: case NSLeftMouseUp: case NSRightMouseDown: @@ -76,7 +76,7 @@ enum { case NSTabletPoint: case NSTabletProximity: processedEvent = [self tkProcessMouseEvent:theEvent]; - break; + break; /* Mouse event. Return the processed event. */ #if 0 case NSSystemDefined: subtype = [theEvent subtype]; @@ -100,7 +100,7 @@ enum { #endif default: - break; + break; /* return theEvent */ } return processedEvent; } @@ -113,14 +113,14 @@ enum { * * TkMacOSXFlushWindows -- * - * This routine flushes all the windows of the application. It is + * This routine flushes all the visible windows of the application. It is * called by XSync(). * * Results: * None. * * Side effects: - * Flushes all Carbon windows + * Flushes all visible Cocoa windows * *---------------------------------------------------------------------- */ @@ -128,22 +128,23 @@ enum { MODULE_SCOPE void TkMacOSXFlushWindows(void) { - NSInteger windowCount; - NSInteger *windowNumbers; + /* This can be called from outside the Appkit event loop, + * so it needs its own AutoreleasePool. + */ + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + NSArray *macWindows = [NSApp orderedWindows]; + NSInteger windowCount = [macWindows count]; - NSCountWindows(&windowCount); if(windowCount) { - windowNumbers = ckalloc(windowCount * sizeof(NSInteger)); - NSWindowList(windowCount, windowNumbers); - for (NSInteger index = 0; index < windowCount; index++) { - NSWindow *w = [NSApp windowWithWindowNumber:windowNumbers[index]]; + for (NSWindow *w in macWindows) { if (TkMacOSXGetXWindow(w)) { [w flushWindow]; } } - ckfree(windowNumbers); } + [pool drain]; } + /* * Local Variables: diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index c9ad9f1..09cdf94 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -78,16 +78,18 @@ static unsigned isFunctionKey(unsigned int code); case NSFlagsChanged: modifiers = [theEvent modifierFlags]; keyCode = [theEvent keyCode]; - w = [self windowWithWindowNumber:[theEvent windowNumber]]; + // w = [self windowWithWindowNumber:[theEvent windowNumber]]; + w = [theEvent window]; #if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1 NSLog(@"-[%@(%p) %s] r=%d mods=%u '%@' '%@' code=%u c=%d %@ %d", [self class], self, _cmd, repeat, modifiers, characters, charactersIgnoringModifiers, keyCode,([charactersIgnoringModifiers length] == 0) ? 0 : [charactersIgnoringModifiers characterAtIndex: 0], w, type); #endif break; default: - return theEvent; + return theEvent; /* Unrecognized key event. */ } + /* Create an Xevent to add to the Tk queue. */ if (!processingCompose) { unsigned int state = 0; @@ -128,7 +130,7 @@ static unsigned isFunctionKey(unsigned int code); tkwin = (Tk_Window) winPtr->dispPtr->focusPtr; if (!tkwin) { TkMacOSXDbgMsg("tkwin == NULL"); - return theEvent; + return theEvent; /* Give up. No window for this event. */ } /* diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 90d2d00..95f0021 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -53,19 +53,17 @@ enum { case NSCursorUpdate: #if 0 trackingArea = [theEvent trackingArea]; -#endif /* fall through */ +#endif case NSLeftMouseDown: case NSLeftMouseUp: case NSRightMouseDown: case NSRightMouseUp: case NSOtherMouseDown: case NSOtherMouseUp: - case NSLeftMouseDragged: case NSRightMouseDragged: case NSOtherMouseDragged: - case NSMouseMoved: #if 0 eventNumber = [theEvent eventNumber]; @@ -73,22 +71,20 @@ enum { clickCount = [theEvent clickCount]; buttonNumber = [theEvent buttonNumber]; } + /* fall through */ #endif - case NSTabletPoint: case NSTabletProximity: - case NSScrollWheel: - win = [self windowWithWindowNumber:[theEvent windowNumber]]; break; - default: + default: /* Unrecognized mouse event. */ return theEvent; - break; } + /* Create an Xevent to add to the Tk queue. */ + win = [theEvent window]; NSPoint global, local = [theEvent locationInWindow]; - if (win) { global = [win convertBaseToScreen:local]; local.y = [win frame].size.height - local.y; @@ -105,7 +101,7 @@ enum { tkwin = TkMacOSXGetCapture(); } if (!tkwin) { - return theEvent; + return theEvent; /* Give up. No window for this event. */ } /* @@ -127,10 +123,10 @@ enum { EventRef eventRef = (EventRef)[theEvent eventRef]; UInt32 buttons; OSStatus err = GetEventParameter(eventRef, kEventParamMouseChord, - typeUInt32, NULL, sizeof(UInt32), NULL, &buttons); + typeUInt32, NULL, sizeof(UInt32), NULL, &buttons); if (err == noErr) { - state |= (buttons & ((1<<5) - 1)) << 8; + state |= (buttons & ((1<<5) - 1)) << 8; } else if (button < 5) { switch (type) { case NSLeftMouseDown: @@ -205,7 +201,6 @@ enum { Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); } } - return theEvent; } @end diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index fc61c7f..ffb3c34 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -463,25 +463,18 @@ FrontWindowAtPoint( int x, int y) { NSPoint p = NSMakePoint(x, tkMacOSXZeroScreenHeight - y); - NSWindow *win = nil; - NSInteger windowCount; - NSInteger *windowNumbers; - - NSCountWindows(&windowCount); - if (windowCount) { - windowNumbers = ckalloc(windowCount * sizeof(NSInteger)); - NSWindowList(windowCount, windowNumbers); - for (NSInteger index = 0; index < windowCount; index++) { - NSWindow *w = [NSApp windowWithWindowNumber:windowNumbers[index]]; + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + NSArray *windows = [NSApp orderedWindows]; + TkWindow *front = NULL; + for (NSWindow *w in windows) { if (w && NSMouseInRect(p, [w frame], NO)) { - win = w; + front = TkMacOSXGetTkWindow(w); break; } } - ckfree(windowNumbers); - } - return (win ? TkMacOSXGetTkWindow(win) : NULL); + [pool drain]; + return front; } /* @@ -677,6 +670,7 @@ TkWmMapWindow( */ XMapWindow(winPtr->display, winPtr->window); + } /* @@ -699,7 +693,7 @@ TkWmMapWindow( void TkWmUnmapWindow( TkWindow *winPtr) /* Top-level window that's about to be - * mapped. */ + * unmapped. */ { XUnmapWindow(winPtr->display, winPtr->window); } @@ -783,21 +777,26 @@ TkWmDeadWindow( NSWindow *window = wmPtr->window; if (window && !Tk_IsEmbedded(winPtr) ) { - [[window parentWindow] removeChildWindow:window]; + NSWindow *parent = [window parentWindow]; + if (parent) { + [parent removeChildWindow:window]; + } [window setExcludedFromWindowsMenu:YES]; [window close]; TkMacOSXUnregisterMacWindow(window); - if (winPtr->window) { - ((MacDrawable *) winPtr->window)->view = nil; + if (winPtr->window) { + ((MacDrawable *) winPtr->window)->view = nil; } - [window release]; + [window release]; wmPtr->window = NULL; - /* Activate the highest window left on the screen. */ - NSArray *windows = [NSApp orderedWindows]; - NSWindow *front = [windows objectAtIndex:0]; - if ( front && [front canBecomeKeyWindow] ) { - [front makeKeyAndOrderFront:NSApp]; - } + /* Activate the highest window left on the screen. */ + NSArray *windows = [NSApp orderedWindows]; + if ( [windows count] > 0 ) { + NSWindow *front = [windows objectAtIndex:0]; + if ( front && [front canBecomeKeyWindow] ) { + [front makeKeyAndOrderFront:NSApp]; + } + } } ckfree(wmPtr); winPtr->wmInfoPtr = NULL; @@ -5927,6 +5926,7 @@ TkpChangeFocus( if (Tk_IsTopLevel(winPtr) && !Tk_IsEmbedded(winPtr) ){ NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); + NSAutoreleasePool *pool = [NSAutoreleasePool new]; TkWmRestackToplevel(winPtr, Above, NULL); if (force ) { [NSApp activateIgnoringOtherApps:YES]; @@ -5934,6 +5934,7 @@ TkpChangeFocus( if ( win && [win canBecomeKeyWindow] ) { [win makeKeyAndOrderFront:NSApp]; } + [pool drain]; } /* @@ -5952,7 +5953,7 @@ TkpChangeFocus( * WmStackorderToplevelWrapperMap -- * * This procedure will create a table that maps the reparent wrapper X id - * for a toplevel to the TkWindow structure that is wraps. Tk keeps track + * for a toplevel to the TkWindow structure that it wraps. Tk keeps track * of a mapping from the window X id to the TkWindow structure but that * does us no good here since we only get the X id of the wrapper window. * Only those toplevel windows that are mapped have a position in the @@ -6015,8 +6016,6 @@ TkWmStackorderToplevel( Tcl_HashTable table; Tcl_HashEntry *hPtr; Tcl_HashSearch search; - NSInteger windowCount; - NSInteger *windowNumbers; /* * Map mac windows to a TkWindow of the wrapped toplevel. @@ -6043,31 +6042,26 @@ TkWmStackorderToplevel( goto done; } - NSCountWindows(&windowCount); + NSArray *macWindows = [NSApp orderedWindows]; + NSInteger windowCount = [macWindows count]; + if (!windowCount) { ckfree(windows); windows = NULL; } else { windowPtr = windows + table.numEntries; *windowPtr-- = NULL; - windowNumbers = ckalloc(windowCount * sizeof(NSInteger)); - NSWindowList(windowCount, windowNumbers); - for (NSInteger index = 0; index < windowCount; index++) { - NSWindow *w = [NSApp windowWithWindowNumber:windowNumbers[index]]; - - if (w) { - hPtr = Tcl_FindHashEntry(&table, (char*) w); - if (hPtr != NULL) { - childWinPtr = Tcl_GetHashValue(hPtr); - *windowPtr-- = childWinPtr; - } + for (NSWindow *w in macWindows) { + hPtr = Tcl_FindHashEntry(&table, (char*) w); + if (hPtr != NULL) { + childWinPtr = Tcl_GetHashValue(hPtr); + *windowPtr-- = childWinPtr; } } if (windowPtr != windows-1) { Tcl_Panic("num matched toplevel windows does not equal num " - "children"); + "children"); } - ckfree(windowNumbers); } done: @@ -6626,7 +6620,6 @@ RemapWindows( MacDrawable *parentWin) { TkWindow *childPtr; - /* * Remove the OS specific window. It will get rebuilt when the window gets * Mapped. -- cgit v0.12 From 6596343ef6a711a8b5a51e17c946f206a90efe16 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 01:22:30 +0000 Subject: Cleanup and simplification of memory management in event loop; now works more smoothly; thanks to Marc Culler for patches --- macosx/tkMacOSXMenu.c | 9 +++- macosx/tkMacOSXNotify.c | 117 ++++++++++++++++++------------------------- macosx/tkMacOSXSubwindows.c | 6 +++ macosx/tkMacOSXWindowEvent.c | 35 ++++++++++--- macosx/tkMacOSXWm.c | 14 +++++- 5 files changed, 104 insertions(+), 77 deletions(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 9f14f47..0cc874c 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -375,6 +375,13 @@ static int ModifierCharWidth(Tk_Font tkfont); @implementation TKApplication(TKMenu) +- (void) safeSetMainMenu: (NSMenu *) menu +{ + NSAutoreleasePool* pool = [NSAutoreleasePool new]; + [self setMainMenu: menu]; + [pool drain]; +} + - (void) menuBeginTracking: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS @@ -466,7 +473,7 @@ static int ModifierCharWidth(Tk_Font tkfont); [servicesMenuItem setSubmenu:_servicesMenu]; } [self setAppleMenu:applicationMenu]; - [self setMainMenu:menu]; + [self safeSetMainMenu:menu]; } @end diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index ab68931..905ada5 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -18,9 +18,9 @@ #include #import +/* This is not used for anything at the moment. */ typedef struct ThreadSpecificData { - int initialized, sendEventNestingLevel; - NSEvent *currentEvent; + int initialized; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; @@ -34,6 +34,7 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags); #pragma mark TKApplication(TKNotify) @interface NSApplication(TKNotify) +/* We need to declare this hidden method. */ - (void) _modalSession: (NSModalSession) session sendEvent: (NSEvent *) event; @end @@ -48,42 +49,30 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags); @end @implementation TKApplication(TKNotify) +/* Redisplay all of our windows, then call super. */ - (NSEvent *) nextEventMatchingMask: (NSUInteger) mask untilDate: (NSDate *) expiration inMode: (NSString *) mode dequeue: (BOOL) deqFlag { NSAutoreleasePool *pool = [NSAutoreleasePool new]; - [NSApp makeWindowsPerform:@selector(tkDisplayIfNeeded) inOrder:NO]; - - int oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); - NSEvent *event = [[super nextEventMatchingMask:mask untilDate:expiration - inMode:mode dequeue:deqFlag] retain]; - - Tcl_SetServiceMode(oldMode); - if (event) { - TSD_INIT(); - if (tsdPtr->sendEventNestingLevel) { - if (![NSApp tkProcessEvent:event]) { - [event release]; - event = nil; - } - } - } [pool drain]; - return [event autorelease]; + NSEvent *event = [super nextEventMatchingMask:mask + untilDate:expiration + inMode:mode + dequeue:deqFlag]; + return event; } +/* + * Call super then check the pasteboard. + */ - (void) sendEvent: (NSEvent *) theEvent { - TSD_INIT(); - int oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); - - tsdPtr->sendEventNestingLevel++; + NSAutoreleasePool *pool = [NSAutoreleasePool new]; [super sendEvent:theEvent]; - tsdPtr->sendEventNestingLevel--; - Tcl_SetServiceMode(oldMode); [NSApp tkCheckPasteboard]; + [pool drain]; } @end @@ -161,7 +150,8 @@ Tk_MacOSXSetupTkNotifier(void) "first [load] of TkAqua has to occur in the main thread!"); } Tcl_CreateEventSource(TkMacOSXEventsSetupProc, - TkMacOSXEventsCheckProc, GetMainEventQueue()); + TkMacOSXEventsCheckProc, + GetMainEventQueue()); TkCreateExitHandler(TkMacOSXNotifyExitHandler, NULL); Tcl_SetServiceMode(TCL_SERVICE_ALL); TclMacOSXNotifierAddRunLoopMode(NSEventTrackingRunLoopMode); @@ -194,7 +184,8 @@ TkMacOSXNotifyExitHandler( TSD_INIT(); Tcl_DeleteEventSource(TkMacOSXEventsSetupProc, - TkMacOSXEventsCheckProc, GetMainEventQueue()); + TkMacOSXEventsCheckProc, + GetMainEventQueue()); tsdPtr->initialized = 0; } @@ -203,16 +194,19 @@ TkMacOSXNotifyExitHandler( * * TkMacOSXEventsSetupProc -- * - * This procedure implements the setup part of the TkAqua Events event - * source. It is invoked by Tcl_DoOneEvent before entering the notifier - * to check for events. + * This procedure implements the setup part of the MacOSX event + * source. It is invoked by Tcl_DoOneEvent before calling + * TkMacOSXEventsProc to process all queued NSEvents. In our + * case, all we need to do is to set the Tcl MaxBlockTime to + * 0 before starting the loop to process all queued NSEvents. * * Results: * None. * * Side effects: - * If TkAqua events are queued, then the maximum block time will be set - * to 0 to ensure that the notifier returns control to Tcl. + * + * If NSEvents are queued, then the maximum block time will be set + * to 0 to ensure that control returns immediately to Tcl. * *---------------------------------------------------------------------- */ @@ -225,19 +219,13 @@ TkMacOSXEventsSetupProc( if (flags & TCL_WINDOW_EVENTS && ![[NSRunLoop currentRunLoop] currentMode]) { static const Tcl_Time zeroBlockTime = { 0, 0 }; - TSD_INIT(); - - if (!tsdPtr->currentEvent) { - NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:GetRunLoopMode(TkMacOSXGetModalSession()) - dequeue:YES]; - if (currentEvent) { - tsdPtr->currentEvent = [currentEvent retain]; - } - } - if (tsdPtr->currentEvent) { + /* Call this with dequeue=NO -- just checking if the queue is empty. */ + NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:GetRunLoopMode(TkMacOSXGetModalSession()) + dequeue:NO]; + if (currentEvent) { Tcl_SetMaxBlockTime(&zeroBlockTime); } } @@ -248,17 +236,18 @@ TkMacOSXEventsSetupProc( * * TkMacOSXEventsCheckProc -- * - * This procedure processes events sitting in the TkAqua event queue. + * This procedure loops through all NSEvents waiting in the + * TKApplication event queue, generating X events from them. * * Results: * None. * * Side effects: - * Moves applicable queued TkAqua events onto the Tcl event queue. + * NSevents are used to generate X events, which are added to the + * Tcl event queue. * *---------------------------------------------------------------------- */ - static void TkMacOSXEventsCheckProc( ClientData clientData, @@ -267,31 +256,23 @@ TkMacOSXEventsCheckProc( if (flags & TCL_WINDOW_EVENTS && ![[NSRunLoop currentRunLoop] currentMode]) { NSEvent *currentEvent = nil; - NSAutoreleasePool *pool = nil; NSModalSession modalSession; - TSD_INIT(); - if (tsdPtr->currentEvent) { - currentEvent = tsdPtr->currentEvent; - [currentEvent autorelease]; - } do { modalSession = TkMacOSXGetModalSession(); + currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:GetRunLoopMode(modalSession) + dequeue:YES]; if (!currentEvent) { - currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:GetRunLoopMode(modalSession) dequeue:YES]; - } - if (!currentEvent) { - break; + break; /* No more events. */ } - [currentEvent retain]; - pool = [NSAutoreleasePool new]; - if (![NSApp tkProcessEvent:currentEvent]) { - [currentEvent release]; - currentEvent = nil; - } - if (currentEvent) { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + /* Generate Xevents. */ + int oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + NSEvent *processedEvent = [NSApp tkProcessEvent:currentEvent]; + Tcl_SetServiceMode(oldServiceMode); + if (processedEvent) { /* Should always be non-NULL. */ #ifdef TK_MAC_DEBUG_EVENTS TKLog(@" event: %@", currentEvent); #endif @@ -300,14 +281,12 @@ TkMacOSXEventsCheckProc( } else { [NSApp sendEvent:currentEvent]; } - [currentEvent release]; - currentEvent = nil; } [pool drain]; - pool = nil; } while (1); } } + /* * Local Variables: diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index ee9167b..869f717 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -131,6 +131,11 @@ XMapWindow( { MacDrawable *macWin = (MacDrawable *) window; XEvent event; + /* + * This function can be called from outside the AppKit event + * loop, so it needs its own AutoreleasePool. + */ + NSAutoreleasePool* pool = [NSAutoreleasePool new]; /* * Under certain situations it's possible for this function to be called @@ -189,6 +194,7 @@ XMapWindow( event.xvisibility.type = VisibilityNotify; event.xvisibility.state = VisibilityUnobscured; NotifyVisibility(macWin->winPtr, &event); + [pool drain]; } /* diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 241da83..2e7c041 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -794,7 +794,6 @@ Tk_MacOSXIsAppInFront(void) @implementation TKContentView @end - /*Restrict event processing to Expose events.*/ static Tk_RestrictAction ExposeRestrictProc( @@ -842,9 +841,37 @@ ExposeRestrictProc( CFRelease(drawShape); } +-(void) setFrameSize: (NSSize)newsize +{ + if ( [self inLiveResize] ) { + NSWindow *window = [self window]; + TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); + Tk_Window tkwin = (Tk_Window) winPtr; + unsigned int width = (unsigned int)newsize.width; + unsigned int height=(unsigned int)newsize.height; + + /* Resize the Tk Window to the requested size.*/ + TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height, + TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY); + + /* Then resize the NSView to the actual window size*/ + newsize.width = (CGFloat)Tk_Width(tkwin); + newsize.height = (CGFloat)Tk_Height(tkwin); + [super setFrameSize: newsize]; + + /* Process all pending events to update the window. */ + while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} + + } else { + [super setFrameSize: newsize]; + } +} + /* * As insurance against bugs that might cause layout glitches during a live - * resize, we redraw the window at the end of the resize operation. + * resize, we redraw the window one more time at the end of the resize + * operation. */ - (void)viewDidEndLiveResize @@ -852,13 +879,11 @@ ExposeRestrictProc( HIRect bounds = NSRectToCGRect([self bounds]); HIShapeRef shape = HIShapeCreateWithRect(&bounds); [self generateExposeEvents: shape]; - } /*Core function of this class, generates expose events for redrawing.*/ - (void) generateExposeEvents: (HIMutableShapeRef) shape { - TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); unsigned long serial; CGRect updateBounds; @@ -867,7 +892,6 @@ ExposeRestrictProc( return; } - HIShapeGetBounds(shape, &updateBounds); serial = LastKnownRequestProcessed(Tk_Display(winPtr)); if (GenerateUpdates(shape, &updateBounds, winPtr) && @@ -895,7 +919,6 @@ ExposeRestrictProc( Tk_RestrictEvents(oldProc, oldArg, &oldArg); while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} - } } diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index ffb3c34..8866118 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -21,6 +21,8 @@ #include "tkMacOSXEvent.h" #include "tkMacOSXDebug.h" +#define DEBUG_ZOMBIES 0 + /* #ifdef TK_MAC_DEBUG #define TK_MAC_DEBUG_WINDOWS @@ -350,6 +352,17 @@ static void RemapWindows(TkWindow *winPtr, kHelpWindowClass || winPtr->wmInfoPtr->attributes & kWindowNoActivatesAttribute)) ? NO : YES; } + +- (id) retain +{ +#if DEBUG_ZOMBIES + const char *title = [[self title] UTF8String]; + if (title != NULL) { + printf("Retaining %s with count %lu\n", title, [self retainCount]); + } +#endif + return [super retain]; +} @end #pragma mark - @@ -781,7 +794,6 @@ TkWmDeadWindow( if (parent) { [parent removeChildWindow:window]; } - [window setExcludedFromWindowsMenu:YES]; [window close]; TkMacOSXUnregisterMacWindow(window); if (winPtr->window) { -- cgit v0.12 From 2dada458ac1b4e93abc46dc642b17c0278dab630 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 01:30:55 +0000 Subject: Improvement of memory management, removal of zombie windows from Tk-Cocoa; thanks to Marc Culler for patch --- macosx/tkMacOSXKeyEvent.c | 17 +++++++++++------ macosx/tkMacOSXMenu.c | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index 09cdf94..7e7e8e4 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -27,7 +27,9 @@ static Tk_Window grabWinPtr = NULL; /* Current grab window, NULL if no grab. */ static Tk_Window keyboardGrabWinPtr = NULL; /* Current keyboard grab window. */ -static NSModalSession modalSession = NULL; +static NSWindow *keyboardGrabNSWindow = nil; + /* NSWindow for the current keyboard grab window. */ +static NSModalSession modalSession = nil; static BOOL processingCompose = NO; static BOOL finishedCompose = NO; @@ -476,7 +478,9 @@ XGrabKeyboard( if (modalSession) { Tcl_Panic("XGrabKeyboard: already grabbed"); } - modalSession = [NSApp beginModalSessionForWindow:[w retain]]; + keyboardGrabNSWindow = w; + [w retain]; + modalSession = [NSApp beginModalSessionForWindow:w]; } } return GrabSuccess; @@ -504,11 +508,12 @@ XUngrabKeyboard( Time time) { if (modalSession) { - NSWindow *w = keyboardGrabWinPtr ? TkMacOSXDrawableWindow( - ((TkWindow *) keyboardGrabWinPtr)->window) : nil; [NSApp endModalSession:modalSession]; - [w release]; - modalSession = NULL; + modalSession = nil; + } + if (keyboardGrabNSWindow) { + [keyboardGrabNSWindow release]; + keyboardGrabNSWindow = nil; } keyboardGrabWinPtr = NULL; } diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 0cc874c..ed22640 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -261,6 +261,7 @@ static int ModifierCharWidth(Tk_Font tkfont); /*Add time for errors to fire if necessary. This is sub-optimal but avoids issues with Tcl/Cocoa event loop integration.*/ Tcl_Sleep(100); + NSAutoreleasePool *pool = [NSAutoreleasePool new]; Tcl_Preserve(interp); Tcl_Preserve(menuPtr); @@ -273,6 +274,7 @@ static int ModifierCharWidth(Tk_Font tkfont); } Tcl_Release(menuPtr); Tcl_Release(interp); + [pool drain]; } } } -- cgit v0.12 From 94df74b09e190a9ec583d0e90eaac44f8afc5fd5 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 01:39:31 +0000 Subject: Add copyright notice for Marc Culler --- macosx/tkMacOSXKeyEvent.c | 1 + macosx/tkMacOSXNotify.c | 1 + 2 files changed, 2 insertions(+) diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index 7e7e8e4..8e278f7 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -7,6 +7,7 @@ * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen * Copyright (c) 2012 Adrian Robert. + * Copyright 2015 Marc Culler. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 905ada5..b5f330f 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -7,6 +7,7 @@ * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2005-2009 Daniel A. Steffen + * Copyright 2015 Marc Culler. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. -- cgit v0.12 From 78fdb8a758d9a6a2fd31d8bb222186e26dc338cc Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 03:21:25 +0000 Subject: Final cleanup of zombie windows in Cocoa --- macosx/tkMacOSXEvent.c | 9 +++------ macosx/tkMacOSXWm.c | 2 ++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/macosx/tkMacOSXEvent.c b/macosx/tkMacOSXEvent.c index 365dc9b..db13249 100644 --- a/macosx/tkMacOSXEvent.c +++ b/macosx/tkMacOSXEvent.c @@ -133,13 +133,10 @@ TkMacOSXFlushWindows(void) */ NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSArray *macWindows = [NSApp orderedWindows]; - NSInteger windowCount = [macWindows count]; - if(windowCount) { - for (NSWindow *w in macWindows) { - if (TkMacOSXGetXWindow(w)) { - [w flushWindow]; - } + for (NSWindow *w in macWindows) { + if (TkMacOSXGetXWindow(w)) { + [w flushWindow]; } } [pool drain]; diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 8866118..417f130 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -790,6 +790,7 @@ TkWmDeadWindow( NSWindow *window = wmPtr->window; if (window && !Tk_IsEmbedded(winPtr) ) { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSWindow *parent = [window parentWindow]; if (parent) { [parent removeChildWindow:window]; @@ -809,6 +810,7 @@ TkWmDeadWindow( [front makeKeyAndOrderFront:NSApp]; } } + [pool drain]; } ckfree(wmPtr); winPtr->wmInfoPtr = NULL; -- cgit v0.12 From 0695305f6b338ad297fb2d027860a860495f8392 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 04:12:05 +0000 Subject: Additional copyright notices --- macosx/Tk-Info.plist.in | 4 ++++ macosx/Wish-Info.plist.in | 12 ++++++++---- macosx/tkMacOSXDialog.c | 3 +++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/macosx/Tk-Info.plist.in b/macosx/Tk-Info.plist.in index 50b9d24..7b0c305 100644 --- a/macosx/Tk-Info.plist.in +++ b/macosx/Tk-Info.plist.in @@ -17,6 +17,10 @@ Tk @TK_WINDOWINGSYSTEM@ @TK_VERSION@@TK_PATCH_LEVEL@, Copyright © 1989-@TK_YEAR@ Tcl Core Team, Copyright © 2002-@TK_YEAR@ Daniel A. Steffen, + Copyright © 1989-@TK_YEAR@ Contributors, + Copyright © 2011-@TK_YEAR@ Kevin Walzer/WordTech + Communications LLC, + Copyright © 2014-@TK_YEAR@ Marc Culler, Copyright © 2001-2009 Apple Inc., Copyright © 2001-2002 Jim Ingham & Ian Reid CFBundleIdentifier diff --git a/macosx/Wish-Info.plist.in b/macosx/Wish-Info.plist.in index 78170f1..db75cf2 100644 --- a/macosx/Wish-Info.plist.in +++ b/macosx/Wish-Info.plist.in @@ -40,10 +40,14 @@ Wish CFBundleGetInfoString Wish Shell @TK_VERSION@@TK_PATCH_LEVEL@, -Copyright © 1989-@TK_YEAR@ Tcl Core Team, -Copyright © 2002-@TK_YEAR@ Daniel A. Steffen, -Copyright © 2001-2009 Apple Inc., -Copyright © 2001-2002 Jim Ingham & Ian Reid + Copyright © 1989-@TK_YEAR@ Tcl Core Team, + Copyright © 1989-@TK_YEAR@ Contributors, + Copyright © 2011-@TK_YEAR@ Kevin Walzer/WordTech + Communications LLC, + Copyright © 2014-@TK_YEAR@ Marc Culler, + Copyright © 2002-@TK_YEAR@ Daniel A. Steffen, + Copyright © 2001-2009 Apple Inc., + Copyright © 2001-2002 Jim Ingham & Ian Reid CFBundleIconFile Wish.icns CFBundleIdentifier diff --git a/macosx/tkMacOSXDialog.c b/macosx/tkMacOSXDialog.c index a66939a..4b19260 100644 --- a/macosx/tkMacOSXDialog.c +++ b/macosx/tkMacOSXDialog.c @@ -857,6 +857,9 @@ TkAboutDlg(void) [[[NSAttributedString alloc] initWithString: [NSString stringWithFormat: @"%1$C 1987-%2$@ Tcl Core Team." "\n\n" + "%1$C 1989-%2$@ Contributors." "\n\n" + "%1$C 2011-%2$@ Kevin Walzer/WordTech Communications LLC." "\n\n" + "%1$C 2014-%2$@ Marc Culler." "\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" -- cgit v0.12 From 9cbdc93d269480ad1aefb7becb392797ce3b76a3 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 22 Mar 2015 15:10:27 +0000 Subject: Suggested fix for [2a70627a03]: shobjidl.h include in tkWinDialog.c breaks mingw cross compile --- win/tkWinDialog.c | 1 - 1 file changed, 1 deletion(-) diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index c137111..dc385e3 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -18,7 +18,6 @@ #include /* includes the common dialog error codes */ #include /* includes SHBrowseForFolder */ -#include #ifdef _MSC_VER # pragma comment (lib, "shell32.lib") -- cgit v0.12 From e376bb72e8ff45dbe2d1754b98b28b4dfa1015c1 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 23 Mar 2015 10:44:09 +0000 Subject: Remove some unnecessary end-of-line spacing --- macosx/tkMacOSXKeyEvent.c | 2 +- macosx/tkMacOSXNotify.c | 8 ++++---- win/makefile.bc | 10 +++++----- win/rc/tk_base.rc | 12 ++++++------ win/rc/wish.rc | 2 +- win/tkConfig.sh.in | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index 8e278f7..df9dd8a 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -7,7 +7,7 @@ * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen * Copyright (c) 2012 Adrian Robert. - * Copyright 2015 Marc Culler. + * Copyright 2015 Marc Culler. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index b5f330f..8b9745d 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -7,7 +7,7 @@ * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2005-2009 Daniel A. Steffen - * Copyright 2015 Marc Culler. + * Copyright 2015 Marc Culler. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -196,7 +196,7 @@ TkMacOSXNotifyExitHandler( * TkMacOSXEventsSetupProc -- * * This procedure implements the setup part of the MacOSX event - * source. It is invoked by Tcl_DoOneEvent before calling + * source. It is invoked by Tcl_DoOneEvent before calling * TkMacOSXEventsProc to process all queued NSEvents. In our * case, all we need to do is to set the Tcl MaxBlockTime to * 0 before starting the loop to process all queued NSEvents. @@ -205,7 +205,7 @@ TkMacOSXNotifyExitHandler( * None. * * Side effects: - * + * * If NSEvents are queued, then the maximum block time will be set * to 0 to ensure that control returns immediately to Tcl. * @@ -221,7 +221,7 @@ TkMacOSXEventsSetupProc( ![[NSRunLoop currentRunLoop] currentMode]) { static const Tcl_Time zeroBlockTime = { 0, 0 }; - /* Call this with dequeue=NO -- just checking if the queue is empty. */ + /* Call this with dequeue=NO -- just checking if the queue is empty. */ NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:GetRunLoopMode(TkMacOSXGetModalSession()) diff --git a/win/makefile.bc b/win/makefile.bc index 934599c..a1b1032 100644 --- a/win/makefile.bc +++ b/win/makefile.bc @@ -3,7 +3,7 @@ # for Visual C++ that came with tk 8.3.3 # # Some "not so obvious" details in this makefile are preceded by a comment -# "maintenance hint", which tries to explain what's going on. Better to +# "maintenance hint", which tries to explain what's going on. Better to # leave those in place. # Helmut Giese, July 2002 # @@ -303,10 +303,10 @@ plugin: setup $(TKPLUGINDLL) $(WISHP) tktest: setup $(TKTEST) $(CAT32) # Maintenance hint: We want to set environment variables before calling tktest. -# If we do this in the form of normal commands, they will not persist up to +# If we do this in the form of normal commands, they will not persist up to # the call of tktest. Therfore we put all commands wanted into a batch file. # The normal way of using 'echo >x.bat' and 'echo >>x.bat' does not work here -# because we cannot write '... > tktest.txt' this way. Hence this advanced +# because we cannot write '... > tktest.txt' this way. Hence this advanced # form of loop hopping: # - Have MAKE produce a temporary file with the content we want. # - Use it as input to the COPY command to produce a batch file. @@ -314,7 +314,7 @@ tktest: setup $(TKTEST) $(CAT32) # test: setup $(TKTEST) $(TKLIB) $(CAT32) copy &&! - set TCL_LIBRARY=$(TCLDIR)/library + set TCL_LIBRARY=$(TCLDIR)/library set PATH=$(TCLDIR)\win\$(TMPDIRNAME);$(PATH) $(TKTEST) $(ROOT)/tests/all.tcl > tktest.txt ! _test.bat @@ -367,7 +367,7 @@ install-libraries: $(TKLIB): $(TKDLL) $(TKSTUBLIB) -# Maintenance hint: The macro puts a '+-' before the first member of +# Maintenance hint: The macro puts a '+-' before the first member of # TKSTUBOBJS, than replaces any ' ' with ' +-' - together putting '+-' in # front of any member of TKSTUBOBJS (provided, they are separated in their # defintion by just one space). diff --git a/win/rc/tk_base.rc b/win/rc/tk_base.rc index 3e065c9..e6ab016 100644 --- a/win/rc/tk_base.rc +++ b/win/rc/tk_base.rc @@ -26,12 +26,12 @@ FONT 8, "Helv" BEGIN LTEXT "Directory &name:",-1,8,6,118,9 EDITTEXT edt10,8,26,144,12, WS_TABSTOP | ES_AUTOHSCROLL - LISTBOX lst2,8,40,144,64,LBS_SORT | LBS_OWNERDRAWFIXED | - LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | + LISTBOX lst2,8,40,144,64,LBS_SORT | LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP LTEXT "Dri&ves:",stc4,8,106,92,9 - COMBOBOX cmb2,8,115,144,68,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | - CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | + COMBOBOX cmb2,8,115,144,68,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | + CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP DEFPUSHBUTTON "OK",1,160,6,50,14,WS_GROUP PUSHBUTTON "Cancel",2,160,24,50,14,WS_GROUP @@ -42,8 +42,8 @@ BEGIN LTEXT "a",stc3,9,143,114,15 EDITTEXT edt1,7,158,135,20,NOT WS_TABSTOP LISTBOX lst1,8,205,134,42,LBS_NOINTEGRALHEIGHT - COMBOBOX cmb1,8,253,135,21,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | - CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | + COMBOBOX cmb1,8,253,135,21,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | + CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL END diff --git a/win/rc/wish.rc b/win/rc/wish.rc index 5cc2fa4..53e02fa 100644 --- a/win/rc/wish.rc +++ b/win/rc/wish.rc @@ -63,7 +63,7 @@ END // // Icon -// +// // The icon whose name or resource ID is lexigraphically first, is used // as the application's icon. // diff --git a/win/tkConfig.sh.in b/win/tkConfig.sh.in index 7816b15..c511312 100644 --- a/win/tkConfig.sh.in +++ b/win/tkConfig.sh.in @@ -1,5 +1,5 @@ # tkConfig.sh -- -# +# # This shell script (for sh) is generated automatically by Tk's # configure script. It will create shell variables for most of # the configuration options discovered by the configure script. -- cgit v0.12 From e450f5762837d46e9c72791b8af7361838364291 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 24 Mar 2015 19:13:10 +0000 Subject: Purge configuration efforts at supporting platforms lacking . --- compat/limits.h | 22 ------- unix/Makefile.in | 2 +- unix/configure | 165 ++--------------------------------------------------- unix/configure.in | 6 -- unix/tcl.m4 | 4 -- unix/tkConfig.h.in | 6 -- unix/tkUnixPort.h | 6 +- 7 files changed, 7 insertions(+), 204 deletions(-) delete mode 100644 compat/limits.h diff --git a/compat/limits.h b/compat/limits.h deleted file mode 100644 index 2cb082b..0000000 --- a/compat/limits.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * limits.h -- - * - * This is a dummy header file to #include in Tcl when there - * is no limits.h in /usr/include. There are only a few - * definitions here; also see tclPort.h, which already - * #defines some of the things here if they're not arleady - * defined. - * - * Copyright (c) 1991 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - */ - -#define LONG_MIN 0x80000000 -#define LONG_MAX 0x7fffffff -#define INT_MIN 0x80000000 -#define INT_MAX 0x7fffffff -#define SHRT_MIN 0x8000 -#define SHRT_MAX 0x7fff diff --git a/unix/Makefile.in b/unix/Makefile.in index f21fdbb..0736055 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -1608,7 +1608,7 @@ dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tkConfig.h.in $(UNIX_DIR)/tk.pc.in $(M $(DISTDIR)/macosx/Tk.xcodeproj mkdir $(DISTDIR)/compat cp -p $(TOP_DIR)/license.terms $(TCLDIR)/compat/unistd.h \ - $(TCLDIR)/compat/stdlib.h $(TCLDIR)/compat/limits.h \ + $(TCLDIR)/compat/stdlib.h \ $(DISTDIR)/compat mkdir $(DISTDIR)/xlib cp -p $(XLIB_DIR)/*.[ch] $(DISTDIR)/xlib diff --git a/unix/configure b/unix/configure index 21a053e..c10a247 100755 --- a/unix/configure +++ b/unix/configure @@ -2692,8 +2692,11 @@ _ACEOF esac -# limits header checks must come early to prevent -# an autoconf bug that throws errors on configure +#-------------------------------------------------------------------- +# Supply a substitute for stdlib.h if it doesn't define strtol, +# strtoul, or strtod (which it doesn't in some versions of SunOS). +#-------------------------------------------------------------------- + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3182,164 +3185,6 @@ fi done -if test "${ac_cv_header_limits_h+set}" = set; then - echo "$as_me:$LINENO: checking for limits.h" >&5 -echo $ECHO_N "checking for limits.h... $ECHO_C" >&6 -if test "${ac_cv_header_limits_h+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -echo "$as_me:$LINENO: result: $ac_cv_header_limits_h" >&5 -echo "${ECHO_T}$ac_cv_header_limits_h" >&6 -else - # Is the header compilable? -echo "$as_me:$LINENO: checking limits.h usability" >&5 -echo $ECHO_N "checking limits.h usability... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_header_compiler=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6 - -# Is the header present? -echo "$as_me:$LINENO: checking limits.h presence" >&5 -echo $ECHO_N "checking limits.h presence... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -_ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_c_preproc_warn_flag - ac_cpp_err=$ac_cpp_err$ac_c_werror_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi -rm -f conftest.err conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6 - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: limits.h: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: limits.h: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: limits.h: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: limits.h: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: limits.h: present but cannot be compiled" >&5 -echo "$as_me: WARNING: limits.h: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: limits.h: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: limits.h: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: limits.h: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: limits.h: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: limits.h: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: limits.h: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: limits.h: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: limits.h: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: limits.h: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: limits.h: in the future, the compiler will take precedence" >&2;} - ( - cat <<\_ASBOX -## ----------------------------- ## -## Report this to the tk lists. ## -## ----------------------------- ## -_ASBOX - ) | - sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -echo "$as_me:$LINENO: checking for limits.h" >&5 -echo $ECHO_N "checking for limits.h... $ECHO_C" >&6 -if test "${ac_cv_header_limits_h+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_cv_header_limits_h=$ac_header_preproc -fi -echo "$as_me:$LINENO: result: $ac_cv_header_limits_h" >&5 -echo "${ECHO_T}$ac_cv_header_limits_h" >&6 - -fi -if test $ac_cv_header_limits_h = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_LIMITS_H 1 -_ACEOF - -else - -cat >>confdefs.h <<\_ACEOF -#define NO_LIMITS_H 1 -_ACEOF - -fi - - - -#-------------------------------------------------------------------- -# Supply a substitute for stdlib.h if it doesn't define strtol, -# strtoul, or strtod (which it doesn't in some versions of SunOS). -#-------------------------------------------------------------------- - if test "${ac_cv_header_stdlib_h+set}" = set; then echo "$as_me:$LINENO: checking for stdlib.h" >&5 echo $ECHO_N "checking for stdlib.h... $ECHO_C" >&6 diff --git a/unix/configure.in b/unix/configure.in index 26aadfd..5a18d46 100644 --- a/unix/configure.in +++ b/unix/configure.in @@ -81,12 +81,6 @@ fi AC_PROG_CC AC_C_INLINE -# limits header checks must come early to prevent -# an autoconf bug that throws errors on configure -AC_CHECK_HEADER(limits.h, - [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], - [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) - #-------------------------------------------------------------------- # Supply a substitute for stdlib.h if it doesn't define strtol, # strtoul, or strtod (which it doesn't in some versions of SunOS). diff --git a/unix/tcl.m4 b/unix/tcl.m4 index 30b3bc1..1a56932 100644 --- a/unix/tcl.m4 +++ b/unix/tcl.m4 @@ -2158,7 +2158,6 @@ dnl # preprocessing tests use only CPPFLAGS. # Defines some of the following vars: # NO_DIRENT_H # NO_VALUES_H -# HAVE_LIMITS_H or NO_LIMITS_H # NO_STDLIB_H # NO_STRING_H # NO_SYS_WAIT_H @@ -2198,9 +2197,6 @@ closedir(d); AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) - AC_CHECK_HEADER(limits.h, - [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], - [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) diff --git a/unix/tkConfig.h.in b/unix/tkConfig.h.in index 1e5593c..4fd7726 100644 --- a/unix/tkConfig.h.in +++ b/unix/tkConfig.h.in @@ -25,9 +25,6 @@ /* Define to 1 if you have the `Xft' library (-lXft). */ #undef HAVE_LIBXFT -/* Do we have ? */ -#undef HAVE_LIMITS_H - /* Define to 1 if you have the `lseek64' function. */ #undef HAVE_LSEEK64 @@ -115,9 +112,6 @@ /* Do we have fd_set? */ #undef NO_FD_SET -/* Do we have ? */ -#undef NO_LIMITS_H - /* Do we have ? */ #undef NO_STDLIB_H diff --git a/unix/tkUnixPort.h b/unix/tkUnixPort.h index 9051c63..dbd5e09 100644 --- a/unix/tkUnixPort.h +++ b/unix/tkUnixPort.h @@ -20,11 +20,7 @@ #include #include #include -#ifndef NO_LIMITS_H -# include -#else -# include "../compat/limits.h" -#endif +#include #include #include #ifdef NO_STDLIB_H -- cgit v0.12 From ccdac05dbacc3b62fc27a65c11c8bd1188daddf4 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Tue, 7 Apr 2015 01:12:45 +0000 Subject: Further cleanup of scrolling, drawing, resize in Cocoa; thanks to Marc Culler for patches --- generic/tkCanvas.c | 13 +++++++ generic/tkInt.decls | 3 ++ generic/tkIntPlatDecls.h | 5 ++- generic/tkTextDisp.c | 30 +++++++-------- macosx/tkMacOSXButton.c | 21 ++++++----- macosx/tkMacOSXDraw.c | 86 ++++++++++++++++++++++++++++++++---------- macosx/tkMacOSXInt.h | 2 +- macosx/tkMacOSXScrlbr.c | 59 ++++++++++++++++------------- macosx/tkMacOSXSubwindows.c | 59 +++++++++++++++++++++++++++++ macosx/tkMacOSXWindowEvent.c | 90 ++++++++++++++++++++++++-------------------- 10 files changed, 253 insertions(+), 115 deletions(-) diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 8e14852..9c4d60a 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -2447,6 +2447,19 @@ DisplayCanvas( goto done; } +#ifdef MAC_OSX_TK + /* + * If drawing is disabled, all we need to do is + * clear the REDRAW_PENDING flag. + */ + TkWindow *winPtr = (TkWindow *)(canvasPtr->tkwin); + MacDrawable *macWin = winPtr->privatePtr; + if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ + canvasPtr->flags &= ~REDRAW_PENDING; + return; + } +#endif + /* * Choose a new current item if that is needed (this could cause event * handlers to be invoked). diff --git a/generic/tkInt.decls b/generic/tkInt.decls index ebbadba..8924d68 100644 --- a/generic/tkInt.decls +++ b/generic/tkInt.decls @@ -1017,6 +1017,9 @@ declare 50 aqua { declare 51 aqua { void TkGenWMDestroyEvent(Tk_Window tkwin) } +declare 52 aqua { + TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag); +} # removed duplicate from tkPlat table (tk.decls) #declare 52 aqua { diff --git a/generic/tkIntPlatDecls.h b/generic/tkIntPlatDecls.h index 3a2a8aa..3a4bdac 100644 --- a/generic/tkIntPlatDecls.h +++ b/generic/tkIntPlatDecls.h @@ -250,7 +250,8 @@ EXTERN int TkGenerateButtonEvent(int x, int y, Window window, unsigned int state); /* 51 */ EXTERN void TkGenWMDestroyEvent(Tk_Window tkwin); -/* Slot 52 is reserved */ +/* 52 */ +EXTERN void TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag); /* 53 */ EXTERN unsigned long TkpGetMS(void); /* 54 */ @@ -395,7 +396,7 @@ typedef struct TkIntPlatStubs { Window (*tkGetTransientMaster) (TkWindow *winPtr); /* 49 */ int (*tkGenerateButtonEvent) (int x, int y, Window window, unsigned int state); /* 50 */ void (*tkGenWMDestroyEvent) (Tk_Window tkwin); /* 51 */ - void (*reserved52)(void); + void (*tkMacOSXSetDrawingEnabled) (TkWindow *winPtr, int flag); /* 52 */ unsigned long (*tkpGetMS) (void); /* 53 */ void * (*tkMacOSXDrawable) (Drawable drawable); /* 54 */ int (*tkpScanWindowId) (Tcl_Interp *interp, const char *string, Window *idPtr); /* 55 */ diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 95ea935..c3bcd5e 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -3948,7 +3948,6 @@ DisplayText( * warnings. */ Tcl_Interp *interp; - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { /* * The widget has been deleted. Don't do anything. @@ -3957,6 +3956,19 @@ DisplayText( return; } +#ifdef MAC_OSX_TK + /* + * If drawing is disabled, all we need to do is + * clear the REDRAW_PENDING flag. + */ + TkWindow *winPtr = (TkWindow *)(textPtr->tkwin); + MacDrawable *macWin = winPtr->privatePtr; + if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ + dInfoPtr->flags &= ~REDRAW_PENDING; + return; + } +#endif + interp = textPtr->interp; Tcl_Preserve(interp); @@ -3964,14 +3976,6 @@ DisplayText( Tcl_SetVar2(interp, "tk_textRelayout", NULL, "", TCL_GLOBAL_ONLY); } - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - if (!Tk_IsMapped(textPtr->tkwin) || (dInfoPtr->maxX <= dInfoPtr->x) || (dInfoPtr->maxY <= dInfoPtr->y)) { UpdateDisplayInfo(textPtr); @@ -3983,14 +3987,6 @@ DisplayText( Tcl_SetVar2(interp, "tk_textRedraw", NULL, "", TCL_GLOBAL_ONLY); } - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - /* * Choose a new current item if that is needed (this could cause event * handlers to be invoked, hence the preserve/release calls and the loop, diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 725c211..59d394e 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -30,10 +30,10 @@ * Default insets for controls */ -#define DEF_INSET_LEFT 2 -#define DEF_INSET_RIGHT 2 -#define DEF_INSET_TOP 2 -#define DEF_INSET_BOTTOM 4 +#define DEF_INSET_LEFT 12 +#define DEF_INSET_RIGHT 12 +#define DEF_INSET_TOP 1 +#define DEF_INSET_BOTTOM 1 /* * Some defines used to control what type of control is drawn. @@ -318,8 +318,8 @@ TkpComputeButtonGeometry( Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); - txtWidth = butPtr->textWidth; - txtHeight = butPtr->textHeight; + txtWidth = butPtr->textWidth + DEF_INSET_LEFT + DEF_INSET_RIGHT; + txtHeight = butPtr->textHeight + DEF_INSET_BOTTOM + DEF_INSET_TOP; charWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); Tk_GetFontMetrics(butPtr->tkfont, &fm); haveText = (txtWidth != 0 && txtHeight != 0); @@ -647,7 +647,7 @@ DrawButtonImageAndText( butPtr->textHeight, &x, &y); x += butPtr->indicatorSpace; Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, - x, y, 0, -1); + x, y - DEF_INSET_BOTTOM, 0, -1); } /* @@ -807,9 +807,12 @@ TkMacOSXDrawButton( hiinfo.animation.time.start = hiinfo.animation.time.current; } - HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); + HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, + &contHIRec); + TkMacOSXRestoreDrawingContext(&dc); - ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, (MacButton *)mbPtr, 32, true); + ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, + (MacButton *)mbPtr, 32, true); } else { if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 328f905..0f6d2f0 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -222,7 +222,8 @@ XCopyArea( } if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { - TkMacOSXDbgMsg("Failed to setup drawing context."); + return; + /*TkMacOSXDbgMsg("Failed to setup drawing context.");*/ } if ( dc.context ) { @@ -243,6 +244,8 @@ XCopyArea( CGRectMake(src_x, src_y, width, height), CGRectMake(dest_x, dest_y, width, height)); CFRelease(img); + + } else { TkMacOSXDbgMsg("Failed to construct CGImage."); } @@ -652,9 +655,9 @@ GetCGContextForDrawable( CGColorSpaceRef colorspace = NULL; CGBitmapInfo bitmapInfo = #ifdef __LITTLE_ENDIAN__ - kCGBitmapByteOrder32Host; + kCGBitmapByteOrder32Host; #else - kCGBitmapByteOrderDefault; + kCGBitmapByteOrderDefault; #endif char *data; CGRect bounds = CGRectMake(0, 0, macDraw->size.width, @@ -731,6 +734,7 @@ DrawCGImage( } } dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff); + if (CGImageIsMask(image)) { /*CGContextSaveGState(context);*/ if (macDraw->flags & TK_IS_BW_PIXMAP) { @@ -765,8 +769,8 @@ DrawCGImage( dstBounds.size.width, dstBounds.size.height); #else /* TK_MAC_DEBUG_IMAGE_DRAWING */ CGContextSaveGState(context); - CGContextTranslateCTM(context, - 0, dstBounds.origin.y + CGRectGetMaxY(dstBounds)); + CGContextTranslateCTM(context, 0, + dstBounds.origin.y + CGRectGetMaxY(dstBounds)); CGContextScaleCTM(context, 1, -1); CGContextDrawImage(context, dstBounds, image); CGContextRestoreGState(context); @@ -1478,10 +1482,9 @@ TkScrollWindow( MacDrawable *macDraw = (MacDrawable *) drawable; NSView *view = TkMacOSXDrawableView(macDraw); CGRect srcRect, dstRect; - HIShapeRef dmgRgn = NULL, extraRgn; + HIShapeRef dmgRgn = NULL, extraRgn = NULL; NSRect bounds, visRect, scrollSrc, scrollDst; - int result; - + int result = 0; if ( view ) { /* Get the scroll area in NSView coordinates (origin at bottom left). */ @@ -1491,36 +1494,79 @@ TkScrollWindow( bounds.size.height - height - (macDraw->yOff + y), width, height); scrollDst = NSOffsetRect(scrollSrc, dx, -dy); + /* Limit scrolling to the window content area. */ visRect = [view visibleRect]; scrollSrc = NSIntersectionRect(scrollSrc, visRect); scrollDst = NSIntersectionRect(scrollDst, visRect); - if ( !NSIsEmptyRect(scrollSrc) && !NSIsEmptyRect(scrollDst) ) { /* * Mark the difference between source and destination as damaged. - * This region is described in the Tk coordinate system. + * This region is described in NSView coordinates (y=0 at the bottom) + * and converted to Tk coordinates later. */ - srcRect = CGRectMake(x, y, width, height); - dstRect = CGRectOffset(srcRect, dx, dy); + srcRect = CGRectMake(x, y, width, height); + dstRect = CGRectOffset(srcRect, dx, dy); + + /* Expand the rectangles slightly to avoid degeneracies. */ + srcRect.origin.y -= 1; + srcRect.size.height += 2; + dstRect.origin.y += 1; + dstRect.size.height -= 2; + + /* Compute the damage. */ dmgRgn = HIShapeCreateMutableWithRect(&srcRect); extraRgn = HIShapeCreateWithRect(&dstRect); ChkErr(HIShapeDifference, dmgRgn, extraRgn, (HIMutableShapeRef) dmgRgn); - CFRelease(extraRgn); + result = HIShapeIsEmpty(dmgRgn) ? 0 : 1; + + /* Convert to Tk coordinates. */ + TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); + if (extraRgn) { + CFRelease(extraRgn); + } /* Scroll the rectangle. */ [view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)]; + + /* Shift the Tk children which meet the source rectangle. */ + TkWindow *winPtr = (TkWindow *)tkwin; + TkWindow *childPtr; + CGRect childBounds; + for (childPtr = winPtr->childList; childPtr != NULL; childPtr = childPtr->nextPtr) { + if (Tk_IsMapped(childPtr) && !Tk_IsTopLevel(childPtr)) { + TkMacOSXWinCGBounds(childPtr, &childBounds); + if (CGRectIntersectsRect(srcRect, childBounds)) { + MacDrawable *macChild = childPtr->privatePtr; + if (macChild) { + macChild->yOff += dy; + macChild->xOff += dx; + childPtr->changes.y = macChild->yOff; + childPtr->changes.x = macChild->xOff; + } + } + } + } + + /* Queue up Expose events for the damage region. */ + int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); + [view generateExposeEvents:dmgRgn childrenOnly:1]; + Tcl_SetServiceMode(oldMode); + + /* Belt and suspenders: make the AppKit request a redraw + when it gets control again. */ + [view setNeedsDisplay:YES]; } + } else { + dmgRgn = HIShapeCreateEmpty(); + TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); } - if ( dmgRgn == NULL ) { - dmgRgn = HIShapeCreateEmpty(); + if (dmgRgn) { + CFRelease(dmgRgn); } - TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); - result = HIShapeIsEmpty(dmgRgn) ? 0 : 1; - CFRelease(dmgRgn); return result; } @@ -1855,6 +1901,7 @@ TkpClipDrawableToRect( CFRelease(macDraw->drawRgn); macDraw->drawRgn = NULL; } + if (width >= 0 && height >= 0) { CGRect clipRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff, width, height); @@ -2002,7 +2049,7 @@ TkpDrawHighlightBorder ( * TkpDrawFrame -- * * This procedure draws the rectangular frame area. If the user - * has request themeing, it draws with a the background theme. + * has requested themeing, it draws with the background theme. * * Results: * None. @@ -2032,6 +2079,7 @@ TkpDrawFrame( border = themedBorder; } } + Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, highlightWidth, highlightWidth, Tk_Width(tkwin) - 2 * highlightWidth, diff --git a/macosx/tkMacOSXInt.h b/macosx/tkMacOSXInt.h index 249d5cf..6971e26 100644 --- a/macosx/tkMacOSXInt.h +++ b/macosx/tkMacOSXInt.h @@ -86,7 +86,7 @@ typedef struct TkWindowPrivate MacDrawable; #define TK_FOCUSED_VIEW 0x10 #define TK_IS_PIXMAP 0x20 #define TK_IS_BW_PIXMAP 0x40 - +#define TK_DO_NOT_DRAW 0x80 /* * I am reserving TK_EMBEDDED = 0x100 in the MacDrawable flags * This is defined in tk.h. We need to duplicate the TK_EMBEDDED flag in the diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index bdb76af..4d4949f 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -26,6 +26,7 @@ #define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum)) #endif /* __LP64__ */ +#define MOUNTAIN_LION_STYLE (NSAppKitVersionNumber < 1138) /* * Declaration of Mac specific scrollbar structure. @@ -80,7 +81,6 @@ static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr); static int ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr); static void UpdateControlValues(TkScrollbar *scrollPtr); - /* *---------------------------------------------------------------------- * @@ -137,7 +137,6 @@ TkpDisplayScrollbar( register TkScrollbar *scrollPtr = (TkScrollbar *) clientData; register Tk_Window tkwin = scrollPtr->tkwin; - if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } @@ -150,7 +149,6 @@ TkpDisplayScrollbar( CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, .ty = viewHeight}; - scrollPtr->flags &= ~REDRAW_PENDING; if (!scrollPtr->tkwin || !Tk_IsMapped(tkwin) || !view || !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { @@ -173,7 +171,6 @@ TkpDisplayScrollbar( (Pixmap) macWin); } - Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, scrollPtr->highlightWidth, scrollPtr->highlightWidth, Tk_Width(tkwin) - 2*scrollPtr->highlightWidth, @@ -186,15 +183,11 @@ TkpDisplayScrollbar( /*Update values and draw in native rect.*/ UpdateControlValues(scrollPtr); -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 - if (scrollPtr->vertical) { - HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); - } else { + if (MOUNTAIN_LION_STYLE) { HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationInverted); + } else { + HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); } -#else - HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); -#endif TkMacOSXRestoreDrawingContext(&dc); scrollPtr->flags &= ~REDRAW_PENDING; @@ -265,11 +258,12 @@ TkpComputeScrollbarGeometry( if (scrollPtr->sliderLast > fieldLength) { scrollPtr->sliderLast = fieldLength; } - scrollPtr->sliderFirst += scrollPtr->inset + + if (!(MOUNTAIN_LION_STYLE)) { + scrollPtr->sliderFirst += scrollPtr->inset + metrics[variant].topArrowHeight; - scrollPtr->sliderLast += scrollPtr->inset + + scrollPtr->sliderLast += scrollPtr->inset + metrics[variant].bottomArrowHeight; - + } /* * Register the desired geometry for the window (leave enough space * for the two arrows plus a minimum-size slider, plus border around @@ -370,21 +364,29 @@ TkpScrollbarPosition( int x, int y) /* Coordinates within scrollPtr's window. */ { - /*Using code from tkUnixScrlbr.c because Unix scroll bindings are driving the display at the script level. All the Mac scrollbar has to do is re-draw itself.*/ + /* + * Using code from tkUnixScrlbr.c because Unix scroll bindings are + * driving the display at the script level. All the Mac scrollbar + * has to do is re-draw itself. + */ - int length, width, tmp; + int length, fieldlength, width, tmp; register const int inset = scrollPtr->inset; + register const int arrowSize = scrollPtr->arrowLength + inset; if (scrollPtr->vertical) { length = Tk_Height(scrollPtr->tkwin); + fieldlength = length - 2 * arrowSize; width = Tk_Width(scrollPtr->tkwin); } else { tmp = x; x = y; y = tmp; length = Tk_Width(scrollPtr->tkwin); + fieldlength = length - 2 * arrowSize; width = Tk_Height(scrollPtr->tkwin); } + fieldlength = fieldlength < 0 ? 0 : fieldlength; if (x=width-inset || y=length-inset) { return OUTSIDE; @@ -395,19 +397,19 @@ TkpScrollbarPosition( * TkpDisplayScrollbar. Be sure to keep the two consistent. */ - if (y < inset + scrollPtr->arrowLength) { - return TOP_ARROW; - } if (y < scrollPtr->sliderFirst) { return TOP_GAP; } if (y < scrollPtr->sliderLast) { return SLIDER; } - if (y >= length - (scrollPtr->arrowLength + inset)) { - return BOTTOM_ARROW; + if (y < fieldlength){ + return BOTTOM_GAP; + } + if (y < fieldlength + arrowSize) { + return TOP_ARROW; } - return BOTTOM_GAP; + return BOTTOM_ARROW; } /* @@ -415,9 +417,11 @@ TkpScrollbarPosition( * * UpdateControlValues -- * - * This procedure updates the Macintosh scrollbar control to display the - * values defined by the Tk scrollbar. This is the key interface to the Mac-native * scrollbar; the Unix bindings drive scrolling in the Tk window and all the Mac - * scrollbar has to do is redraw itself. + * This procedure updates the Macintosh scrollbar control to + * display the values defined by the Tk scrollbar. This is the + * key interface to the Mac-native * scrollbar; the Unix bindings + * drive scrolling in the Tk window and all the Mac scrollbar has + * to do is redraw itself. * * Results: * None. @@ -432,7 +436,6 @@ static void UpdateControlValues( TkScrollbar *scrollPtr) /* Scrollbar data struct. */ { - Tk_Window tkwin = scrollPtr->tkwin; MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin); double dViewSize; @@ -484,7 +487,11 @@ UpdateControlValues( factor - dViewSize; info.trackInfo.scrollbar.viewsize = dViewSize; if (scrollPtr->vertical) { + if (MOUNTAIN_LION_STYLE) { + info.value = factor * scrollPtr->firstFraction; + } else { info.value = info.max - factor * scrollPtr->firstFraction; + } } else { info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction; } diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 869f717..2a88422 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -657,6 +657,65 @@ XConfigureWindow( /* *---------------------------------------------------------------------- * + * TkMacOSXSetDrawingEnabled -- + * + * This function sets the TK_DO_NOT_DRAW flag for a given window and + * all of its children. + * + * Results: + * None. + * + * Side effects: + * The clipping regions for the window and its children are cleared. + * + *---------------------------------------------------------------------- + */ + +void +TkMacOSXSetDrawingEnabled( + TkWindow *winPtr, + int flag) +{ + TkWindow *childPtr; + MacDrawable *macWin = winPtr->privatePtr; + + if (macWin) { + if (flag ) { + macWin->flags &= ~TK_DO_NOT_DRAW; + } else { + macWin->flags |= TK_DO_NOT_DRAW; + } + } + + /* + * Set the flag for all children & their descendants, excluding + * Toplevels. (??? Do we need to exclude Toplevels?) + */ + + childPtr = winPtr->childList; + while (childPtr) { + if (!Tk_IsTopLevel(childPtr)) { + TkMacOSXSetDrawingEnabled(childPtr, flag); + } + childPtr = childPtr->nextPtr; + } + + /* + * If the window is a container, set the flag for its embedded window. + */ + + if (Tk_IsContainer(winPtr)) { + childPtr = TkpGetOtherWindow(winPtr); + + if (childPtr) { + TkMacOSXSetDrawingEnabled(childPtr, flag); + } + } +} + +/* + *---------------------------------------------------------------------- + * * TkMacOSXUpdateClipRgn -- * * This function updates the clipping regions for a given window and all of diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 2e7c041..35f9f1c 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -29,7 +29,7 @@ * Declaration of functions used only in this file */ -static int GenerateUpdates(HIMutableShapeRef updateRgn, +static int GenerateUpdates(HIShapeRef updateRgn, CGRect *updateBounds, TkWindow *winPtr); static int GenerateActivateEvents(TkWindow *winPtr, int activeFlag); @@ -315,7 +315,7 @@ extern BOOL opaqueTag; static int GenerateUpdates( - HIMutableShapeRef updateRgn, + HIShapeRef updateRgn, CGRect *updateBounds, TkWindow *winPtr) { @@ -782,7 +782,8 @@ Tk_MacOSXIsAppInFront(void) @interface TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect; -- (void) generateExposeEvents: (HIMutableShapeRef) shape; +- (void) generateExposeEvents: (HIShapeRef) shape; +- (void) generateExposeEvents: (HIShapeRef) shape childrenOnly: (int) childrenOnly; - (void) viewDidEndLiveResize; - (void) tkToolbarButton: (id) sender; - (BOOL) isOpaque; @@ -792,6 +793,8 @@ Tk_MacOSXIsAppInFront(void) @end @implementation TKContentView +NSDate *_resizeStart; +NSTimeInterval _resizeDuration; @end /*Restrict event processing to Expose events.*/ @@ -829,7 +832,7 @@ ExposeRestrictProc( HIShapeUnionWithRect(drawShape, &r); } if (CFRunLoopGetMain() == CFRunLoopGetCurrent()) { - [self generateExposeEvents:drawShape]; + [self generateExposeEvents:(HIShapeRef)drawShape]; } else { [self performSelectorOnMainThread:@selector(generateExposeEvents:) withObject:(id)drawShape waitUntilDone:NO @@ -844,25 +847,33 @@ ExposeRestrictProc( -(void) setFrameSize: (NSSize)newsize { if ( [self inLiveResize] ) { - NSWindow *window = [self window]; - TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); + NSWindow *w = [self window]; + TkWindow *winPtr = TkMacOSXGetTkWindow(w); Tk_Window tkwin = (Tk_Window) winPtr; unsigned int width = (unsigned int)newsize.width; unsigned int height=(unsigned int)newsize.height; - /* Resize the Tk Window to the requested size.*/ - TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height, - TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY); - - /* Then resize the NSView to the actual window size*/ - newsize.width = (CGFloat)Tk_Width(tkwin); - newsize.height = (CGFloat)Tk_Height(tkwin); + /* Resize the NSView */ [super setFrameSize: newsize]; - /* Process all pending events to update the window. */ - while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} + /* Disable drawing until the window has been completely configured.*/ + TkMacOSXSetDrawingEnabled(winPtr, 0); + /* Generate and handle a ConfigureNotify event for the new size.*/ + TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height, + TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY); + while ( Tk_DoOneEvent(TK_X_EVENTS|TK_DONT_WAIT) ) {} + + /* Now that Tk has configured all subwindows we can create the clip regions. */ + TkMacOSXSetDrawingEnabled(winPtr, 1); + TkMacOSXInvalClipRgns(tkwin); + TkMacOSXUpdateClipRgn(winPtr); + + /* Finally, generate and process expose events to redraw the window. */ + HIRect bounds = NSRectToCGRect([self bounds]); + HIShapeRef shape = HIShapeCreateWithRect(&bounds); + [self generateExposeEvents: shape]; + while ( Tk_DoOneEvent(TK_ALL_EVENTS|TK_DONT_WAIT) ) {} } else { [super setFrameSize: newsize]; } @@ -881,46 +892,44 @@ ExposeRestrictProc( [self generateExposeEvents: shape]; } -/*Core function of this class, generates expose events for redrawing.*/ -- (void) generateExposeEvents: (HIMutableShapeRef) shape +/* Core method of this class: generates expose events for redrawing. + * Whereas drawRect is intended to be called only from the Appkit event + * loop, this can be called from Tk. If the Tcl_ServiceMode is set to + * TCL_SERVICE_ALL then the expose events will be immediately removed + * from the Tcl event loop and processed. Typically, they should be queued, + * however. + */ +- (void) generateExposeEvents: (HIShapeRef) shape +{ + [self generateExposeEvents:shape childrenOnly:0]; +} + +- (void) generateExposeEvents: (HIShapeRef) shape + childrenOnly: (int) childrenOnly { TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); unsigned long serial; CGRect updateBounds; + int updatesNeeded; if (!winPtr) { return; } + /* Generate Tk Expose events. */ HIShapeGetBounds(shape, &updateBounds); + /* All of these events will share the same serial number. */ serial = LastKnownRequestProcessed(Tk_Display(winPtr)); - if (GenerateUpdates(shape, &updateBounds, winPtr) && - ![[NSRunLoop currentRunLoop] currentMode] && - Tcl_GetServiceMode() != TCL_SERVICE_NONE) { - /* - * Ensure there are no pending idle-time redraws that could - * prevent the just posted Expose events from generating - * new redraws. - */ - - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} - - /* - * For smoother drawing, process Expose events and resulting - * redraws immediately instead of at idle time. - */ - - ClientData oldArg; + updatesNeeded = GenerateUpdates(shape, &updateBounds, winPtr); + + /* Process the Expose events if the service mode is TCL_SERVICE_ALL */ + if (updatesNeeded && Tcl_GetServiceMode() == TCL_SERVICE_ALL) { + ClientData oldArg; Tk_RestrictProc *oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg); - while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} - Tk_RestrictEvents(oldProc, oldArg, &oldArg); - - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} } - } /* @@ -936,7 +945,6 @@ ExposeRestrictProc( int x, y; TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); Tk_Window tkwin = (Tk_Window) winPtr; - bzero(&event, sizeof(XVirtualEvent)); event.type = VirtualEvent; event.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); -- cgit v0.12 From 6540e0be10afe7208f8e370632256cfd262f5706 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Tue, 7 Apr 2015 01:42:59 +0000 Subject: Backing out changes; unexpected issues with window resizing that require further investigation --- generic/tkCanvas.c | 13 ------- generic/tkInt.decls | 3 -- generic/tkIntPlatDecls.h | 5 +-- generic/tkTextDisp.c | 30 ++++++++------- macosx/tkMacOSXButton.c | 21 +++++------ macosx/tkMacOSXDraw.c | 86 ++++++++++-------------------------------- macosx/tkMacOSXInt.h | 2 +- macosx/tkMacOSXScrlbr.c | 59 +++++++++++++---------------- macosx/tkMacOSXSubwindows.c | 59 ----------------------------- macosx/tkMacOSXWindowEvent.c | 90 ++++++++++++++++++++------------------------ 10 files changed, 115 insertions(+), 253 deletions(-) diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 9c4d60a..8e14852 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -2447,19 +2447,6 @@ DisplayCanvas( goto done; } -#ifdef MAC_OSX_TK - /* - * If drawing is disabled, all we need to do is - * clear the REDRAW_PENDING flag. - */ - TkWindow *winPtr = (TkWindow *)(canvasPtr->tkwin); - MacDrawable *macWin = winPtr->privatePtr; - if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ - canvasPtr->flags &= ~REDRAW_PENDING; - return; - } -#endif - /* * Choose a new current item if that is needed (this could cause event * handlers to be invoked). diff --git a/generic/tkInt.decls b/generic/tkInt.decls index 8924d68..ebbadba 100644 --- a/generic/tkInt.decls +++ b/generic/tkInt.decls @@ -1017,9 +1017,6 @@ declare 50 aqua { declare 51 aqua { void TkGenWMDestroyEvent(Tk_Window tkwin) } -declare 52 aqua { - TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag); -} # removed duplicate from tkPlat table (tk.decls) #declare 52 aqua { diff --git a/generic/tkIntPlatDecls.h b/generic/tkIntPlatDecls.h index 3a4bdac..3a2a8aa 100644 --- a/generic/tkIntPlatDecls.h +++ b/generic/tkIntPlatDecls.h @@ -250,8 +250,7 @@ EXTERN int TkGenerateButtonEvent(int x, int y, Window window, unsigned int state); /* 51 */ EXTERN void TkGenWMDestroyEvent(Tk_Window tkwin); -/* 52 */ -EXTERN void TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag); +/* Slot 52 is reserved */ /* 53 */ EXTERN unsigned long TkpGetMS(void); /* 54 */ @@ -396,7 +395,7 @@ typedef struct TkIntPlatStubs { Window (*tkGetTransientMaster) (TkWindow *winPtr); /* 49 */ int (*tkGenerateButtonEvent) (int x, int y, Window window, unsigned int state); /* 50 */ void (*tkGenWMDestroyEvent) (Tk_Window tkwin); /* 51 */ - void (*tkMacOSXSetDrawingEnabled) (TkWindow *winPtr, int flag); /* 52 */ + void (*reserved52)(void); unsigned long (*tkpGetMS) (void); /* 53 */ void * (*tkMacOSXDrawable) (Drawable drawable); /* 54 */ int (*tkpScanWindowId) (Tcl_Interp *interp, const char *string, Window *idPtr); /* 55 */ diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index c3bcd5e..95ea935 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -3948,6 +3948,7 @@ DisplayText( * warnings. */ Tcl_Interp *interp; + if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { /* * The widget has been deleted. Don't do anything. @@ -3956,19 +3957,6 @@ DisplayText( return; } -#ifdef MAC_OSX_TK - /* - * If drawing is disabled, all we need to do is - * clear the REDRAW_PENDING flag. - */ - TkWindow *winPtr = (TkWindow *)(textPtr->tkwin); - MacDrawable *macWin = winPtr->privatePtr; - if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ - dInfoPtr->flags &= ~REDRAW_PENDING; - return; - } -#endif - interp = textPtr->interp; Tcl_Preserve(interp); @@ -3976,6 +3964,14 @@ DisplayText( Tcl_SetVar2(interp, "tk_textRelayout", NULL, "", TCL_GLOBAL_ONLY); } + if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { + /* + * The widget has been deleted. Don't do anything. + */ + + goto end; + } + if (!Tk_IsMapped(textPtr->tkwin) || (dInfoPtr->maxX <= dInfoPtr->x) || (dInfoPtr->maxY <= dInfoPtr->y)) { UpdateDisplayInfo(textPtr); @@ -3987,6 +3983,14 @@ DisplayText( Tcl_SetVar2(interp, "tk_textRedraw", NULL, "", TCL_GLOBAL_ONLY); } + if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { + /* + * The widget has been deleted. Don't do anything. + */ + + goto end; + } + /* * Choose a new current item if that is needed (this could cause event * handlers to be invoked, hence the preserve/release calls and the loop, diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 59d394e..725c211 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -30,10 +30,10 @@ * Default insets for controls */ -#define DEF_INSET_LEFT 12 -#define DEF_INSET_RIGHT 12 -#define DEF_INSET_TOP 1 -#define DEF_INSET_BOTTOM 1 +#define DEF_INSET_LEFT 2 +#define DEF_INSET_RIGHT 2 +#define DEF_INSET_TOP 2 +#define DEF_INSET_BOTTOM 4 /* * Some defines used to control what type of control is drawn. @@ -318,8 +318,8 @@ TkpComputeButtonGeometry( Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); - txtWidth = butPtr->textWidth + DEF_INSET_LEFT + DEF_INSET_RIGHT; - txtHeight = butPtr->textHeight + DEF_INSET_BOTTOM + DEF_INSET_TOP; + txtWidth = butPtr->textWidth; + txtHeight = butPtr->textHeight; charWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); Tk_GetFontMetrics(butPtr->tkfont, &fm); haveText = (txtWidth != 0 && txtHeight != 0); @@ -647,7 +647,7 @@ DrawButtonImageAndText( butPtr->textHeight, &x, &y); x += butPtr->indicatorSpace; Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, - x, y - DEF_INSET_BOTTOM, 0, -1); + x, y, 0, -1); } /* @@ -807,12 +807,9 @@ TkMacOSXDrawButton( hiinfo.animation.time.start = hiinfo.animation.time.current; } - HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, - &contHIRec); - + HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); TkMacOSXRestoreDrawingContext(&dc); - ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, - (MacButton *)mbPtr, 32, true); + ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, (MacButton *)mbPtr, 32, true); } else { if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 0f6d2f0..328f905 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -222,8 +222,7 @@ XCopyArea( } if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { - return; - /*TkMacOSXDbgMsg("Failed to setup drawing context.");*/ + TkMacOSXDbgMsg("Failed to setup drawing context."); } if ( dc.context ) { @@ -244,8 +243,6 @@ XCopyArea( CGRectMake(src_x, src_y, width, height), CGRectMake(dest_x, dest_y, width, height)); CFRelease(img); - - } else { TkMacOSXDbgMsg("Failed to construct CGImage."); } @@ -655,9 +652,9 @@ GetCGContextForDrawable( CGColorSpaceRef colorspace = NULL; CGBitmapInfo bitmapInfo = #ifdef __LITTLE_ENDIAN__ - kCGBitmapByteOrder32Host; + kCGBitmapByteOrder32Host; #else - kCGBitmapByteOrderDefault; + kCGBitmapByteOrderDefault; #endif char *data; CGRect bounds = CGRectMake(0, 0, macDraw->size.width, @@ -734,7 +731,6 @@ DrawCGImage( } } dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff); - if (CGImageIsMask(image)) { /*CGContextSaveGState(context);*/ if (macDraw->flags & TK_IS_BW_PIXMAP) { @@ -769,8 +765,8 @@ DrawCGImage( dstBounds.size.width, dstBounds.size.height); #else /* TK_MAC_DEBUG_IMAGE_DRAWING */ CGContextSaveGState(context); - CGContextTranslateCTM(context, 0, - dstBounds.origin.y + CGRectGetMaxY(dstBounds)); + CGContextTranslateCTM(context, + 0, dstBounds.origin.y + CGRectGetMaxY(dstBounds)); CGContextScaleCTM(context, 1, -1); CGContextDrawImage(context, dstBounds, image); CGContextRestoreGState(context); @@ -1482,9 +1478,10 @@ TkScrollWindow( MacDrawable *macDraw = (MacDrawable *) drawable; NSView *view = TkMacOSXDrawableView(macDraw); CGRect srcRect, dstRect; - HIShapeRef dmgRgn = NULL, extraRgn = NULL; + HIShapeRef dmgRgn = NULL, extraRgn; NSRect bounds, visRect, scrollSrc, scrollDst; - int result = 0; + int result; + if ( view ) { /* Get the scroll area in NSView coordinates (origin at bottom left). */ @@ -1494,79 +1491,36 @@ TkScrollWindow( bounds.size.height - height - (macDraw->yOff + y), width, height); scrollDst = NSOffsetRect(scrollSrc, dx, -dy); - /* Limit scrolling to the window content area. */ visRect = [view visibleRect]; scrollSrc = NSIntersectionRect(scrollSrc, visRect); scrollDst = NSIntersectionRect(scrollDst, visRect); + if ( !NSIsEmptyRect(scrollSrc) && !NSIsEmptyRect(scrollDst) ) { /* * Mark the difference between source and destination as damaged. - * This region is described in NSView coordinates (y=0 at the bottom) - * and converted to Tk coordinates later. + * This region is described in the Tk coordinate system. */ - srcRect = CGRectMake(x, y, width, height); - dstRect = CGRectOffset(srcRect, dx, dy); - - /* Expand the rectangles slightly to avoid degeneracies. */ - srcRect.origin.y -= 1; - srcRect.size.height += 2; - dstRect.origin.y += 1; - dstRect.size.height -= 2; - - /* Compute the damage. */ + srcRect = CGRectMake(x, y, width, height); + dstRect = CGRectOffset(srcRect, dx, dy); dmgRgn = HIShapeCreateMutableWithRect(&srcRect); extraRgn = HIShapeCreateWithRect(&dstRect); ChkErr(HIShapeDifference, dmgRgn, extraRgn, (HIMutableShapeRef) dmgRgn); - result = HIShapeIsEmpty(dmgRgn) ? 0 : 1; - - /* Convert to Tk coordinates. */ - TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); - if (extraRgn) { - CFRelease(extraRgn); - } + CFRelease(extraRgn); /* Scroll the rectangle. */ [view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)]; - - /* Shift the Tk children which meet the source rectangle. */ - TkWindow *winPtr = (TkWindow *)tkwin; - TkWindow *childPtr; - CGRect childBounds; - for (childPtr = winPtr->childList; childPtr != NULL; childPtr = childPtr->nextPtr) { - if (Tk_IsMapped(childPtr) && !Tk_IsTopLevel(childPtr)) { - TkMacOSXWinCGBounds(childPtr, &childBounds); - if (CGRectIntersectsRect(srcRect, childBounds)) { - MacDrawable *macChild = childPtr->privatePtr; - if (macChild) { - macChild->yOff += dy; - macChild->xOff += dx; - childPtr->changes.y = macChild->yOff; - childPtr->changes.x = macChild->xOff; - } - } - } - } - - /* Queue up Expose events for the damage region. */ - int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); - [view generateExposeEvents:dmgRgn childrenOnly:1]; - Tcl_SetServiceMode(oldMode); - - /* Belt and suspenders: make the AppKit request a redraw - when it gets control again. */ - [view setNeedsDisplay:YES]; } - } else { - dmgRgn = HIShapeCreateEmpty(); - TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); } - if (dmgRgn) { - CFRelease(dmgRgn); + if ( dmgRgn == NULL ) { + dmgRgn = HIShapeCreateEmpty(); } + TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); + result = HIShapeIsEmpty(dmgRgn) ? 0 : 1; + CFRelease(dmgRgn); return result; } @@ -1901,7 +1855,6 @@ TkpClipDrawableToRect( CFRelease(macDraw->drawRgn); macDraw->drawRgn = NULL; } - if (width >= 0 && height >= 0) { CGRect clipRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff, width, height); @@ -2049,7 +2002,7 @@ TkpDrawHighlightBorder ( * TkpDrawFrame -- * * This procedure draws the rectangular frame area. If the user - * has requested themeing, it draws with the background theme. + * has request themeing, it draws with a the background theme. * * Results: * None. @@ -2079,7 +2032,6 @@ TkpDrawFrame( border = themedBorder; } } - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, highlightWidth, highlightWidth, Tk_Width(tkwin) - 2 * highlightWidth, diff --git a/macosx/tkMacOSXInt.h b/macosx/tkMacOSXInt.h index 6971e26..249d5cf 100644 --- a/macosx/tkMacOSXInt.h +++ b/macosx/tkMacOSXInt.h @@ -86,7 +86,7 @@ typedef struct TkWindowPrivate MacDrawable; #define TK_FOCUSED_VIEW 0x10 #define TK_IS_PIXMAP 0x20 #define TK_IS_BW_PIXMAP 0x40 -#define TK_DO_NOT_DRAW 0x80 + /* * I am reserving TK_EMBEDDED = 0x100 in the MacDrawable flags * This is defined in tk.h. We need to duplicate the TK_EMBEDDED flag in the diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index 4d4949f..bdb76af 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -26,7 +26,6 @@ #define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum)) #endif /* __LP64__ */ -#define MOUNTAIN_LION_STYLE (NSAppKitVersionNumber < 1138) /* * Declaration of Mac specific scrollbar structure. @@ -81,6 +80,7 @@ static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr); static int ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr); static void UpdateControlValues(TkScrollbar *scrollPtr); + /* *---------------------------------------------------------------------- * @@ -137,6 +137,7 @@ TkpDisplayScrollbar( register TkScrollbar *scrollPtr = (TkScrollbar *) clientData; register Tk_Window tkwin = scrollPtr->tkwin; + if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } @@ -149,6 +150,7 @@ TkpDisplayScrollbar( CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, .ty = viewHeight}; + scrollPtr->flags &= ~REDRAW_PENDING; if (!scrollPtr->tkwin || !Tk_IsMapped(tkwin) || !view || !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { @@ -171,6 +173,7 @@ TkpDisplayScrollbar( (Pixmap) macWin); } + Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, scrollPtr->highlightWidth, scrollPtr->highlightWidth, Tk_Width(tkwin) - 2*scrollPtr->highlightWidth, @@ -183,11 +186,15 @@ TkpDisplayScrollbar( /*Update values and draw in native rect.*/ UpdateControlValues(scrollPtr); - if (MOUNTAIN_LION_STYLE) { - HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationInverted); - } else { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 + if (scrollPtr->vertical) { HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); + } else { + HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationInverted); } +#else + HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); +#endif TkMacOSXRestoreDrawingContext(&dc); scrollPtr->flags &= ~REDRAW_PENDING; @@ -258,12 +265,11 @@ TkpComputeScrollbarGeometry( if (scrollPtr->sliderLast > fieldLength) { scrollPtr->sliderLast = fieldLength; } - if (!(MOUNTAIN_LION_STYLE)) { - scrollPtr->sliderFirst += scrollPtr->inset + + scrollPtr->sliderFirst += scrollPtr->inset + metrics[variant].topArrowHeight; - scrollPtr->sliderLast += scrollPtr->inset + + scrollPtr->sliderLast += scrollPtr->inset + metrics[variant].bottomArrowHeight; - } + /* * Register the desired geometry for the window (leave enough space * for the two arrows plus a minimum-size slider, plus border around @@ -364,29 +370,21 @@ TkpScrollbarPosition( int x, int y) /* Coordinates within scrollPtr's window. */ { - /* - * Using code from tkUnixScrlbr.c because Unix scroll bindings are - * driving the display at the script level. All the Mac scrollbar - * has to do is re-draw itself. - */ + /*Using code from tkUnixScrlbr.c because Unix scroll bindings are driving the display at the script level. All the Mac scrollbar has to do is re-draw itself.*/ - int length, fieldlength, width, tmp; + int length, width, tmp; register const int inset = scrollPtr->inset; - register const int arrowSize = scrollPtr->arrowLength + inset; if (scrollPtr->vertical) { length = Tk_Height(scrollPtr->tkwin); - fieldlength = length - 2 * arrowSize; width = Tk_Width(scrollPtr->tkwin); } else { tmp = x; x = y; y = tmp; length = Tk_Width(scrollPtr->tkwin); - fieldlength = length - 2 * arrowSize; width = Tk_Height(scrollPtr->tkwin); } - fieldlength = fieldlength < 0 ? 0 : fieldlength; if (x=width-inset || y=length-inset) { return OUTSIDE; @@ -397,19 +395,19 @@ TkpScrollbarPosition( * TkpDisplayScrollbar. Be sure to keep the two consistent. */ + if (y < inset + scrollPtr->arrowLength) { + return TOP_ARROW; + } if (y < scrollPtr->sliderFirst) { return TOP_GAP; } if (y < scrollPtr->sliderLast) { return SLIDER; } - if (y < fieldlength){ - return BOTTOM_GAP; - } - if (y < fieldlength + arrowSize) { - return TOP_ARROW; + if (y >= length - (scrollPtr->arrowLength + inset)) { + return BOTTOM_ARROW; } - return BOTTOM_ARROW; + return BOTTOM_GAP; } /* @@ -417,11 +415,9 @@ TkpScrollbarPosition( * * UpdateControlValues -- * - * This procedure updates the Macintosh scrollbar control to - * display the values defined by the Tk scrollbar. This is the - * key interface to the Mac-native * scrollbar; the Unix bindings - * drive scrolling in the Tk window and all the Mac scrollbar has - * to do is redraw itself. + * This procedure updates the Macintosh scrollbar control to display the + * values defined by the Tk scrollbar. This is the key interface to the Mac-native * scrollbar; the Unix bindings drive scrolling in the Tk window and all the Mac + * scrollbar has to do is redraw itself. * * Results: * None. @@ -436,6 +432,7 @@ static void UpdateControlValues( TkScrollbar *scrollPtr) /* Scrollbar data struct. */ { + Tk_Window tkwin = scrollPtr->tkwin; MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin); double dViewSize; @@ -487,11 +484,7 @@ UpdateControlValues( factor - dViewSize; info.trackInfo.scrollbar.viewsize = dViewSize; if (scrollPtr->vertical) { - if (MOUNTAIN_LION_STYLE) { - info.value = factor * scrollPtr->firstFraction; - } else { info.value = info.max - factor * scrollPtr->firstFraction; - } } else { info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction; } diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 2a88422..869f717 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -657,65 +657,6 @@ XConfigureWindow( /* *---------------------------------------------------------------------- * - * TkMacOSXSetDrawingEnabled -- - * - * This function sets the TK_DO_NOT_DRAW flag for a given window and - * all of its children. - * - * Results: - * None. - * - * Side effects: - * The clipping regions for the window and its children are cleared. - * - *---------------------------------------------------------------------- - */ - -void -TkMacOSXSetDrawingEnabled( - TkWindow *winPtr, - int flag) -{ - TkWindow *childPtr; - MacDrawable *macWin = winPtr->privatePtr; - - if (macWin) { - if (flag ) { - macWin->flags &= ~TK_DO_NOT_DRAW; - } else { - macWin->flags |= TK_DO_NOT_DRAW; - } - } - - /* - * Set the flag for all children & their descendants, excluding - * Toplevels. (??? Do we need to exclude Toplevels?) - */ - - childPtr = winPtr->childList; - while (childPtr) { - if (!Tk_IsTopLevel(childPtr)) { - TkMacOSXSetDrawingEnabled(childPtr, flag); - } - childPtr = childPtr->nextPtr; - } - - /* - * If the window is a container, set the flag for its embedded window. - */ - - if (Tk_IsContainer(winPtr)) { - childPtr = TkpGetOtherWindow(winPtr); - - if (childPtr) { - TkMacOSXSetDrawingEnabled(childPtr, flag); - } - } -} - -/* - *---------------------------------------------------------------------- - * * TkMacOSXUpdateClipRgn -- * * This function updates the clipping regions for a given window and all of diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 35f9f1c..2e7c041 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -29,7 +29,7 @@ * Declaration of functions used only in this file */ -static int GenerateUpdates(HIShapeRef updateRgn, +static int GenerateUpdates(HIMutableShapeRef updateRgn, CGRect *updateBounds, TkWindow *winPtr); static int GenerateActivateEvents(TkWindow *winPtr, int activeFlag); @@ -315,7 +315,7 @@ extern BOOL opaqueTag; static int GenerateUpdates( - HIShapeRef updateRgn, + HIMutableShapeRef updateRgn, CGRect *updateBounds, TkWindow *winPtr) { @@ -782,8 +782,7 @@ Tk_MacOSXIsAppInFront(void) @interface TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect; -- (void) generateExposeEvents: (HIShapeRef) shape; -- (void) generateExposeEvents: (HIShapeRef) shape childrenOnly: (int) childrenOnly; +- (void) generateExposeEvents: (HIMutableShapeRef) shape; - (void) viewDidEndLiveResize; - (void) tkToolbarButton: (id) sender; - (BOOL) isOpaque; @@ -793,8 +792,6 @@ Tk_MacOSXIsAppInFront(void) @end @implementation TKContentView -NSDate *_resizeStart; -NSTimeInterval _resizeDuration; @end /*Restrict event processing to Expose events.*/ @@ -832,7 +829,7 @@ ExposeRestrictProc( HIShapeUnionWithRect(drawShape, &r); } if (CFRunLoopGetMain() == CFRunLoopGetCurrent()) { - [self generateExposeEvents:(HIShapeRef)drawShape]; + [self generateExposeEvents:drawShape]; } else { [self performSelectorOnMainThread:@selector(generateExposeEvents:) withObject:(id)drawShape waitUntilDone:NO @@ -847,33 +844,25 @@ ExposeRestrictProc( -(void) setFrameSize: (NSSize)newsize { if ( [self inLiveResize] ) { - NSWindow *w = [self window]; - TkWindow *winPtr = TkMacOSXGetTkWindow(w); + NSWindow *window = [self window]; + TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); Tk_Window tkwin = (Tk_Window) winPtr; unsigned int width = (unsigned int)newsize.width; unsigned int height=(unsigned int)newsize.height; - /* Resize the NSView */ + /* Resize the Tk Window to the requested size.*/ + TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height, + TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY); + + /* Then resize the NSView to the actual window size*/ + newsize.width = (CGFloat)Tk_Width(tkwin); + newsize.height = (CGFloat)Tk_Height(tkwin); [super setFrameSize: newsize]; - /* Disable drawing until the window has been completely configured.*/ - TkMacOSXSetDrawingEnabled(winPtr, 0); + /* Process all pending events to update the window. */ + while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} - /* Generate and handle a ConfigureNotify event for the new size.*/ - TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height, - TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY); - while ( Tk_DoOneEvent(TK_X_EVENTS|TK_DONT_WAIT) ) {} - - /* Now that Tk has configured all subwindows we can create the clip regions. */ - TkMacOSXSetDrawingEnabled(winPtr, 1); - TkMacOSXInvalClipRgns(tkwin); - TkMacOSXUpdateClipRgn(winPtr); - - /* Finally, generate and process expose events to redraw the window. */ - HIRect bounds = NSRectToCGRect([self bounds]); - HIShapeRef shape = HIShapeCreateWithRect(&bounds); - [self generateExposeEvents: shape]; - while ( Tk_DoOneEvent(TK_ALL_EVENTS|TK_DONT_WAIT) ) {} } else { [super setFrameSize: newsize]; } @@ -892,44 +881,46 @@ ExposeRestrictProc( [self generateExposeEvents: shape]; } -/* Core method of this class: generates expose events for redrawing. - * Whereas drawRect is intended to be called only from the Appkit event - * loop, this can be called from Tk. If the Tcl_ServiceMode is set to - * TCL_SERVICE_ALL then the expose events will be immediately removed - * from the Tcl event loop and processed. Typically, they should be queued, - * however. - */ -- (void) generateExposeEvents: (HIShapeRef) shape -{ - [self generateExposeEvents:shape childrenOnly:0]; -} - -- (void) generateExposeEvents: (HIShapeRef) shape - childrenOnly: (int) childrenOnly +/*Core function of this class, generates expose events for redrawing.*/ +- (void) generateExposeEvents: (HIMutableShapeRef) shape { TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); unsigned long serial; CGRect updateBounds; - int updatesNeeded; if (!winPtr) { return; } - /* Generate Tk Expose events. */ HIShapeGetBounds(shape, &updateBounds); - /* All of these events will share the same serial number. */ serial = LastKnownRequestProcessed(Tk_Display(winPtr)); - updatesNeeded = GenerateUpdates(shape, &updateBounds, winPtr); - - /* Process the Expose events if the service mode is TCL_SERVICE_ALL */ - if (updatesNeeded && Tcl_GetServiceMode() == TCL_SERVICE_ALL) { - ClientData oldArg; + if (GenerateUpdates(shape, &updateBounds, winPtr) && + ![[NSRunLoop currentRunLoop] currentMode] && + Tcl_GetServiceMode() != TCL_SERVICE_NONE) { + /* + * Ensure there are no pending idle-time redraws that could + * prevent the just posted Expose events from generating + * new redraws. + */ + + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} + + /* + * For smoother drawing, process Expose events and resulting + * redraws immediately instead of at idle time. + */ + + ClientData oldArg; Tk_RestrictProc *oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg); + while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} + Tk_RestrictEvents(oldProc, oldArg, &oldArg); + + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} } + } /* @@ -945,6 +936,7 @@ ExposeRestrictProc( int x, y; TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); Tk_Window tkwin = (Tk_Window) winPtr; + bzero(&event, sizeof(XVirtualEvent)); event.type = VirtualEvent; event.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); -- cgit v0.12 From 69e749839382af95c02bdb100c49402eb6b926ae Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 9 Apr 2015 02:00:49 +0000 Subject: Re-working of internal Cocoa widget drawing routines, especially when resizing; fix rendering of scrollbar when resized or clipped; cleanup of button metrics; thanks to Marc Culler for extensive patches --- generic/tkCanvas.c | 13 ++++++ generic/tkInt.decls | 3 ++ generic/tkIntPlatDecls.h | 5 ++- generic/tkTextDisp.c | 28 +++++------- macosx/tkMacOSXButton.c | 21 +++++---- macosx/tkMacOSXDraw.c | 86 ++++++++++++++++++++++++++++-------- macosx/tkMacOSXInt.h | 2 +- macosx/tkMacOSXMouseEvent.c | 6 --- macosx/tkMacOSXNotify.c | 27 ++++++++---- macosx/tkMacOSXScrlbr.c | 84 +++++++++++++++++++---------------- macosx/tkMacOSXSubwindows.c | 59 +++++++++++++++++++++++++ macosx/tkMacOSXWindowEvent.c | 101 ++++++++++++++++++++++++++----------------- 12 files changed, 297 insertions(+), 138 deletions(-) diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 8e14852..9c4d60a 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -2447,6 +2447,19 @@ DisplayCanvas( goto done; } +#ifdef MAC_OSX_TK + /* + * If drawing is disabled, all we need to do is + * clear the REDRAW_PENDING flag. + */ + TkWindow *winPtr = (TkWindow *)(canvasPtr->tkwin); + MacDrawable *macWin = winPtr->privatePtr; + if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ + canvasPtr->flags &= ~REDRAW_PENDING; + return; + } +#endif + /* * Choose a new current item if that is needed (this could cause event * handlers to be invoked). diff --git a/generic/tkInt.decls b/generic/tkInt.decls index ebbadba..8924d68 100644 --- a/generic/tkInt.decls +++ b/generic/tkInt.decls @@ -1017,6 +1017,9 @@ declare 50 aqua { declare 51 aqua { void TkGenWMDestroyEvent(Tk_Window tkwin) } +declare 52 aqua { + TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag); +} # removed duplicate from tkPlat table (tk.decls) #declare 52 aqua { diff --git a/generic/tkIntPlatDecls.h b/generic/tkIntPlatDecls.h index 3a2a8aa..3a4bdac 100644 --- a/generic/tkIntPlatDecls.h +++ b/generic/tkIntPlatDecls.h @@ -250,7 +250,8 @@ EXTERN int TkGenerateButtonEvent(int x, int y, Window window, unsigned int state); /* 51 */ EXTERN void TkGenWMDestroyEvent(Tk_Window tkwin); -/* Slot 52 is reserved */ +/* 52 */ +EXTERN void TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag); /* 53 */ EXTERN unsigned long TkpGetMS(void); /* 54 */ @@ -395,7 +396,7 @@ typedef struct TkIntPlatStubs { Window (*tkGetTransientMaster) (TkWindow *winPtr); /* 49 */ int (*tkGenerateButtonEvent) (int x, int y, Window window, unsigned int state); /* 50 */ void (*tkGenWMDestroyEvent) (Tk_Window tkwin); /* 51 */ - void (*reserved52)(void); + void (*tkMacOSXSetDrawingEnabled) (TkWindow *winPtr, int flag); /* 52 */ unsigned long (*tkpGetMS) (void); /* 53 */ void * (*tkMacOSXDrawable) (Drawable drawable); /* 54 */ int (*tkpScanWindowId) (Tcl_Interp *interp, const char *string, Window *idPtr); /* 55 */ diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 95ea935..a95bb91 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -3948,6 +3948,18 @@ DisplayText( * warnings. */ Tcl_Interp *interp; +#ifdef MAC_OSX_TK + /* + * If drawing is disabled, all we need to do is + * clear the REDRAW_PENDING flag. + */ + TkWindow *winPtr = (TkWindow *)(textPtr->tkwin); + MacDrawable *macWin = winPtr->privatePtr; + if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ + dInfoPtr->flags &= ~REDRAW_PENDING; + return; + } +#endif if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { /* @@ -3964,14 +3976,6 @@ DisplayText( Tcl_SetVar2(interp, "tk_textRelayout", NULL, "", TCL_GLOBAL_ONLY); } - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - if (!Tk_IsMapped(textPtr->tkwin) || (dInfoPtr->maxX <= dInfoPtr->x) || (dInfoPtr->maxY <= dInfoPtr->y)) { UpdateDisplayInfo(textPtr); @@ -3983,14 +3987,6 @@ DisplayText( Tcl_SetVar2(interp, "tk_textRedraw", NULL, "", TCL_GLOBAL_ONLY); } - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - /* * Choose a new current item if that is needed (this could cause event * handlers to be invoked, hence the preserve/release calls and the loop, diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 725c211..59d394e 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -30,10 +30,10 @@ * Default insets for controls */ -#define DEF_INSET_LEFT 2 -#define DEF_INSET_RIGHT 2 -#define DEF_INSET_TOP 2 -#define DEF_INSET_BOTTOM 4 +#define DEF_INSET_LEFT 12 +#define DEF_INSET_RIGHT 12 +#define DEF_INSET_TOP 1 +#define DEF_INSET_BOTTOM 1 /* * Some defines used to control what type of control is drawn. @@ -318,8 +318,8 @@ TkpComputeButtonGeometry( Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); - txtWidth = butPtr->textWidth; - txtHeight = butPtr->textHeight; + txtWidth = butPtr->textWidth + DEF_INSET_LEFT + DEF_INSET_RIGHT; + txtHeight = butPtr->textHeight + DEF_INSET_BOTTOM + DEF_INSET_TOP; charWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); Tk_GetFontMetrics(butPtr->tkfont, &fm); haveText = (txtWidth != 0 && txtHeight != 0); @@ -647,7 +647,7 @@ DrawButtonImageAndText( butPtr->textHeight, &x, &y); x += butPtr->indicatorSpace; Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, - x, y, 0, -1); + x, y - DEF_INSET_BOTTOM, 0, -1); } /* @@ -807,9 +807,12 @@ TkMacOSXDrawButton( hiinfo.animation.time.start = hiinfo.animation.time.current; } - HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); + HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, + &contHIRec); + TkMacOSXRestoreDrawingContext(&dc); - ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, (MacButton *)mbPtr, 32, true); + ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, + (MacButton *)mbPtr, 32, true); } else { if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 328f905..0f6d2f0 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -222,7 +222,8 @@ XCopyArea( } if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { - TkMacOSXDbgMsg("Failed to setup drawing context."); + return; + /*TkMacOSXDbgMsg("Failed to setup drawing context.");*/ } if ( dc.context ) { @@ -243,6 +244,8 @@ XCopyArea( CGRectMake(src_x, src_y, width, height), CGRectMake(dest_x, dest_y, width, height)); CFRelease(img); + + } else { TkMacOSXDbgMsg("Failed to construct CGImage."); } @@ -652,9 +655,9 @@ GetCGContextForDrawable( CGColorSpaceRef colorspace = NULL; CGBitmapInfo bitmapInfo = #ifdef __LITTLE_ENDIAN__ - kCGBitmapByteOrder32Host; + kCGBitmapByteOrder32Host; #else - kCGBitmapByteOrderDefault; + kCGBitmapByteOrderDefault; #endif char *data; CGRect bounds = CGRectMake(0, 0, macDraw->size.width, @@ -731,6 +734,7 @@ DrawCGImage( } } dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff); + if (CGImageIsMask(image)) { /*CGContextSaveGState(context);*/ if (macDraw->flags & TK_IS_BW_PIXMAP) { @@ -765,8 +769,8 @@ DrawCGImage( dstBounds.size.width, dstBounds.size.height); #else /* TK_MAC_DEBUG_IMAGE_DRAWING */ CGContextSaveGState(context); - CGContextTranslateCTM(context, - 0, dstBounds.origin.y + CGRectGetMaxY(dstBounds)); + CGContextTranslateCTM(context, 0, + dstBounds.origin.y + CGRectGetMaxY(dstBounds)); CGContextScaleCTM(context, 1, -1); CGContextDrawImage(context, dstBounds, image); CGContextRestoreGState(context); @@ -1478,10 +1482,9 @@ TkScrollWindow( MacDrawable *macDraw = (MacDrawable *) drawable; NSView *view = TkMacOSXDrawableView(macDraw); CGRect srcRect, dstRect; - HIShapeRef dmgRgn = NULL, extraRgn; + HIShapeRef dmgRgn = NULL, extraRgn = NULL; NSRect bounds, visRect, scrollSrc, scrollDst; - int result; - + int result = 0; if ( view ) { /* Get the scroll area in NSView coordinates (origin at bottom left). */ @@ -1491,36 +1494,79 @@ TkScrollWindow( bounds.size.height - height - (macDraw->yOff + y), width, height); scrollDst = NSOffsetRect(scrollSrc, dx, -dy); + /* Limit scrolling to the window content area. */ visRect = [view visibleRect]; scrollSrc = NSIntersectionRect(scrollSrc, visRect); scrollDst = NSIntersectionRect(scrollDst, visRect); - if ( !NSIsEmptyRect(scrollSrc) && !NSIsEmptyRect(scrollDst) ) { /* * Mark the difference between source and destination as damaged. - * This region is described in the Tk coordinate system. + * This region is described in NSView coordinates (y=0 at the bottom) + * and converted to Tk coordinates later. */ - srcRect = CGRectMake(x, y, width, height); - dstRect = CGRectOffset(srcRect, dx, dy); + srcRect = CGRectMake(x, y, width, height); + dstRect = CGRectOffset(srcRect, dx, dy); + + /* Expand the rectangles slightly to avoid degeneracies. */ + srcRect.origin.y -= 1; + srcRect.size.height += 2; + dstRect.origin.y += 1; + dstRect.size.height -= 2; + + /* Compute the damage. */ dmgRgn = HIShapeCreateMutableWithRect(&srcRect); extraRgn = HIShapeCreateWithRect(&dstRect); ChkErr(HIShapeDifference, dmgRgn, extraRgn, (HIMutableShapeRef) dmgRgn); - CFRelease(extraRgn); + result = HIShapeIsEmpty(dmgRgn) ? 0 : 1; + + /* Convert to Tk coordinates. */ + TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); + if (extraRgn) { + CFRelease(extraRgn); + } /* Scroll the rectangle. */ [view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)]; + + /* Shift the Tk children which meet the source rectangle. */ + TkWindow *winPtr = (TkWindow *)tkwin; + TkWindow *childPtr; + CGRect childBounds; + for (childPtr = winPtr->childList; childPtr != NULL; childPtr = childPtr->nextPtr) { + if (Tk_IsMapped(childPtr) && !Tk_IsTopLevel(childPtr)) { + TkMacOSXWinCGBounds(childPtr, &childBounds); + if (CGRectIntersectsRect(srcRect, childBounds)) { + MacDrawable *macChild = childPtr->privatePtr; + if (macChild) { + macChild->yOff += dy; + macChild->xOff += dx; + childPtr->changes.y = macChild->yOff; + childPtr->changes.x = macChild->xOff; + } + } + } + } + + /* Queue up Expose events for the damage region. */ + int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); + [view generateExposeEvents:dmgRgn childrenOnly:1]; + Tcl_SetServiceMode(oldMode); + + /* Belt and suspenders: make the AppKit request a redraw + when it gets control again. */ + [view setNeedsDisplay:YES]; } + } else { + dmgRgn = HIShapeCreateEmpty(); + TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); } - if ( dmgRgn == NULL ) { - dmgRgn = HIShapeCreateEmpty(); + if (dmgRgn) { + CFRelease(dmgRgn); } - TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); - result = HIShapeIsEmpty(dmgRgn) ? 0 : 1; - CFRelease(dmgRgn); return result; } @@ -1855,6 +1901,7 @@ TkpClipDrawableToRect( CFRelease(macDraw->drawRgn); macDraw->drawRgn = NULL; } + if (width >= 0 && height >= 0) { CGRect clipRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff, width, height); @@ -2002,7 +2049,7 @@ TkpDrawHighlightBorder ( * TkpDrawFrame -- * * This procedure draws the rectangular frame area. If the user - * has request themeing, it draws with a the background theme. + * has requested themeing, it draws with the background theme. * * Results: * None. @@ -2032,6 +2079,7 @@ TkpDrawFrame( border = themedBorder; } } + Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, highlightWidth, highlightWidth, Tk_Width(tkwin) - 2 * highlightWidth, diff --git a/macosx/tkMacOSXInt.h b/macosx/tkMacOSXInt.h index 249d5cf..6971e26 100644 --- a/macosx/tkMacOSXInt.h +++ b/macosx/tkMacOSXInt.h @@ -86,7 +86,7 @@ typedef struct TkWindowPrivate MacDrawable; #define TK_FOCUSED_VIEW 0x10 #define TK_IS_PIXMAP 0x20 #define TK_IS_BW_PIXMAP 0x40 - +#define TK_DO_NOT_DRAW 0x80 /* * I am reserving TK_EMBEDDED = 0x100 in the MacDrawable flags * This is defined in tk.h. We need to duplicate the TK_EMBEDDED flag in the diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 95f0021..8c0a2e6 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -104,12 +104,6 @@ enum { return theEvent; /* Give up. No window for this event. */ } - /* - MacDrawable *macWin = (MacDrawable *) window; - NSView *view = TkMacOSXDrawableView(macWin); - local = [view convertPoint:local fromView:nil]; - local.y = NSHeight([view bounds]) - local.y; - */ TkWindow *winPtr = (TkWindow *) tkwin; local.x -= winPtr->wmInfoPtr->xInParent; local.y -= winPtr->wmInfoPtr->yInParent; diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 8b9745d..1d4c6c5 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -50,18 +50,18 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags); @end @implementation TKApplication(TKNotify) -/* Redisplay all of our windows, then call super. */ +/* Call super then redisplay all of our windows. */ - (NSEvent *) nextEventMatchingMask: (NSUInteger) mask untilDate: (NSDate *) expiration inMode: (NSString *) mode dequeue: (BOOL) deqFlag { - NSAutoreleasePool *pool = [NSAutoreleasePool new]; - [NSApp makeWindowsPerform:@selector(tkDisplayIfNeeded) inOrder:NO]; - [pool drain]; NSEvent *event = [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:deqFlag]; + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + [NSApp makeWindowsPerform:@selector(tkDisplayIfNeeded) inOrder:NO]; + [pool drain]; return event; } @@ -226,7 +226,7 @@ TkMacOSXEventsSetupProc( untilDate:[NSDate distantPast] inMode:GetRunLoopMode(TkMacOSXGetModalSession()) dequeue:NO]; - if (currentEvent) { + if (currentEvent && currentEvent.type > 0) { Tcl_SetMaxBlockTime(&zeroBlockTime); } } @@ -254,19 +254,30 @@ TkMacOSXEventsCheckProc( ClientData clientData, int flags) { - if (flags & TCL_WINDOW_EVENTS && - ![[NSRunLoop currentRunLoop] currentMode]) { + NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode]; + if (flags & TCL_WINDOW_EVENTS && !runloopMode) { + NSEvent *currentEvent = nil; + NSEvent *testEvent = nil; NSModalSession modalSession; do { modalSession = TkMacOSXGetModalSession(); + testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:GetRunLoopMode(modalSession) + dequeue:NO]; + /* We must not steal any events during LiveResize. */ + if (testEvent && [[testEvent window] inLiveResize]) { + break; + } + currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:GetRunLoopMode(modalSession) dequeue:YES]; if (!currentEvent) { - break; /* No more events. */ + break; /* No events are available. */ } NSAutoreleasePool *pool = [NSAutoreleasePool new]; /* Generate Xevents. */ diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index bdb76af..37178ed 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -26,6 +26,7 @@ #define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum)) #endif /* __LP64__ */ +#define MOUNTAIN_LION_STYLE (NSAppKitVersionNumber < 1138) /* * Declaration of Mac specific scrollbar structure. @@ -80,7 +81,6 @@ static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr); static int ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr); static void UpdateControlValues(TkScrollbar *scrollPtr); - /* *---------------------------------------------------------------------- * @@ -136,27 +136,26 @@ TkpDisplayScrollbar( { register TkScrollbar *scrollPtr = (TkScrollbar *) clientData; register Tk_Window tkwin = scrollPtr->tkwin; + TkWindow *winPtr = (TkWindow *) tkwin; + TkMacOSXDrawingContext dc; + scrollPtr->flags &= ~REDRAW_PENDING; - if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { + if (tkwin == NULL || !Tk_IsMapped(tkwin)) { return; } - TkWindow *winPtr = (TkWindow *) tkwin; MacDrawable *macWin = (MacDrawable *) winPtr->window; - TkMacOSXDrawingContext dc; NSView *view = TkMacOSXDrawableView(macWin); + if (!view || + macWin->flags & TK_DO_NOT_DRAW || + !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { + return; + } + CGFloat viewHeight = [view bounds].size.height; CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, .ty = viewHeight}; - - - scrollPtr->flags &= ~REDRAW_PENDING; - if (!scrollPtr->tkwin || !Tk_IsMapped(tkwin) || !view || - !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { - return; - } - CGContextConcatCTM(dc.context, t); /*Draw Unix-style scroll trough to provide rect for native scrollbar.*/ @@ -173,7 +172,6 @@ TkpDisplayScrollbar( (Pixmap) macWin); } - Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, scrollPtr->highlightWidth, scrollPtr->highlightWidth, Tk_Width(tkwin) - 2*scrollPtr->highlightWidth, @@ -186,15 +184,11 @@ TkpDisplayScrollbar( /*Update values and draw in native rect.*/ UpdateControlValues(scrollPtr); -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 - if (scrollPtr->vertical) { - HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); - } else { + if (MOUNTAIN_LION_STYLE) { HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationInverted); + } else { + HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); } -#else - HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); -#endif TkMacOSXRestoreDrawingContext(&dc); scrollPtr->flags &= ~REDRAW_PENDING; @@ -265,11 +259,12 @@ TkpComputeScrollbarGeometry( if (scrollPtr->sliderLast > fieldLength) { scrollPtr->sliderLast = fieldLength; } - scrollPtr->sliderFirst += scrollPtr->inset + + if (!(MOUNTAIN_LION_STYLE)) { + scrollPtr->sliderFirst += scrollPtr->inset + metrics[variant].topArrowHeight; - scrollPtr->sliderLast += scrollPtr->inset + + scrollPtr->sliderLast += scrollPtr->inset + metrics[variant].bottomArrowHeight; - + } /* * Register the desired geometry for the window (leave enough space * for the two arrows plus a minimum-size slider, plus border around @@ -370,21 +365,29 @@ TkpScrollbarPosition( int x, int y) /* Coordinates within scrollPtr's window. */ { - /*Using code from tkUnixScrlbr.c because Unix scroll bindings are driving the display at the script level. All the Mac scrollbar has to do is re-draw itself.*/ + /* + * Using code from tkUnixScrlbr.c because Unix scroll bindings are + * driving the display at the script level. All the Mac scrollbar + * has to do is re-draw itself. + */ - int length, width, tmp; + int length, fieldlength, width, tmp; register const int inset = scrollPtr->inset; + register const int arrowSize = scrollPtr->arrowLength + inset; if (scrollPtr->vertical) { length = Tk_Height(scrollPtr->tkwin); + fieldlength = length - 2 * arrowSize; width = Tk_Width(scrollPtr->tkwin); } else { tmp = x; x = y; y = tmp; length = Tk_Width(scrollPtr->tkwin); + fieldlength = length - 2 * arrowSize; width = Tk_Height(scrollPtr->tkwin); } + fieldlength = fieldlength < 0 ? 0 : fieldlength; if (x=width-inset || y=length-inset) { return OUTSIDE; @@ -395,19 +398,19 @@ TkpScrollbarPosition( * TkpDisplayScrollbar. Be sure to keep the two consistent. */ - if (y < inset + scrollPtr->arrowLength) { - return TOP_ARROW; - } if (y < scrollPtr->sliderFirst) { return TOP_GAP; } if (y < scrollPtr->sliderLast) { return SLIDER; } - if (y >= length - (scrollPtr->arrowLength + inset)) { - return BOTTOM_ARROW; + if (y < fieldlength){ + return BOTTOM_GAP; + } + if (y < fieldlength + arrowSize) { + return TOP_ARROW; } - return BOTTOM_GAP; + return BOTTOM_ARROW; } /* @@ -415,9 +418,11 @@ TkpScrollbarPosition( * * UpdateControlValues -- * - * This procedure updates the Macintosh scrollbar control to display the - * values defined by the Tk scrollbar. This is the key interface to the Mac-native * scrollbar; the Unix bindings drive scrolling in the Tk window and all the Mac - * scrollbar has to do is redraw itself. + * This procedure updates the Macintosh scrollbar control to + * display the values defined by the Tk scrollbar. This is the + * key interface to the Mac-native * scrollbar; the Unix bindings + * drive scrolling in the Tk window and all the Mac scrollbar has + * to do is redraw itself. * * Results: * None. @@ -432,7 +437,6 @@ static void UpdateControlValues( TkScrollbar *scrollPtr) /* Scrollbar data struct. */ { - Tk_Window tkwin = scrollPtr->tkwin; MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin); double dViewSize; @@ -462,8 +466,10 @@ UpdateControlValues( */ info.bounds = contrlRect; - if (!scrollPtr->vertical) { - info.attributes |= kThemeTrackHorizontal; + if (scrollPtr->vertical) { + info.attributes &= ~kThemeTrackHorizontal; + } else { + info.attributes |= kThemeTrackHorizontal; } /* @@ -484,7 +490,11 @@ UpdateControlValues( factor - dViewSize; info.trackInfo.scrollbar.viewsize = dViewSize; if (scrollPtr->vertical) { + if (MOUNTAIN_LION_STYLE) { + info.value = factor * scrollPtr->firstFraction; + } else { info.value = info.max - factor * scrollPtr->firstFraction; + } } else { info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction; } diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 869f717..2a88422 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -657,6 +657,65 @@ XConfigureWindow( /* *---------------------------------------------------------------------- * + * TkMacOSXSetDrawingEnabled -- + * + * This function sets the TK_DO_NOT_DRAW flag for a given window and + * all of its children. + * + * Results: + * None. + * + * Side effects: + * The clipping regions for the window and its children are cleared. + * + *---------------------------------------------------------------------- + */ + +void +TkMacOSXSetDrawingEnabled( + TkWindow *winPtr, + int flag) +{ + TkWindow *childPtr; + MacDrawable *macWin = winPtr->privatePtr; + + if (macWin) { + if (flag ) { + macWin->flags &= ~TK_DO_NOT_DRAW; + } else { + macWin->flags |= TK_DO_NOT_DRAW; + } + } + + /* + * Set the flag for all children & their descendants, excluding + * Toplevels. (??? Do we need to exclude Toplevels?) + */ + + childPtr = winPtr->childList; + while (childPtr) { + if (!Tk_IsTopLevel(childPtr)) { + TkMacOSXSetDrawingEnabled(childPtr, flag); + } + childPtr = childPtr->nextPtr; + } + + /* + * If the window is a container, set the flag for its embedded window. + */ + + if (Tk_IsContainer(winPtr)) { + childPtr = TkpGetOtherWindow(winPtr); + + if (childPtr) { + TkMacOSXSetDrawingEnabled(childPtr, flag); + } + } +} + +/* + *---------------------------------------------------------------------- + * * TkMacOSXUpdateClipRgn -- * * This function updates the clipping regions for a given window and all of diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 2e7c041..15e86ca 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -29,7 +29,7 @@ * Declaration of functions used only in this file */ -static int GenerateUpdates(HIMutableShapeRef updateRgn, +static int GenerateUpdates(HIShapeRef updateRgn, CGRect *updateBounds, TkWindow *winPtr); static int GenerateActivateEvents(TkWindow *winPtr, int activeFlag); @@ -315,7 +315,7 @@ extern BOOL opaqueTag; static int GenerateUpdates( - HIMutableShapeRef updateRgn, + HIShapeRef updateRgn, CGRect *updateBounds, TkWindow *winPtr) { @@ -782,7 +782,8 @@ Tk_MacOSXIsAppInFront(void) @interface TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect; -- (void) generateExposeEvents: (HIMutableShapeRef) shape; +- (void) generateExposeEvents: (HIShapeRef) shape; +- (void) generateExposeEvents: (HIShapeRef) shape childrenOnly: (int) childrenOnly; - (void) viewDidEndLiveResize; - (void) tkToolbarButton: (id) sender; - (BOOL) isOpaque; @@ -804,6 +805,15 @@ ExposeRestrictProc( ? TK_PROCESS_EVENT : TK_DEFER_EVENT); } +/*Restrict event processing to ConfigureNotify events.*/ +static Tk_RestrictAction +ConfigureRestrictProc( + ClientData arg, + XEvent *eventPtr) +{ + return (eventPtr->type==ConfigureNotify ? TK_PROCESS_EVENT : TK_DEFER_EVENT); +} + @implementation TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect @@ -829,11 +839,12 @@ ExposeRestrictProc( HIShapeUnionWithRect(drawShape, &r); } if (CFRunLoopGetMain() == CFRunLoopGetCurrent()) { - [self generateExposeEvents:drawShape]; + [self generateExposeEvents:(HIShapeRef)drawShape]; } else { [self performSelectorOnMainThread:@selector(generateExposeEvents:) withObject:(id)drawShape waitUntilDone:NO modes:[NSArray arrayWithObjects:NSRunLoopCommonModes, + NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode, nil]]; } @@ -844,25 +855,37 @@ ExposeRestrictProc( -(void) setFrameSize: (NSSize)newsize { if ( [self inLiveResize] ) { - NSWindow *window = [self window]; - TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); + NSWindow *w = [self window]; + TkWindow *winPtr = TkMacOSXGetTkWindow(w); Tk_Window tkwin = (Tk_Window) winPtr; unsigned int width = (unsigned int)newsize.width; unsigned int height=(unsigned int)newsize.height; + ClientData oldArg; + Tk_RestrictProc *oldProc; + + /* Resize the NSView */ + [super setFrameSize: newsize]; - /* Resize the Tk Window to the requested size.*/ + /* Disable drawing until the window has been completely configured.*/ + TkMacOSXSetDrawingEnabled(winPtr, 0); + + /* Generate and handle a ConfigureNotify event for the new size.*/ TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height, TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY); + oldProc = Tk_RestrictEvents(ConfigureRestrictProc, NULL, &oldArg); + while ( Tk_DoOneEvent(TK_X_EVENTS|TK_DONT_WAIT) ) {} + Tk_RestrictEvents(oldProc, oldArg, &oldArg); - /* Then resize the NSView to the actual window size*/ - newsize.width = (CGFloat)Tk_Width(tkwin); - newsize.height = (CGFloat)Tk_Height(tkwin); - [super setFrameSize: newsize]; - - /* Process all pending events to update the window. */ - while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} + /* Now that Tk has configured all subwindows we can create the clip regions. */ + TkMacOSXSetDrawingEnabled(winPtr, 1); + TkMacOSXInvalClipRgns(tkwin); + TkMacOSXUpdateClipRgn(winPtr); + /* Finally, generate and process expose events to redraw the window. */ + HIRect bounds = NSRectToCGRect([self bounds]); + HIShapeRef shape = HIShapeCreateWithRect(&bounds); + [self generateExposeEvents: shape]; + while ( Tk_DoOneEvent(TK_ALL_EVENTS|TK_DONT_WAIT) ) {} } else { [super setFrameSize: newsize]; } @@ -878,49 +901,48 @@ ExposeRestrictProc( { HIRect bounds = NSRectToCGRect([self bounds]); HIShapeRef shape = HIShapeCreateWithRect(&bounds); + [super viewDidEndLiveResize]; [self generateExposeEvents: shape]; } -/*Core function of this class, generates expose events for redrawing.*/ -- (void) generateExposeEvents: (HIMutableShapeRef) shape +/* Core method of this class: generates expose events for redrawing. + * Whereas drawRect is intended to be called only from the Appkit event + * loop, this can be called from Tk. If the Tcl_ServiceMode is set to + * TCL_SERVICE_ALL then the expose events will be immediately removed + * from the Tcl event loop and processed. Typically, they should be queued, + * however. + */ +- (void) generateExposeEvents: (HIShapeRef) shape +{ + [self generateExposeEvents:shape childrenOnly:0]; +} + +- (void) generateExposeEvents: (HIShapeRef) shape + childrenOnly: (int) childrenOnly { TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); unsigned long serial; CGRect updateBounds; + int updatesNeeded; if (!winPtr) { return; } + /* Generate Tk Expose events. */ HIShapeGetBounds(shape, &updateBounds); + /* All of these events will share the same serial number. */ serial = LastKnownRequestProcessed(Tk_Display(winPtr)); - if (GenerateUpdates(shape, &updateBounds, winPtr) && - ![[NSRunLoop currentRunLoop] currentMode] && - Tcl_GetServiceMode() != TCL_SERVICE_NONE) { - /* - * Ensure there are no pending idle-time redraws that could - * prevent the just posted Expose events from generating - * new redraws. - */ - - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} - - /* - * For smoother drawing, process Expose events and resulting - * redraws immediately instead of at idle time. - */ - - ClientData oldArg; + updatesNeeded = GenerateUpdates(shape, &updateBounds, winPtr); + + /* Process the Expose events if the service mode is TCL_SERVICE_ALL */ + if (updatesNeeded && Tcl_GetServiceMode() == TCL_SERVICE_ALL) { + ClientData oldArg; Tk_RestrictProc *oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg); - while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} - Tk_RestrictEvents(oldProc, oldArg, &oldArg); - - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} } - } /* @@ -936,7 +958,6 @@ ExposeRestrictProc( int x, y; TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); Tk_Window tkwin = (Tk_Window) winPtr; - bzero(&event, sizeof(XVirtualEvent)); event.type = VirtualEvent; event.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); -- cgit v0.12 From bd5f98d30fa3fccd6ba5e1d106b1bfd55f1ede2e Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Thu, 9 Apr 2015 22:15:18 +0000 Subject: Small patch for menubtton demo on OS X; thanks to Marc Culler --- library/menu.tcl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/menu.tcl b/library/menu.tcl index d05740f..cd05207 100644 --- a/library/menu.tcl +++ b/library/menu.tcl @@ -313,6 +313,9 @@ proc ::tk::MbPost {w {x {}} {y {}}} { set x [expr {[winfo rootx $w] - [winfo reqwidth $menu]}] set y [expr {(2 * [winfo rooty $w] + [winfo height $w]) / 2}] set entry [MenuFindName $menu [$w cget -text]] + if {$entry eq ""} { + set entry 0 + } if {[$w cget -indicatoron]} { if {$entry == [$menu index last]} { incr y [expr {-([$menu yposition $entry] \ @@ -333,6 +336,9 @@ proc ::tk::MbPost {w {x {}} {y {}}} { set x [expr {[winfo rootx $w] + [winfo width $w]}] set y [expr {(2 * [winfo rooty $w] + [winfo height $w]) / 2}] set entry [MenuFindName $menu [$w cget -text]] + if {$entry eq ""} { + set entry 0 + } if {[$w cget -indicatoron]} { if {$entry == [$menu index last]} { incr y [expr {-([$menu yposition $entry] \ -- cgit v0.12 From 5f46d2f08eda1b81b09264e12b2fdf4a16342e2f Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 15 May 2015 12:03:25 +0000 Subject: Use assertion to prevent writing pixel lines beyond end of Photo image block. --- generic/tkImgPNG.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/generic/tkImgPNG.c b/generic/tkImgPNG.c index d6a706a..8146e33 100644 --- a/generic/tkImgPNG.c +++ b/generic/tkImgPNG.c @@ -10,6 +10,7 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ +#include "assert.h" #include "tkInt.h" #define PNG_INT32(a,b,c,d) \ @@ -1880,6 +1881,8 @@ DecodeLine( * Calculate offset into pixelPtr for the first pixel of the line. */ + assert(pngPtr->currentLine < pngPtr->block.height); + offset = pngPtr->currentLine * pngPtr->block.pitch; /* -- cgit v0.12 From a7faf9f8a33c55adb9081e5a27a31d2eae249638 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 15 May 2015 15:51:20 +0000 Subject: [dece631375] Prevent PNG Reader writing to memory beyond end of photo image block. --- generic/tkImgPNG.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/generic/tkImgPNG.c b/generic/tkImgPNG.c index 8146e33..9d0fb30 100644 --- a/generic/tkImgPNG.c +++ b/generic/tkImgPNG.c @@ -2092,7 +2092,8 @@ ReadIDAT( * Process IDAT contents until there is no more in this chunk. */ - while (chunkSz && !Tcl_ZlibStreamEof(pngPtr->stream)) { + while (chunkSz && !Tcl_ZlibStreamEof(pngPtr->stream) + && pngPtr->currentLine < pngPtr->block.height) { int len1, len2; /* @@ -2178,10 +2179,13 @@ ReadIDAT( /* * Try to read another line of pixels out of the buffer - * immediately. + * immediately, but don't allow write past end of block. */ - goto getNextLine; + if (pngPtr->currentLine < pngPtr->block.height) { + goto getNextLine; + } + } /* -- cgit v0.12 From 348a58fe272f747f88db363b397cc98e8980e8e7 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 15 May 2015 19:26:36 +0000 Subject: [dece63137] Correct problems with overflow computing memory block sizes. --- generic/tkImgPhoto.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c index 63e2fa8..73a06b7 100644 --- a/generic/tkImgPhoto.c +++ b/generic/tkImgPhoto.c @@ -2051,8 +2051,8 @@ static int ToggleComplexAlphaIfNeeded( PhotoMaster *mPtr) { - size_t len = MAX(mPtr->userWidth, mPtr->width) * - MAX(mPtr->userHeight, mPtr->height) * 4; + size_t len = (size_t)MAX(mPtr->userWidth, mPtr->width) * + (size_t)MAX(mPtr->userHeight, mPtr->height) * 4; unsigned char *c = mPtr->pix32; unsigned char *end = c + len; @@ -2257,14 +2257,14 @@ ImgPhotoSetSize( if ((masterPtr->pix32 != NULL) && ((width == masterPtr->width) || (width == validBox.width))) { if (validBox.y > 0) { - memset(newPix32, 0, (size_t) (validBox.y * pitch)); + memset(newPix32, 0, ((size_t) validBox.y * pitch)); } h = validBox.y + validBox.height; if (h < height) { - memset(newPix32 + h*pitch, 0, (size_t) ((height - h) * pitch)); + memset(newPix32 + h*pitch, 0, ((size_t) (height - h) * pitch)); } } else { - memset(newPix32, 0, (size_t) (height * pitch)); + memset(newPix32, 0, ((size_t)height * pitch)); } if (masterPtr->pix32 != NULL) { @@ -2281,7 +2281,7 @@ ImgPhotoSetSize( offset = validBox.y * pitch; memcpy(newPix32 + offset, masterPtr->pix32 + offset, - (size_t) (validBox.height * pitch)); + ((size_t)validBox.height * pitch)); } else if ((validBox.width > 0) && (validBox.height > 0)) { /* @@ -2292,7 +2292,7 @@ ImgPhotoSetSize( srcPtr = masterPtr->pix32 + (validBox.y * masterPtr->width + validBox.x) * 4; for (h = validBox.height; h > 0; h--) { - memcpy(destPtr, srcPtr, (size_t) (validBox.width * 4)); + memcpy(destPtr, srcPtr, ((size_t)validBox.width * 4)); destPtr += width * 4; srcPtr += masterPtr->width * 4; } @@ -2772,7 +2772,7 @@ Tk_PhotoPutBlock( && (blockPtr->pitch == pitch))) && (compRule == TK_PHOTO_COMPOSITE_SET)) { memmove(destLinePtr, blockPtr->pixelPtr + blockPtr->offset[0], - (size_t) (height * width * 4)); + ((size_t)height * width * 4)); /* * We know there's an alpha offset and we're setting the data, so skip @@ -2804,7 +2804,7 @@ Tk_PhotoPutBlock( && (blueOffset == 2) && (alphaOffset == 3) && (width <= blockPtr->width) && compRuleSet) { - memcpy(destLinePtr, srcLinePtr, (size_t) (width * 4)); + memcpy(destLinePtr, srcLinePtr, ((size_t)width * 4)); srcLinePtr += blockPtr->pitch; destLinePtr += pitch; continue; @@ -3454,7 +3454,7 @@ Tk_PhotoBlank( */ memset(masterPtr->pix32, 0, - (size_t) (masterPtr->width * masterPtr->height * 4)); + ((size_t)masterPtr->width * masterPtr->height * 4)); for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; instancePtr = instancePtr->nextPtr) { TkImgResetDither(instancePtr); -- cgit v0.12 From c4379d2c51d34a6cba21e73692660730930e73f7 Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 18 May 2015 18:21:41 +0000 Subject: [dece631375] Prevent overflows in photo image memory allocations. --- generic/tkImgPhoto.c | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c index 73a06b7..6e34fe4 100644 --- a/generic/tkImgPhoto.c +++ b/generic/tkImgPhoto.c @@ -886,6 +886,19 @@ ImgPhotoCmd( break; } dataWidth = listObjc; + /* + * Memory allocation overflow protection. + * May not be able to trigger/ demo / test this. + */ + + if (dataWidth > (UINT_MAX/3) / dataHeight) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "photo image dimensions exceed Tcl memory limits", -1)); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", + "OVERFLOW", NULL); + break; + } + pixelPtr = ckalloc(dataWidth * dataHeight * 3); block.pixelPtr = pixelPtr; } else if (listObjc != dataWidth) { @@ -2192,6 +2205,10 @@ ImgPhotoSetSize( height = masterPtr->userHeight; } + if (width > INT_MAX / 4) { + /* Pitch overflows int */ + return TCL_ERROR; + } pitch = width * 4; /* @@ -2201,11 +2218,12 @@ ImgPhotoSetSize( if ((width != masterPtr->width) || (height != masterPtr->height) || (masterPtr->pix32 == NULL)) { - /* - * Not a u-long, but should be one. - */ + unsigned newPixSize; - unsigned /*long*/ newPixSize = (unsigned /*long*/) (height * pitch); + if (pitch && height > UINT_MAX / pitch) { + return TCL_ERROR; + } + newPixSize = height * pitch; /* * Some mallocs() really hate allocating zero bytes. [Bug 619544] @@ -3699,6 +3717,10 @@ ImgGetPhoto( if ((greenOffset||blueOffset) && !(optPtr->options & OPT_GRAYSCALE)) { newPixelSize += 2; } + + if (blockPtr->height > (UINT_MAX/newPixelSize)/blockPtr->width) { + return NULL; + } data = attemptckalloc(newPixelSize*blockPtr->width*blockPtr->height); if (data == NULL) { return NULL; @@ -3835,32 +3857,32 @@ ImgStringWrite( Tk_PhotoImageBlock *blockPtr) { int greenOffset, blueOffset; - Tcl_DString data; + Tcl_Obj *data; + Tcl_Obj *line = Tcl_NewObj(); greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; - Tcl_DStringInit(&data); + data = Tcl_NewListObj(blockPtr->height, NULL); if ((blockPtr->width > 0) && (blockPtr->height > 0)) { - char *line = ckalloc((8 * blockPtr->width) + 2); int row, col; for (row=0; rowheight; row++) { unsigned char *pixelPtr = blockPtr->pixelPtr + blockPtr->offset[0] + row * blockPtr->pitch; - char *linePtr = line; for (col=0; colwidth; col++) { - sprintf(linePtr, " #%02x%02x%02x", *pixelPtr, + Tcl_AppendPrintfToObj(line, "%s#%02x%02x%02x", + col ? " " : "", *pixelPtr, pixelPtr[greenOffset], pixelPtr[blueOffset]); pixelPtr += blockPtr->pixelSize; - linePtr += 8; } - Tcl_DStringAppendElement(&data, line+1); + Tcl_ListObjAppendElement(NULL, data, line); + Tcl_SetObjLength(line, 0); } - ckfree(line); } - Tcl_DStringResult(interp, &data); + Tcl_DecrRefCount(line); + Tcl_SetObjResult(interp, data); return TCL_OK; } -- cgit v0.12 From 54196211723b6c139157a3ab50b176f8f1dcd094 Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 18 May 2015 18:44:45 +0000 Subject: Repair last commit. --- generic/tkImgPhoto.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c index 6e34fe4..0c783f1 100644 --- a/generic/tkImgPhoto.c +++ b/generic/tkImgPhoto.c @@ -3858,7 +3858,6 @@ ImgStringWrite( { int greenOffset, blueOffset; Tcl_Obj *data; - Tcl_Obj *line = Tcl_NewObj(); greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; @@ -3868,20 +3867,19 @@ ImgStringWrite( int row, col; for (row=0; rowheight; row++) { + Tcl_Obj *line = Tcl_NewListObj(blockPtr->width, NULL); unsigned char *pixelPtr = blockPtr->pixelPtr + blockPtr->offset[0] + row * blockPtr->pitch; for (col=0; colwidth; col++) { - Tcl_AppendPrintfToObj(line, "%s#%02x%02x%02x", - col ? " " : "", *pixelPtr, - pixelPtr[greenOffset], pixelPtr[blueOffset]); + Tcl_ListObjAppendElement(NULL, line, Tcl_ObjPrintf( + "%s#%02x%02x%02x", col ? " " : "", *pixelPtr, + pixelPtr[greenOffset], pixelPtr[blueOffset])); pixelPtr += blockPtr->pixelSize; } Tcl_ListObjAppendElement(NULL, data, line); - Tcl_SetObjLength(line, 0); } } - Tcl_DecrRefCount(line); Tcl_SetObjResult(interp, data); return TCL_OK; } -- cgit v0.12 From 511a4b5d5ef8ff90218dd3aa8c85478bd5f56a36 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 20 May 2015 02:41:26 +0000 Subject: Initialize memory to stop valgrind notices about conditionals dependent on reads from uninit memory. --- generic/tkImgGIF.c | 7 +++++++ generic/tkImgPhoto.c | 3 +++ 2 files changed, 10 insertions(+) diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c index 27de486..6273c69 100644 --- a/generic/tkImgGIF.c +++ b/generic/tkImgGIF.c @@ -410,6 +410,7 @@ FileReadGIF( * source and not a file. */ + memset(colorMap, 0, MAXCOLORMAPSIZE*4); memset(gifConfPtr, 0, sizeof(GIFImageConfig)); if (fileName == INLINE_DATA_BINARY || fileName == INLINE_DATA_BASE64) { gifConfPtr->fromData = fileName; @@ -592,6 +593,9 @@ FileReadGIF( if (trashBuffer == NULL) { nBytes = fileWidth * fileHeight * 3; trashBuffer = ckalloc(nBytes); + if (trashBuffer) { + memset(trashBuffer, 0, nBytes); + } } /* @@ -678,6 +682,9 @@ FileReadGIF( block.pitch = block.pixelSize * imageWidth; nBytes = block.pitch * imageHeight; block.pixelPtr = ckalloc(nBytes); + if (block.pixelPtr) { + memset(block.pixelPtr, 0, nBytes); + } if (ReadImage(gifConfPtr, interp, block.pixelPtr, chan, imageWidth, imageHeight, colorMap, srcX, srcY, BitSet(buf[8], INTERLACE), diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c index fcb6d2f..7fa894c 100644 --- a/generic/tkImgPhoto.c +++ b/generic/tkImgPhoto.c @@ -2075,6 +2075,9 @@ ToggleComplexAlphaIfNeeded( */ mPtr->flags &= ~COMPLEX_ALPHA; + if (c == NULL) { + return 0; + } c += 3; /* Start at first alpha byte. */ for (; c < end; c += 4) { if (*c && *c != 255) { -- cgit v0.12 From 670cc8175d070b56068e54ebf6fd1b69eb31af7d Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 20 May 2015 12:34:32 +0000 Subject: [dece631375] More mem alloc overflow check and init with proper unsigneds. --- generic/tkImgGIF.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c index 6273c69..fbfe621 100644 --- a/generic/tkImgGIF.c +++ b/generic/tkImgGIF.c @@ -393,7 +393,8 @@ FileReadGIF( * image being read. */ { int fileWidth, fileHeight, imageWidth, imageHeight; - int nBytes, index = 0, argc = 0, i, result = TCL_ERROR; + unsigned int nBytes; + int index = 0, argc = 0, i, result = TCL_ERROR; Tcl_Obj **objv; unsigned char buf[100]; unsigned char *trashBuffer = NULL; @@ -426,8 +427,9 @@ FileReadGIF( return TCL_ERROR; } for (i = 1; i < argc; i++) { + int optionIdx; if (Tcl_GetIndexFromObjStruct(interp, objv[i], optionStrings, - sizeof(char *), "option name", 0, &nBytes) != TCL_OK) { + sizeof(char *), "option name", 0, &optionIdx) != TCL_OK) { return TCL_ERROR; } if (i == (argc-1)) { @@ -591,6 +593,9 @@ FileReadGIF( */ if (trashBuffer == NULL) { + if (fileWidth > (UINT_MAX/3)/fileHeight) { + goto error; + } nBytes = fileWidth * fileHeight * 3; trashBuffer = ckalloc(nBytes); if (trashBuffer) { @@ -679,7 +684,13 @@ FileReadGIF( block.offset[1] = 1; block.offset[2] = 2; block.offset[3] = (transparent>=0) ? 3 : 0; + if (imageWidth > INT_MAX/block.pixelSize) { + goto error; + } block.pitch = block.pixelSize * imageWidth; + if (imageHeight > UINT_MAX/block.pitch) { + goto error; + } nBytes = block.pitch * imageHeight; block.pixelPtr = ckalloc(nBytes); if (block.pixelPtr) { -- cgit v0.12 From b88c04907a34f7ca20777929634bcc40370d95ee Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 20 May 2015 15:17:10 +0000 Subject: [29044ba23f] Remove RANLIB as part of library installation. At best it's redundant to the RANLIB already done as part of library build. At worst, it conflicts with needs of cross-compiling. Thanks Erik Leunissen. --- unix/Makefile.in | 4 ---- unix/configure | 6 ++---- unix/tcl.m4 | 6 ++---- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/unix/Makefile.in b/unix/Makefile.in index 0736055..331722c 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -709,10 +709,6 @@ install-strip: INSTALL_PROGRAM="$(INSTALL_PROGRAM) ${INSTALL_STRIP_PROGRAM}" \ INSTALL_LIBRARY="$(INSTALL_LIBRARY) ${INSTALL_STRIP_LIBRARY}" -# Note: before running ranlib below, must cd to target directory because -# some ranlibs write to current directory, and this might not always be -# possible (e.g. if installing as root). - install-binaries: $(TK_STUB_LIB_FILE) $(TK_LIB_FILE) ${WISH_EXE} @for i in "$(LIB_INSTALL_DIR)" "$(BIN_INSTALL_DIR)" \ "$(PKG_INSTALL_DIR)" "$(CONFIG_INSTALL_DIR)" ; \ diff --git a/unix/configure b/unix/configure index c10a247..7934d9e 100755 --- a/unix/configure +++ b/unix/configure @@ -6695,15 +6695,14 @@ else if test "$RANLIB" = ""; then MAKE_LIB='$(STLIB_LD) $@ ${OBJS}' - INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)"' else MAKE_LIB='${STLIB_LD} $@ ${OBJS} ; ${RANLIB} $@' - INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)" ; (cd "$(LIB_INSTALL_DIR)" ; $(RANLIB) $(LIB_FILE))' fi + INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)"' fi @@ -6712,15 +6711,14 @@ fi if test "$RANLIB" = ""; then MAKE_STUB_LIB='${STLIB_LD} $@ ${STUB_LIB_OBJS}' - INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)"' else MAKE_STUB_LIB='${STLIB_LD} $@ ${STUB_LIB_OBJS} ; ${RANLIB} $@' - INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)" ; (cd "$(LIB_INSTALL_DIR)" ; $(RANLIB) $(STUB_LIB_FILE))' fi + INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)"' # Define TCL_LIBS now that we know what DL_LIBS is. # The trick here is that we don't want to change the value of TCL_LIBS if diff --git a/unix/tcl.m4 b/unix/tcl.m4 index 1a56932..a6cb41b 100644 --- a/unix/tcl.m4 +++ b/unix/tcl.m4 @@ -2060,21 +2060,19 @@ dnl # preprocessing tests use only CPPFLAGS. AS_IF([test "$RANLIB" = ""], [ MAKE_LIB='$(STLIB_LD) [$]@ ${OBJS}' - INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)"' ], [ MAKE_LIB='${STLIB_LD} [$]@ ${OBJS} ; ${RANLIB} [$]@' - INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)" ; (cd "$(LIB_INSTALL_DIR)" ; $(RANLIB) $(LIB_FILE))' ]) + INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)"' ]) # Stub lib does not depend on shared/static configuration AS_IF([test "$RANLIB" = ""], [ MAKE_STUB_LIB='${STLIB_LD} [$]@ ${STUB_LIB_OBJS}' - INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)"' ], [ MAKE_STUB_LIB='${STLIB_LD} [$]@ ${STUB_LIB_OBJS} ; ${RANLIB} [$]@' - INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)" ; (cd "$(LIB_INSTALL_DIR)" ; $(RANLIB) $(STUB_LIB_FILE))' ]) + INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)"' # Define TCL_LIBS now that we know what DL_LIBS is. # The trick here is that we don't want to change the value of TCL_LIBS if -- cgit v0.12 From 32058aca4beb9db6cdde22c184e509193a756267 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 25 May 2015 22:17:20 +0000 Subject: Fix [2a02881e4c23634022d0ae40a14383d9baad9eb9|2a02881e4c]: Colors added/changed in 8.6 not documented in man page --- doc/colors.n | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/colors.n b/doc/colors.n index ee44f7b..9081b27 100644 --- a/doc/colors.n +++ b/doc/colors.n @@ -29,6 +29,7 @@ AntiqueWhite1 255 239 219 AntiqueWhite2 238 223 204 AntiqueWhite3 205 192 176 AntiqueWhite4 139 131 120 +agua 0 255 255 aquamarine 127 255 212 aquamarine1 127 255 212 aquamarine2 118 238 198 @@ -93,6 +94,7 @@ cornsilk1 255 248 220 cornsilk2 238 232 205 cornsilk3 205 200 177 cornsilk4 139 136 120 +crymson 220 20 60 cyan 0 255 255 cyan1 0 255 255 cyan2 0 238 238 @@ -191,6 +193,7 @@ floral white 255 250 240 FloralWhite 255 250 240 forest green 34 139 34 ForestGreen 34 139 34 +fuchsia 255 0 255 gainsboro 220 220 220 ghost white 248 248 255 GhostWhite 248 248 255 @@ -204,7 +207,7 @@ goldenrod1 255 193 37 goldenrod2 238 180 34 goldenrod3 205 155 29 goldenrod4 139 105 20 -gray 190 190 190 +gray 128 128 128 gray0 0 0 0 gray1 3 3 3 gray2 5 5 5 @@ -306,14 +309,14 @@ gray97 247 247 247 gray98 250 250 250 gray99 252 252 252 gray100 255 255 255 -green 0 255 0 +green 0 128 0 green yellow 173 255 47 green1 0 255 0 green2 0 238 0 green3 0 205 0 green4 0 139 0 GreenYellow 173 255 47 -grey 190 190 190 +grey 128 128 128 grey0 0 0 0 grey1 3 3 3 grey2 5 5 5 @@ -432,6 +435,7 @@ IndianRed1 255 106 106 IndianRed2 238 99 99 IndianRed3 205 85 85 IndianRed4 139 58 58 +indigo 75 0 130 ivory 255 255 240 ivory1 255 255 240 ivory2 238 238 224 @@ -523,6 +527,7 @@ LightYellow1 255 255 224 LightYellow2 238 238 209 LightYellow3 205 205 180 LightYellow4 139 139 122 +lime 0 255 0 lime green 50 205 50 LimeGreen 50 205 50 linen 250 240 230 @@ -531,7 +536,7 @@ magenta1 255 0 255 magenta2 238 0 238 magenta3 205 0 205 magenta4 139 0 139 -maroon 176 48 96 +maroon 128 0 0 maroon1 255 52 179 maroon2 238 48 167 maroon3 205 41 144 @@ -584,6 +589,7 @@ navy blue 0 0 128 NavyBlue 0 0 128 old lace 253 245 230 OldLace 253 245 230 +olive 128 128 0 olive drab 107 142 35 OliveDrab 107 142 35 OliveDrab1 192 255 62 @@ -647,7 +653,7 @@ plum3 205 150 205 plum4 139 102 139 powder blue 176 224 230 PowderBlue 176 224 230 -purple 160 32 240 +purple 128 0 128 purple1 155 48 255 purple2 145 44 238 purple3 125 38 205 @@ -694,6 +700,7 @@ sienna1 255 130 71 sienna2 238 121 66 sienna3 205 104 57 sienna4 139 71 38 +silver 192 192 192 sky blue 135 206 235 SkyBlue 135 206 235 SkyBlue1 135 206 255 @@ -736,6 +743,7 @@ tan1 255 165 79 tan2 238 154 73 tan3 205 133 63 tan4 139 90 43 +teal 0 128 128 thistle 216 191 216 thistle1 255 225 255 thistle2 238 210 238 -- cgit v0.12 From 9cb6db3c5911d701d13fbe2bed6f21d7cabae4b0 Mon Sep 17 00:00:00 2001 From: fvogel Date: Mon, 1 Jun 2015 19:10:13 +0000 Subject: Test panedwindow-25.2 uses tcltest 2 format --- tests/panedwindow.test | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/panedwindow.test b/tests/panedwindow.test index 7c7e138..4bc59a8 100644 --- a/tests/panedwindow.test +++ b/tests/panedwindow.test @@ -5087,7 +5087,9 @@ test panedwindow-25.1 {DestroyPanedWindow} -setup { } set result {} } -result {} -test panedwindow-26.2 {UnmapNotify and MapNotify events are propagated to slaves} { +test panedwindow-25.2 {UnmapNotify and MapNotify events are propagated to slaves} -setup { + deleteWindows +} -body { panedwindow .pw .pw add [button .pw.b] pack .pw @@ -5103,7 +5105,9 @@ test panedwindow-26.2 {UnmapNotify and MapNotify events are propagated to slaves lappend result [winfo ismapped .pw.b] destroy .pw .pw.b set result -} {1 0 0 1 1} +} -cleanup { + deleteWindows +} -result {1 0 0 1 1} test panedwindow-26.1 {PanedWindowIdentifyCoords} -setup { -- cgit v0.12 From a585861ebc284c8467d46e834bbf9f5a177364a6 Mon Sep 17 00:00:00 2001 From: fvogel Date: Mon, 1 Jun 2015 20:19:20 +0000 Subject: Fixed broken trunk caused by "signed/unsigned mismatch" compiler error on Windows, introduced by [4fe3c06b97] and [07622d5618] --- generic/tkImgGIF.c | 4 ++-- generic/tkImgPhoto.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c index fbfe621..1c28b54 100644 --- a/generic/tkImgGIF.c +++ b/generic/tkImgGIF.c @@ -593,7 +593,7 @@ FileReadGIF( */ if (trashBuffer == NULL) { - if (fileWidth > (UINT_MAX/3)/fileHeight) { + if (fileWidth > (int)((UINT_MAX/3)/fileHeight)) { goto error; } nBytes = fileWidth * fileHeight * 3; @@ -688,7 +688,7 @@ FileReadGIF( goto error; } block.pitch = block.pixelSize * imageWidth; - if (imageHeight > UINT_MAX/block.pitch) { + if (imageHeight > (int)(UINT_MAX/block.pitch)) { goto error; } nBytes = block.pitch * imageHeight; diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c index 7fa894c..3e03f3d 100644 --- a/generic/tkImgPhoto.c +++ b/generic/tkImgPhoto.c @@ -891,7 +891,7 @@ ImgPhotoCmd( * May not be able to trigger/ demo / test this. */ - if (dataWidth > (UINT_MAX/3) / dataHeight) { + if (dataWidth > (int)((UINT_MAX/3) / dataHeight)) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "photo image dimensions exceed Tcl memory limits", -1)); Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", @@ -2223,7 +2223,7 @@ ImgPhotoSetSize( || (masterPtr->pix32 == NULL)) { unsigned newPixSize; - if (pitch && height > UINT_MAX / pitch) { + if (pitch && height > (int)(UINT_MAX / pitch)) { return TCL_ERROR; } newPixSize = height * pitch; @@ -3721,7 +3721,7 @@ ImgGetPhoto( newPixelSize += 2; } - if (blockPtr->height > (UINT_MAX/newPixelSize)/blockPtr->width) { + if (blockPtr->height > (int)((UINT_MAX/newPixelSize)/blockPtr->width)) { return NULL; } data = attemptckalloc(newPixelSize*blockPtr->width*blockPtr->height); -- cgit v0.12 From db72cf3cd352c43ddcb5abcb300f60aea2df558f Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 5 Jun 2015 04:01:10 +0000 Subject: Add missing bold effect to documentation for [canvas -splinesteps]. --- doc/canvas.n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/canvas.n b/doc/canvas.n index bc29cc3..ae139db 100644 --- a/doc/canvas.n +++ b/doc/canvas.n @@ -1573,7 +1573,7 @@ times) so that it also becomes a knot point. \fB\-splinesteps \fInumber\fR Specifies the degree of smoothness desired for curves: each spline will be approximated with \fInumber\fR line segments. This -option is ignored unless the \fB\-smooth\fR option is true or \fBraw\fR. +option is ignored unless the \fB\-smooth\fR option is \fBtrue\fR or \fBraw\fR. .SS "OVAL ITEMS" .PP Items of type \fBoval\fR appear as circular or oval regions on -- cgit v0.12 From 4a6942aa314339a94bb067b7cc073bad867f77a8 Mon Sep 17 00:00:00 2001 From: andy Date: Thu, 2 Jul 2015 20:21:10 +0000 Subject: Revert [b80a6942]. Realize now that "true" was not bold because the option does not have to literally be the exact string "true" but can also be any of the other acceptable true values, such as "yes" or "t". --- doc/canvas.n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/canvas.n b/doc/canvas.n index ae139db..bc29cc3 100644 --- a/doc/canvas.n +++ b/doc/canvas.n @@ -1573,7 +1573,7 @@ times) so that it also becomes a knot point. \fB\-splinesteps \fInumber\fR Specifies the degree of smoothness desired for curves: each spline will be approximated with \fInumber\fR line segments. This -option is ignored unless the \fB\-smooth\fR option is \fBtrue\fR or \fBraw\fR. +option is ignored unless the \fB\-smooth\fR option is true or \fBraw\fR. .SS "OVAL ITEMS" .PP Items of type \fBoval\fR appear as circular or oval regions on -- cgit v0.12 From 973b6e6d17b26ec027eb3b6df3b37d9da9d9f514 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 8 Jul 2015 07:54:08 +0000 Subject: Use size_t in stead of int for some internal refCount variables. On 32-bit systems, this doubles the range (as size_t is unsigned), on 64-bit system much more than that. --- macosx/tkMacOSXDraw.c | 2 +- macosx/tkMacOSXScrlbr.c | 2 +- win/tkWinColor.c | 14 ++++++++------ win/tkWinFont.c | 5 ++--- win/tkWinWm.c | 6 ++---- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 0f6d2f0..5f31a2c 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -769,7 +769,7 @@ DrawCGImage( dstBounds.size.width, dstBounds.size.height); #else /* TK_MAC_DEBUG_IMAGE_DRAWING */ CGContextSaveGState(context); - CGContextTranslateCTM(context, 0, + CGContextTranslateCTM(context, 0, dstBounds.origin.y + CGRectGetMaxY(dstBounds)); CGContextScaleCTM(context, 1, -1); CGContextDrawImage(context, dstBounds, image); diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index 37178ed..91cf112 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -384,7 +384,7 @@ TkpScrollbarPosition( x = y; y = tmp; length = Tk_Width(scrollPtr->tkwin); - fieldlength = length - 2 * arrowSize; + fieldlength = length - 2 * arrowSize; width = Tk_Height(scrollPtr->tkwin); } fieldlength = fieldlength < 0 ? 0 : fieldlength; diff --git a/win/tkWinColor.c b/win/tkWinColor.c index 5eaeeb3..ba9815c 100644 --- a/win/tkWinColor.c +++ b/win/tkWinColor.c @@ -316,7 +316,8 @@ XAllocColor( if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) { unsigned long sizePalette = GetDeviceCaps(dc, SIZEPALETTE); UINT newPixel, closePixel; - int new, refCount; + int new; + size_t refCount; Tcl_HashEntry *entryPtr; UINT index; @@ -361,9 +362,9 @@ XAllocColor( if (new) { refCount = 1; } else { - refCount = (PTR2INT(Tcl_GetHashValue(entryPtr))) + 1; + refCount = (size_t)Tcl_GetHashValue(entryPtr) + 1; } - Tcl_SetHashValue(entryPtr, INT2PTR(refCount)); + Tcl_SetHashValue(entryPtr, (void *)refCount); } else { /* * Determine what color will actually be used on non-colormap systems. @@ -407,7 +408,8 @@ XFreeColors( { TkWinColormap *cmap = (TkWinColormap *) colormap; COLORREF cref; - UINT count, index, refCount; + UINT count, index; + size_t refCount; int i; PALETTEENTRY entry, *entries; Tcl_HashEntry *entryPtr; @@ -427,7 +429,7 @@ XFreeColors( if (!entryPtr) { Tcl_Panic("Tried to free a color that isn't allocated"); } - refCount = PTR2INT(Tcl_GetHashValue(entryPtr)) - 1; + refCount = (size_t)Tcl_GetHashValue(entryPtr) - 1; if (refCount == 0) { cref = pixels[i] & 0x00ffffff; index = GetNearestPaletteIndex(cmap->palette, cref); @@ -444,7 +446,7 @@ XFreeColors( } Tcl_DeleteHashEntry(entryPtr); } else { - Tcl_SetHashValue(entryPtr, INT2PTR(refCount)); + Tcl_SetHashValue(entryPtr, (size_t)refCount); } } } diff --git a/win/tkWinFont.c b/win/tkWinFont.c index 86f63ac..9172b00 100644 --- a/win/tkWinFont.c +++ b/win/tkWinFont.c @@ -33,7 +33,7 @@ typedef struct FontFamily { struct FontFamily *nextPtr; /* Next in list of all known font families. */ - int refCount; /* How many SubFonts are referring to this + size_t refCount; /* How many SubFonts are referring to this * FontFamily. When the refCount drops to * zero, this FontFamily may be freed. */ /* @@ -1869,8 +1869,7 @@ FreeFontFamily( if (familyPtr == NULL) { return; } - familyPtr->refCount--; - if (familyPtr->refCount > 0) { + if (familyPtr->refCount-- > 1) { return; } for (i = 0; i < FONTMAP_PAGES; i++) { diff --git a/win/tkWinWm.c b/win/tkWinWm.c index 4d46fd5..768ee69 100644 --- a/win/tkWinWm.c +++ b/win/tkWinWm.c @@ -148,7 +148,7 @@ typedef struct { */ typedef struct WinIconInstance { - int refCount; /* Number of instances that share this data + size_t refCount; /* Number of instances that share this data * structure. */ BlockOfIconImagesPtr iconBlock; /* Pointer to icon resource data for image */ @@ -1421,9 +1421,7 @@ static void DecrIconRefCount( WinIconPtr titlebaricon) { - titlebaricon->refCount--; - - if (titlebaricon->refCount <= 0) { + if (titlebaricon->refCount-- <= 1) { if (titlebaricon->iconBlock != NULL) { FreeIconBlock(titlebaricon->iconBlock); } -- cgit v0.12 From 3525b8b01c138cbc30c498a9e0f9a587dab26e32 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 5 Aug 2015 20:33:00 +0000 Subject: Remove various unnecessary "global tcl_platform" occurrences, which are no longer used. Add "Fit To Screen Width" menu entry to Windows (and android) console menu. Ported from androwish. --- library/bgerror.tcl | 2 +- library/console.tcl | 34 ++++++++++++++++++++++++++++------ library/demos/aniwave.tcl | 2 +- library/demos/fontchoose.tcl | 2 +- library/demos/knightstour.tcl | 4 ++-- library/demos/menu.tcl | 2 +- library/demos/menubu.tcl | 2 +- library/demos/msgbox.tcl | 4 ++-- library/demos/puzzle.tcl | 2 +- library/dialog.tcl | 1 - library/entry.tcl | 1 - library/menu.tcl | 11 ++--------- library/msgbox.tcl | 2 +- library/spinbox.tcl | 1 - library/text.tcl | 2 -- library/tk.tcl | 1 - 16 files changed, 41 insertions(+), 32 deletions(-) diff --git a/library/bgerror.tcl b/library/bgerror.tcl index d1ed60a..b15387e 100644 --- a/library/bgerror.tcl +++ b/library/bgerror.tcl @@ -98,7 +98,7 @@ proc ::tk::dialog::error::ReturnInDetails w { # err - The error message. # proc ::tk::dialog::error::bgerror err { - global errorInfo tcl_platform + global errorInfo variable button set info $errorInfo diff --git a/library/console.tcl b/library/console.tcl index 566140f..ba68ccc 100644 --- a/library/console.tcl +++ b/library/console.tcl @@ -41,8 +41,6 @@ interp alias {} EvalAttached {} consoleinterp eval # None. proc ::tk::ConsoleInit {} { - global tcl_platform - if {![consoleinterp eval {set tcl_interactive}]} { wm withdraw . } @@ -78,7 +76,7 @@ proc ::tk::ConsoleInit {} { AmpMenuArgs .menubar.edit add command -label [mc P&aste] -accel "$mod+V"\ -command {event generate .console <>} - if {$tcl_platform(platform) ne "windows"} { + if {[tk windowingsystem] ne "win32"} { AmpMenuArgs .menubar.edit add command -label [mc Cl&ear] \ -command {event generate .console <>} } else { @@ -114,6 +112,8 @@ proc ::tk::ConsoleInit {} { -accel "$mod++" -command {event generate .console <>} AmpMenuArgs .menubar.edit add command -label [mc "&Decrease Font Size"] \ -accel "$mod+-" -command {event generate .console <>} + AmpMenuArgs .menubar.edit add command -label [mc "Fit To Screen Width"] \ + -command {event generate .console <>} if {[tk windowingsystem] eq "aqua"} { .menubar add cascade -label [mc Window] -menu [menu .menubar.window] @@ -193,7 +193,7 @@ proc ::tk::ConsoleInit {} { $w mark set promptEnd insert $w mark gravity promptEnd left - if {$tcl_platform(platform) eq "windows"} { + if {[tk windowingsystem] ne "aqua"} { # Subtle work-around to erase the '% ' that tclMain.c prints out after idle [subst -nocommand { if {[$con get 1.0 output] eq "% "} { $con delete 1.0 output } @@ -378,6 +378,26 @@ proc ::tk::console::Paste {w} { } } +# Fit TkConsoleFont to window width +proc ::tk::console::FitScreenWidth {w} { + set width [winfo screenwidth $w] + set cwidth [$w cget -width] + set s -50 + set fit 0 + array set fi [font configure TkConsoleFont] + while {$s < 0} { + set fi(-size) $s + set f [font create {*}[array get fi]] + set c [font measure $f "eM"] + font delete $f + if {$c * $cwidth < 1.667 * $width} { + font configure TkConsoleFont -size $s + break + } + incr s 2 + } +} + # ::tk::ConsoleBind -- # This procedure first ensures that the default bindings for the Text # class have been defined. Then certain bindings are overridden for @@ -600,6 +620,9 @@ proc ::tk::ConsoleBind {w} { tk fontchooser configure -font TkConsoleFont } } + bind Console <> { + ::tk::console::FitScreenWidth %W + } ## ## Bindings for doing special things based on certain keys @@ -987,8 +1010,7 @@ proc ::tk::console::ExpandPathname str { set match {} } else { if {[llength $m] > 1} { - global tcl_platform - if {[string match windows $tcl_platform(platform)]} { + if { $::tcl_platform(platform) eq "windows" } { ## Windows is screwy because it's case insensitive set tmp [ExpandBestMatch [string tolower $m] \ [string tolower $dir]] diff --git a/library/demos/aniwave.tcl b/library/demos/aniwave.tcl index 6122132..a7539fb 100644 --- a/library/demos/aniwave.tcl +++ b/library/demos/aniwave.tcl @@ -17,7 +17,7 @@ wm title $w "Animated Wave Demonstration" wm iconname $w "aniwave" positionWindow $w -label $w.msg -font $font -wraplength 4i -justify left -text "This demonstration contains a canvas widget with a line item inside it. The animation routines work by adjusting the coordinates list of the line; a trace on a variable is used so updates to the variable result in a change of position of the line." +label $w.msg -font $font -wraplength 4i -justify left -text "This demonstration contains a canvas widget with a line item inside it. The animation routines work by adjusting the coordinates list of the line; a trace on a variable is used so updates to the variable result in a change of position of the line." pack $w.msg -side top ## See Code / Dismiss buttons diff --git a/library/demos/fontchoose.tcl b/library/demos/fontchoose.tcl index def30c3..8b34377 100644 --- a/library/demos/fontchoose.tcl +++ b/library/demos/fontchoose.tcl @@ -57,7 +57,7 @@ grid columnconfigure $f 0 -weight 1 grid rowconfigure $f 0 -weight 1 bind $w { bind %W {} - grid propagate %W.f 0 + grid propagate %W.f 0 } ## See Code / Dismiss buttons diff --git a/library/demos/knightstour.tcl b/library/demos/knightstour.tcl index 73ca3a3..6113db2 100644 --- a/library/demos/knightstour.tcl +++ b/library/demos/knightstour.tcl @@ -221,7 +221,7 @@ proc CreateGUI {} { $c bind knight [namespace code [list DragStart %W %x %y]] $c bind knight [namespace code [list DragMotion %W %x %y]] $c bind knight [namespace code [list DragEnd %W %x %y]] - + grid $c $f.txt $f.vs -sticky news grid rowconfigure $f 0 -weight 1 grid columnconfigure $f 1 -weight 1 @@ -244,7 +244,7 @@ proc CreateGUI {} { if {[info exists ::widgetDemo]} { grid [addSeeDismiss $dlg.buttons $dlg] - - - - - -sticky ew } - + grid rowconfigure $dlg 0 -weight 1 grid columnconfigure $dlg 0 -weight 1 diff --git a/library/demos/menu.tcl b/library/demos/menu.tcl index e19df57..e32b54f 100644 --- a/library/demos/menu.tcl +++ b/library/demos/menu.tcl @@ -16,7 +16,7 @@ wm title $w "Menu Demonstration" wm iconname $w "menu" positionWindow $w -label $w.msg -font $font -wraplength 4i -justify left +label $w.msg -font $font -wraplength 4i -justify left if {[tk windowingsystem] eq "aqua"} { catch {set origUseCustomMDEF $::tk::mac::useCustomMDEF; set ::tk::mac::useCustomMDEF 1} $w.msg configure -text "This window has a menubar with cascaded menus. You can invoke entries with an accelerator by typing Command+x, where \"x\" is the character next to the command key symbol. The rightmost menu can be torn off into a palette by selecting the first item in the menu." diff --git a/library/demos/menubu.tcl b/library/demos/menubu.tcl index 86326b5..96e3b15 100644 --- a/library/demos/menubu.tcl +++ b/library/demos/menubu.tcl @@ -21,7 +21,7 @@ pack $w.body -expand 1 -fill both if {[tk windowingsystem] eq "aqua"} {catch {set origUseCustomMDEF $::tk::mac::useCustomMDEF; set ::tk::mac::useCustomMDEF 1}} menubutton $w.body.below -text "Below" -underline 0 -direction below -menu $w.body.below.m -relief raised -menu $w.body.below.m -tearoff 0 +menu $w.body.below.m -tearoff 0 $w.body.below.m add command -label "Below menu: first item" -command "puts \"You have selected the first item from the Below menu.\"" $w.body.below.m add command -label "Below menu: second item" -command "puts \"You have selected the second item from the Below menu.\"" grid $w.body.below -row 0 -column 1 -sticky n diff --git a/library/demos/msgbox.tcl b/library/demos/msgbox.tcl index bd98bf2..2c2cc2d 100644 --- a/library/demos/msgbox.tcl +++ b/library/demos/msgbox.tcl @@ -23,7 +23,7 @@ pack [addSeeDismiss $w.buttons $w {} { }] -side bottom -fill x #pack $w.buttons.dismiss $w.buttons.code $w.buttons.vars -side left -expand 1 -frame $w.left +frame $w.left frame $w.right pack $w.left $w.right -side left -expand yes -fill y -pady .5c -padx .5c @@ -56,7 +56,7 @@ proc showMessageBox {w} { set button [tk_messageBox -icon $msgboxIcon -type $msgboxType \ -title Message -parent $w\ -message "This is a \"$msgboxType\" type messagebox with the \"$msgboxIcon\" icon"] - + tk_messageBox -icon info -message "You have selected \"$button\"" -type ok\ -parent $w } diff --git a/library/demos/puzzle.tcl b/library/demos/puzzle.tcl index fb8ab4c..4f7f955 100644 --- a/library/demos/puzzle.tcl +++ b/library/demos/puzzle.tcl @@ -54,7 +54,7 @@ pack $btns -side bottom -fill x scrollbar $w.s # The button metrics are a bit bigger in Aqua, and since we are -# using place which doesn't autosize, then we need to have a +# using place which doesn't autosize, then we need to have a # slightly larger frame here... if {[tk windowingsystem] eq "aqua"} { diff --git a/library/dialog.tcl b/library/dialog.tcl index 22c4dd3..c751621 100644 --- a/library/dialog.tcl +++ b/library/dialog.tcl @@ -28,7 +28,6 @@ # bottom of the dialog box. proc ::tk_dialog {w title text bitmap default args} { - global tcl_platform variable ::tk::Priv # Check that $default was properly given diff --git a/library/entry.tcl b/library/entry.tcl index c8422dc..f7170f7 100644 --- a/library/entry.tcl +++ b/library/entry.tcl @@ -46,7 +46,6 @@ bind Entry <> { } } bind Entry <> { - global tcl_platform catch { if {[tk windowingsystem] ne "x11"} { catch { diff --git a/library/menu.tcl b/library/menu.tcl index 5a5d9de..a7aaa3f 100644 --- a/library/menu.tcl +++ b/library/menu.tcl @@ -248,7 +248,6 @@ proc ::tk::MbLeave w { proc ::tk::MbPost {w {x {}} {y {}}} { global errorInfo variable ::tk::Priv - global tcl_platform if {[$w cget -state] eq "disabled" || $w eq $Priv(postedMb)} { return @@ -402,7 +401,6 @@ proc ::tk::MbPost {w {x {}} {y {}}} { # is a posted menubutton. proc ::tk::MenuUnpost menu { - global tcl_platform variable ::tk::Priv set mb $Priv(postedMb) @@ -531,7 +529,6 @@ proc ::tk::MbMotion {w upDown rootx rooty} { proc ::tk::MbButtonUp w { variable ::tk::Priv - global tcl_platform set menu [$w cget -menu] set tearoff [expr {[tk windowingsystem] eq "x11" || \ @@ -606,7 +603,6 @@ proc ::tk::MenuMotion {menu x y state} { proc ::tk::MenuButtonDown menu { variable ::tk::Priv - global tcl_platform if {![winfo viewable $menu]} { return @@ -1218,8 +1214,6 @@ proc ::tk::MenuFindName {menu s} { # upper-left corner goes at (x,y). proc ::tk::PostOverPoint {menu x y {entry {}}} { - global tcl_platform - if {$entry ne ""} { if {$entry == [$menu index last]} { incr y [expr {-([$menu yposition $entry] \ @@ -1234,8 +1228,8 @@ proc ::tk::PostOverPoint {menu x y {entry {}}} { if {[tk windowingsystem] eq "win32"} { # osVersion is not available in safe interps set ver 5 - if {[info exists tcl_platform(osVersion)]} { - scan $tcl_platform(osVersion) %d ver + if {[info exists ::tcl_platform(osVersion)]} { + scan $::tcl_platform(osVersion) %d ver } # We need to fix some problems with menu posting on Windows, @@ -1340,7 +1334,6 @@ proc ::tk::GenerateMenuSelect {menu} { proc ::tk_popup {menu x y {entry {}}} { variable ::tk::Priv - global tcl_platform if {$Priv(popup) ne "" || $Priv(postedMb) ne ""} { tk::MenuUnpost {} } diff --git a/library/msgbox.tcl b/library/msgbox.tcl index 939928d..6d329c2 100644 --- a/library/msgbox.tcl +++ b/library/msgbox.tcl @@ -129,7 +129,7 @@ static unsigned char w3_bits[] = { # See the user documentation for details on what tk_messageBox does. # proc ::tk::MessageBox {args} { - global tcl_platform tk_strictMotif + global tk_strictMotif variable ::tk::Priv set w ::tk::PrivMsgBox diff --git a/library/spinbox.tcl b/library/spinbox.tcl index 4d94420..6a5f829 100644 --- a/library/spinbox.tcl +++ b/library/spinbox.tcl @@ -52,7 +52,6 @@ bind Spinbox <> { } } bind Spinbox <> { - global tcl_platform catch { if {[tk windowingsystem] ne "x11"} { catch { diff --git a/library/text.tcl b/library/text.tcl index 279e2d9..18fed2c 100644 --- a/library/text.tcl +++ b/library/text.tcl @@ -543,7 +543,6 @@ proc ::tk::TextAnchor {w} { } proc ::tk::TextSelectTo {w x y {extend 0}} { - global tcl_platform variable ::tk::Priv set anchorname [tk::TextAnchor $w] @@ -1036,7 +1035,6 @@ proc ::tk_textCut w { # w - Name of a text widget. proc ::tk_textPaste w { - global tcl_platform if {![catch {::tk::GetSelection $w CLIPBOARD} sel]} { set oldSeparator [$w cget -autoseparators] if {$oldSeparator} { diff --git a/library/tk.tcl b/library/tk.tcl index da619e6..9a6a581 100644 --- a/library/tk.tcl +++ b/library/tk.tcl @@ -253,7 +253,6 @@ proc ::tk::ScreenChanged screen { uplevel #0 [list upvar #0 ::tk::Priv.$disp ::tk::Priv] variable ::tk::Priv - global tcl_platform if {[info exists Priv]} { set Priv(screen) $screen -- cgit v0.12 From 4660929af627a46789752dc4856f013ed2b5653a Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 18 Aug 2015 14:41:55 +0000 Subject: minor spacing, no functional change. --- generic/tkOldConfig.c | 2 +- library/demos/ixset | 4 ++-- library/demos/square | 2 +- library/msgs/es.msg | 4 ++-- library/msgs/ru.msg | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/generic/tkOldConfig.c b/generic/tkOldConfig.c index 87f4987..920d93e 100644 --- a/generic/tkOldConfig.c +++ b/generic/tkOldConfig.c @@ -114,7 +114,7 @@ Tk_ConfigureWidget( staticSpecs = GetCachedSpecs(interp, specs); for (specPtr = staticSpecs; specPtr->type != TK_CONFIG_END; specPtr++) { - specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED; + specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED; } /* diff --git a/library/demos/ixset b/library/demos/ixset index 06b644d..ee6e072 100644 --- a/library/demos/ixset +++ b/library/demos/ixset @@ -186,12 +186,12 @@ proc createwindows {} { # frame .buttons - button .buttons.ok -default active -command ok -text "Ok" + button .buttons.ok -default active -command ok -text "Ok" button .buttons.apply -default normal -command apply -text "Apply" \ -state disabled button .buttons.cancel -default normal -command cancel -text "Cancel" \ -state disabled - button .buttons.quit -default normal -command quit -text "Quit" + button .buttons.quit -default normal -command quit -text "Quit" pack .buttons.ok .buttons.apply .buttons.cancel .buttons.quit \ -side left -expand yes -pady 5 diff --git a/library/demos/square b/library/demos/square index 08c362b..1d7eb20 100644 --- a/library/demos/square +++ b/library/demos/square @@ -7,7 +7,7 @@ exec wish "$0" ${1+"$@"} # widget. It's only usable in the "tktest" application or if Tk has # been compiled with tkSquare.c. This demo arranges the following # bindings for the widget: -# +# # Button-1 press/drag: moves square to mouse # "a": toggle size animation on/off diff --git a/library/msgs/es.msg b/library/msgs/es.msg index 991711b..578c52c 100644 --- a/library/msgs/es.msg +++ b/library/msgs/es.msg @@ -1,7 +1,7 @@ namespace eval ::tk { ::msgcat::mcset es "&Abort" "&Abortar" ::msgcat::mcset es "&About..." "&Acerca de ..." - ::msgcat::mcset es "All Files" "Todos los archivos" + ::msgcat::mcset es "All Files" "Todos los archivos" ::msgcat::mcset es "Application Error" "Error de la aplicaci\u00f3n" ::msgcat::mcset es "&Blue" "&Azul" ::msgcat::mcset es "Cancel" "Cancelar" @@ -61,7 +61,7 @@ namespace eval ::tk { ::msgcat::mcset es "Tcl Scripts" "Scripts Tcl" ::msgcat::mcset es "Tcl for Windows" "Tcl para Windows" ::msgcat::mcset es "Text Files" "Archivos de texto" - ::msgcat::mcset es "&Yes" "&S\u00ed" + ::msgcat::mcset es "&Yes" "&S\u00ed" ::msgcat::mcset es "abort" "abortar" ::msgcat::mcset es "blue" "azul" ::msgcat::mcset es "cancel" "cancelar" diff --git a/library/msgs/ru.msg b/library/msgs/ru.msg index be2b551..2aac5bb 100644 --- a/library/msgs/ru.msg +++ b/library/msgs/ru.msg @@ -18,7 +18,7 @@ namespace eval ::tk { ::msgcat::mcset ru "Details >>" "\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 >>" ::msgcat::mcset ru "Directory \"%1\$s\" does not exist." "\u041a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 \"%1\$s\" \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442." ::msgcat::mcset ru "&Directory:" "&\u041a\u0430\u0442\u0430\u043b\u043e\u0433:" - ::msgcat::mcset ru "Error: %1\$s" "\u041e\u0448\u0438\u0431\u043a\u0430: %1\$s" + ::msgcat::mcset ru "Error: %1\$s" "\u041e\u0448\u0438\u0431\u043a\u0430: %1\$s" ::msgcat::mcset ru "E&xit" "\u0412\u044b\u0445\u043e\u0434" ::msgcat::mcset ru "File \"%1\$s\" already exists.\nDo you want to overwrite it?" \ "\u0424\u0430\u0439\u043b \"%1\$s\" \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.\n\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0435\u0433\u043e?" @@ -34,7 +34,7 @@ namespace eval ::tk { ::msgcat::mcset ru "Hi" "\u041f\u0440\u0438\u0432\u0435\u0442" ::msgcat::mcset ru "&Hide Console" "\u0421\u043f\u0440\u044f\u0442\u0430\u0442\u044c \u043a\u043e\u043d\u0441\u043e\u043b\u044c" ::msgcat::mcset ru "&Ignore" "&\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c" - ::msgcat::mcset ru "Invalid file name \"%1\$s\"." "\u041d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \"%1\$s\"." + ::msgcat::mcset ru "Invalid file name \"%1\$s\"." "\u041d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \"%1\$s\"." ::msgcat::mcset ru "Log Files" "\u0424\u0430\u0439\u043b\u044b \u0436\u0443\u0440\u043d\u0430\u043b\u0430" ::msgcat::mcset ru "&No" "&\u041d\u0435\u0442" ::msgcat::mcset ru "&OK" "&\u041e\u041a" -- cgit v0.12 From f0195b7327bd47beebd87d10978b3a98a5297757 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 10 Sep 2015 14:05:46 +0000 Subject: Remove licenced images (which cannot be used for commercial purposes). See [/artifact/b2a203459daa9c49?ln=69]. Still to be replaced: win/rc/wish.ico and win/rc/lamp.bmp. This partially reverts commit [0fce209405dff92a]. --- library/images/lamp.png | Bin 8203 -> 0 bytes library/images/lamp.svg | 114 ------------------------------------------------ 2 files changed, 114 deletions(-) delete mode 100644 library/images/lamp.png delete mode 100644 library/images/lamp.svg diff --git a/library/images/lamp.png b/library/images/lamp.png deleted file mode 100644 index 5445746..0000000 Binary files a/library/images/lamp.png and /dev/null differ diff --git a/library/images/lamp.svg b/library/images/lamp.svg deleted file mode 100644 index aa34765..0000000 --- a/library/images/lamp.svg +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - Wish - - - - - - - - - - - - - - - - - - - - -- cgit v0.12 From 0925f4bde6aca761cff7aa5fdc61b66192687da5 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 11 Sep 2015 12:06:04 +0000 Subject: Experiment, just to have a look how the new icon could look like. --- win/rc/lamp.bmp | Bin 2102 -> 2102 bytes win/rc/wish.ico | Bin 46878 -> 43646 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/win/rc/lamp.bmp b/win/rc/lamp.bmp index 834c0f9..1e2f9d4 100644 Binary files a/win/rc/lamp.bmp and b/win/rc/lamp.bmp differ diff --git a/win/rc/wish.ico b/win/rc/wish.ico index 05cad66..5801fb8 100644 Binary files a/win/rc/wish.ico and b/win/rc/wish.ico differ -- cgit v0.12 From e2138596ed17444e34d4aacc028486e200cad81f Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 23 Sep 2015 21:29:42 +0000 Subject: [c648c8dad1] Repair PNG reader buffer overflow protections that prevented read of valid PNG image. --- generic/tkImgPNG.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/generic/tkImgPNG.c b/generic/tkImgPNG.c index 9d0fb30..2ee515b 100644 --- a/generic/tkImgPNG.c +++ b/generic/tkImgPNG.c @@ -1847,6 +1847,13 @@ DecodeLine( if (UnfilterLine(interp, pngPtr) == TCL_ERROR) { return TCL_ERROR; } + if (pngPtr->currentLine >= pngPtr->block.height) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "PNG image data overflow")); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "DATA_OVERFLOW", NULL); + return TCL_ERROR; + } + if (pngPtr->interlace) { switch (pngPtr->phase) { @@ -1881,8 +1888,6 @@ DecodeLine( * Calculate offset into pixelPtr for the first pixel of the line. */ - assert(pngPtr->currentLine < pngPtr->block.height); - offset = pngPtr->currentLine * pngPtr->block.pitch; /* @@ -2092,8 +2097,7 @@ ReadIDAT( * Process IDAT contents until there is no more in this chunk. */ - while (chunkSz && !Tcl_ZlibStreamEof(pngPtr->stream) - && pngPtr->currentLine < pngPtr->block.height) { + while (chunkSz && !Tcl_ZlibStreamEof(pngPtr->stream)) { int len1, len2; /* -- cgit v0.12 From 1a403e858b44dbf3d3a12d896877397894fe3e36 Mon Sep 17 00:00:00 2001 From: ashok Date: Tue, 6 Oct 2015 06:14:34 +0000 Subject: Fix for [46c83f60] (relative paths ignored in tk_getOpenFile/tk_getSaveFile on Vista+). Added tests for -initialdir option. --- tests/winDialog.test | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++ win/tkWinDialog.c | 31 ++++++--- 2 files changed, 213 insertions(+), 11 deletions(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index b7847a5..6b8af59 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -339,6 +339,7 @@ test winDialog-5.11 {GetFileName: initial directory} -constraints { } return $x } -result [file join [initialdir] "12x 455"] + test winDialog-5.12 {GetFileName: initial directory: Tcl_TranslateFilename()} -constraints { nt } -body { @@ -346,6 +347,198 @@ test winDialog-5.12 {GetFileName: initial directory: Tcl_TranslateFilename()} -c tk_getOpenFile -initialdir ~12x/455 } -returnCodes error -result {user "12x" doesn't exist} + +test winDialog-5.12.1 {tk_getSaveFile: initial directory: ~} -constraints { + nt testwinevent +} -body { + unset -nocomplain x + start {set x [tk_getSaveFile \ + -initialdir ~ \ + -initialfile "5 12 1" -title Foo]} + then { + Click ok + } + return $x +} -result [file normalize [file join ~ "5 12 1"]] + +test winDialog-5.12.2 {tk_getSaveFile: initial directory: ~user} -constraints { + nt testwinevent DISABLED +} -body { + # Note: this test is currently disabled because of a bug in file normalize + # for names of the form ~xxx that returns the wrong dir on Windows. + # In particular (in Win8 at least) it returns /users/Default instead + # of /users/USERNAME... + + unset -nocomplain x + start {set x [tk_getSaveFile \ + -initialdir ~$::env(USERNAME) \ + -initialfile "5 12 2" -title Foo]} + then { + Click ok + } + return $x +} -result [file normalize [file join ~$::env(USERNAME) "5 12 2"]] + +test winDialog-5.12.3 {tk_getSaveFile: initial directory: .} -constraints { + nt testwinevent +} -body { + # Windows remembers dirs from previous selections so use + # a subdir for this test, not [initialdir] itself + set newdir [tcltest::makeDirectory "5 12 3"] + set cur [pwd] + try { + cd $newdir + unset -nocomplain x + start {set x [tk_getSaveFile \ + -initialdir . \ + -initialfile "testfile" -title Foo]} + then { + Click ok + } + } finally { + cd $cur + } + string equal $x [file join $newdir testfile] +} -result 1 + +test winDialog-5.12.4 {tk_getSaveFile: initial directory: unicode} -constraints { + nt testwinevent +} -body { + set dir [tcltest::makeDirectory "\u0167\u00e9\u015d\u0167"] + unset -nocomplain x + start {set x [tk_getSaveFile \ + -initialdir $dir \ + -initialfile "testfile" -title Foo]} + then { + Click ok + } + string equal $x [file join $dir testfile] +} -result 1 + +test winDialog-5.12.5 {tk_getSaveFile: initial directory: nativename} -constraints { + nt testwinevent +} -body { + unset -nocomplain x + start {set x [tk_getSaveFile \ + -initialdir [file nativename [initialdir]] \ + -initialfile "5 12 5" -title Foo]} + then { + Click ok + } + return $x +} -result [file join [initialdir] "5 12 5"] + +test winDialog-5.12.6 {tk_getSaveFile: initial directory: relative} -constraints { + nt testwinevent +} -body { + # Windows remembers dirs from previous selections so use + # a subdir for this test, not [initialdir] itself + set dir [tcltest::makeDirectory "5 12 6"] + set cur [pwd] + try { + cd [file dirname $dir] + unset -nocomplain x + start {set x [tk_getSaveFile \ + -initialdir "5 12 6" \ + -initialfile "testfile" -title Foo]} + then { + Click ok + } + } finally { + cd $cur + } + string equal $x [file join $dir testfile] +} -result 1 + +test winDialog-5.12.7 {tk_getOpenFile: initial directory: ~} -constraints { + nt testwinevent +} -body { + set fn [file tail [lindex [glob ~/*] 0]] + unset -nocomplain x + start {set x [tk_getOpenFile \ + -initialdir ~ \ + -initialfile $fn -title Foo]} + then { + Click ok + } + string equal $x [file normalize [file join ~ $fn]] +} -result 1 + +test winDialog-5.12.8 {tk_getOpenFile: initial directory: .} -constraints { + nt testwinevent +} -body { + # Windows remembers dirs from previous selections so use + # a subdir for this test, not [initialdir] itself + set newdir [tcltest::makeDirectory "5 12 8"] + set path [tcltest::makeFile "" "testfile" $newdir] + set cur [pwd] + try { + cd $newdir + unset -nocomplain x + start {set x [tk_getOpenFile \ + -initialdir . \ + -initialfile "testfile" -title Foo]} + then { + Click ok + } + } finally { + cd $cur + } + string equal $x $path +} -result 1 + +test winDialog-5.12.9 {tk_getOpenFile: initial directory: unicode} -constraints { + nt testwinevent +} -body { + set dir [tcltest::makeDirectory "\u0167\u00e9\u015d\u0167"] + set path [tcltest::makeFile "" testfile $dir] + unset -nocomplain x + start {set x [tk_getOpenFile \ + -initialdir $dir \ + -initialfile "testfile" -title Foo]} + then { + Click ok + } + string equal $x $path +} -result 1 + +test winDialog-5.12.10 {tk_getOpenFile: initial directory: nativename} -constraints { + nt testwinevent +} -body { + unset -nocomplain x + tcltest::makeFile "" "5 12 10" [initialdir] + start {set x [tk_getOpenFile \ + -initialdir [file nativename [initialdir]] \ + -initialfile "5 12 10" -title Foo]} + then { + Click ok + } + return $x +} -result [file join [initialdir] "5 12 10"] + +test winDialog-5.12.11 {tk_getOpenFile: initial directory: relative} -constraints { + nt testwinevent +} -body { + # Windows remembers dirs from previous selections so use + # a subdir for this test, not [initialdir] itself + set dir [tcltest::makeDirectory "5 12 11"] + set path [tcltest::makeFile "" testfile $dir] + set cur [pwd] + try { + cd [file dirname $dir] + unset -nocomplain x + start {set x [tk_getOpenFile \ + -initialdir [file tail $dir] \ + -initialfile "testfile" -title Foo]} + then { + Click ok + } + } finally { + cd $cur + } + string equal $x $path +} -result 1 + test winDialog-5.13 {GetFileName: initial file} -constraints { nt testwinevent } -body { diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index dc385e3..0188296 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -1388,18 +1388,27 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, } if (Tcl_DStringValue(&optsPtr->utfDirString)[0] != '\0') { - Tcl_DString dirString; - Tcl_WinUtfToTChar(Tcl_DStringValue(&optsPtr->utfDirString), - Tcl_DStringLength(&optsPtr->utfDirString), &dirString); - hr = ShellProcs.SHCreateItemFromParsingName( - (TCHAR *) Tcl_DStringValue(&dirString), NULL, - &IIDIShellItem, (void **) &dirIf); - /* XXX - Note on failure we do not raise error, simply ignore ini dir */ - if (SUCCEEDED(hr)) { - /* Note we use SetFolder, not SetDefaultFolder - see MSDN docs */ - fdlgIf->lpVtbl->SetFolder(fdlgIf, dirIf); /* Ignore errors */ + Tcl_Obj *normPath, *iniDirPath; + iniDirPath = Tcl_NewStringObj(Tcl_DStringValue(&optsPtr->utfDirString), -1); + Tcl_IncrRefCount(iniDirPath); + normPath = Tcl_FSGetNormalizedPath(interp, iniDirPath); + /* XXX - Note on failures do not raise error, simply ignore ini dir */ + if (normPath) { + const WCHAR *nativePath; + Tcl_IncrRefCount(normPath); + nativePath = Tcl_FSGetNativePath(normPath); /* Points INTO normPath*/ + if (nativePath) { + hr = ShellProcs.SHCreateItemFromParsingName( + nativePath, NULL, + &IIDIShellItem, (void **) &dirIf); + if (SUCCEEDED(hr)) { + /* Note we use SetFolder, not SetDefaultFolder - see MSDN */ + fdlgIf->lpVtbl->SetFolder(fdlgIf, dirIf); /* Ignore errors */ + } + } + Tcl_DecrRefCount(normPath); /* ALSO INVALIDATES nativePath !! */ } - Tcl_DStringFree(&dirString); + Tcl_DecrRefCount(iniDirPath); } oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); -- cgit v0.12 From 47a8d3de4e7b782b904446dcfe4897a631764254 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 6 Oct 2015 11:46:46 +0000 Subject: Fix [600b72bfbc789]: Unnecessary inclusion of tclInt.h in tkMain.c in Windows build The only thing needed from tclInt.h is the definition of TclIntPlatStubs. Including just a tiny part of this struct is enough to make it compile, without the need for tclInt.h --- generic/tkMain.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/generic/tkMain.c b/generic/tkMain.c index f6f4013..1b21223 100644 --- a/generic/tkMain.c +++ b/generic/tkMain.c @@ -55,7 +55,16 @@ extern int TkCygwinMainEx(int, char **, Tcl_AppInitProc *, Tcl_Interp *); * to strcmp here. */ #ifdef _WIN32 -# include "tclInt.h" +/* Little hack to eliminate the need for "tclInt.h" here: + Just copy a small portion of TclIntPlatStubs, just + enough to make it work. See [600b72bfbc] */ +typedef struct { + int magic; + void *hooks; + void (*dummy[16]) (void); /* dummy entries 0-15, not used */ + int (*tclpIsAtty) (int fd); /* 16 */ +} TclIntPlatStubs; +extern const TclIntPlatStubs *tclIntPlatStubsPtr; # include "tkWinInt.h" #else # define TCHAR char @@ -108,9 +117,9 @@ static int WinIsTty(int fd) { */ #if !defined(STATIC_BUILD) - if (tclStubsPtr->reserved9 && TclpIsAtty) { + if (tclStubsPtr->reserved9 && tclIntPlatStubsPtr->tclpIsAtty) { /* We are running on Cygwin */ - return TclpIsAtty(fd); + return tclIntPlatStubsPtr->tclpIsAtty(fd); } #endif handle = GetStdHandle(STD_INPUT_HANDLE + fd); -- cgit v0.12 From c7881f1311665010dcf5da4bab4d7a5f3b0ca631 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 6 Oct 2015 15:04:42 +0000 Subject: Link with userenv.lib, because it is now needed by Tcl. --- win/configure | 4 ++-- win/makefile.vc | 2 +- win/tcl.m4 | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/win/configure b/win/configure index 8671721..64aea44 100755 --- a/win/configure +++ b/win/configure @@ -3736,7 +3736,7 @@ echo $ECHO_N "checking compiler flags... $ECHO_C" >&6 if test "${GCC}" = "yes" ; then SHLIB_LD="" SHLIB_LD_LIBS='${LIBS}' - LIBS="-lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32" + LIBS="-lnetapi32 -lkernel32 -luser32 -ladvapi32 -luserenv -lws2_32" # mingw needs to link ole32 and oleaut32 for [send], but MSVC doesn't LIBS_GUI="-lgdi32 -lcomdlg32 -limm32 -lcomctl32 -lshell32 -luuid -lole32 -loleaut32" STLIB_LD='${AR} cr' @@ -3952,7 +3952,7 @@ echo "${ECHO_T} Using 64-bit $MACHINE mode" >&6 fi fi - LIBS="netapi32.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib" + LIBS="netapi32.lib kernel32.lib user32.lib advapi32.lib userenv.lib ws2_32.lib" case "x`echo \${VisualStudioVersion}`" in x1[4-9]*) diff --git a/win/makefile.vc b/win/makefile.vc index 1b55cdf..ae43eb6 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -523,7 +523,7 @@ guilflags = $(lflags) -subsystem:windows tcllibs = $(TCLSTUBLIB) $(TCLIMPLIB) -baselibs = netapi32.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib +baselibs = netapi32.lib kernel32.lib user32.lib advapi32.lib userenv.lib ws2_32.lib # Avoid 'unresolved external symbol __security_cookie' errors. # c.f. http://support.microsoft.com/?id=894573 !if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" diff --git a/win/tcl.m4 b/win/tcl.m4 index 80a5086..db86f6c 100644 --- a/win/tcl.m4 +++ b/win/tcl.m4 @@ -673,7 +673,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ if test "${GCC}" = "yes" ; then SHLIB_LD="" SHLIB_LD_LIBS='${LIBS}' - LIBS="-lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32" + LIBS="-lnetapi32 -lkernel32 -luser32 -ladvapi32 -luserenv -lws2_32" # mingw needs to link ole32 and oleaut32 for [send], but MSVC doesn't LIBS_GUI="-lgdi32 -lcomdlg32 -limm32 -lcomctl32 -lshell32 -luuid -lole32 -loleaut32" STLIB_LD='${AR} cr' @@ -834,7 +834,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ fi fi - LIBS="netapi32.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib" + LIBS="netapi32.lib kernel32.lib user32.lib advapi32.lib userenv.lib ws2_32.lib" case "x`echo \${VisualStudioVersion}`" in x1[[4-9]]*) -- cgit v0.12 From a330258fc1d11057954a3f1c9ca93f06c10784cd Mon Sep 17 00:00:00 2001 From: ashok Date: Fri, 9 Oct 2015 04:03:31 +0000 Subject: Bug [47af31bd3a] - tk_getSaveFile adds . as extension. Also added more tests for -filetypes and -defaultextension combinations. --- tests/winDialog.test | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++- win/tkWinDialog.c | 25 +++++++---- 2 files changed, 131 insertions(+), 9 deletions(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index 6b8af59..80a025c 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -265,6 +265,7 @@ test winDialog-5.6 {GetFileName: valid option, but missing value} -constraints { } -body { tk_getOpenFile -initialdir bar -title } -returnCodes error -result {value for "-title" missing} + test winDialog-5.7 {GetFileName: extension begins with .} -constraints { nt testwinevent } -body { @@ -281,6 +282,116 @@ test winDialog-5.7 {GetFileName: extension begins with .} -constraints { } -cleanup { unset msg } -result bar.foo + +test winDialog-5.7.1 {GetFileName: extension {} } -constraints { + nt testwinevent +} -body { + start {set x [tk_getSaveFile -defaultextension {} -title Save]} + set msg {} + then { + if {[catch {SetText [vista? 0x47C 0x3e9] bar} msg]} { + Click cancel + } else { + Click ok + } + } + set x "[file tail $x]$msg" +} -cleanup { + unset msg +} -result bar + +test winDialog-5.7.2 {GetFileName: extension {} Bug 47af31bd3ac6fbbb33cde1a5bab1e756ff2a6e00 } -constraints { + nt testwinevent +} -body { + start {set x [tk_getSaveFile -filetypes {{All *}} -defaultextension {} -title Save]} + set msg {} + then { + if {[catch {SetText [vista? 0x47C 0x3e9] bar} msg]} { + Click cancel + } else { + Click ok + } + } + set x "[file tail $x]$msg" +} -cleanup { + unset msg +} -result bar + +test winDialog-5.7.3 {GetFileName: extension {} Bug 47af31bd3ac6fbbb33cde1a5bab1e756ff2a6e00 } -constraints { + nt testwinevent +} -body { + start {set x [tk_getSaveFile -filetypes {{All *}} -defaultextension {} -title Save]} + set msg {} + then { + if {[catch {SetText [vista? 0x47C 0x3e9] bar.c} msg]} { + Click cancel + } else { + Click ok + } + } + set x "[file tail $x]$msg" +} -cleanup { + unset msg +} -result bar.c + +test winDialog-5.7.4 {GetFileName: extension {} } -constraints { + nt testwinevent +} -body { + # Although the docs do not explicitly mention, -filetypes seems to + # override -defaultextension + start {set x [tk_getSaveFile -filetypes {{C .c} {Tcl .tcl}} -defaultextension {foo} -title Save]} + set msg {} + then { + if {[catch {SetText [vista? 0x47C 0x3e9] bar} msg]} { + Click cancel + } else { + Click ok + } + } + set x "[file tail $x]$msg" +} -cleanup { + unset msg +} -result bar.c + +test winDialog-5.7.5 {GetFileName: extension {} } -constraints { + nt testwinevent +} -body { + # Although the docs do not explicitly mention, -filetypes seems to + # override -defaultextension + start {set x [tk_getSaveFile -filetypes {{C .c} {Tcl .tcl}} -defaultextension {} -title Save]} + set msg {} + then { + if {[catch {SetText [vista? 0x47C 0x3e9] bar} msg]} { + Click cancel + } else { + Click ok + } + } + set x "[file tail $x]$msg" +} -cleanup { + unset msg +} -result bar.c + + +test winDialog-5.7.6 {GetFileName: All/extension } -constraints { + nt testwinevent +} -body { + # In 8.6.4 this combination resulted in bar.ext.ext which is bad + start {set x [tk_getSaveFile -filetypes {{All *}} -defaultextension {ext} -title Save]} + set msg {} + then { + if {[catch {SetText [vista? 0x47C 0x3e9] bar} msg]} { + Click cancel + } else { + Click ok + } + } + set x "[file tail $x]$msg" +} -cleanup { + unset msg +} -result bar.ext + + test winDialog-5.8 {GetFileName: extension doesn't begin with .} -constraints { nt testwinevent } -body { @@ -362,7 +473,7 @@ test winDialog-5.12.1 {tk_getSaveFile: initial directory: ~} -constraints { } -result [file normalize [file join ~ "5 12 1"]] test winDialog-5.12.2 {tk_getSaveFile: initial directory: ~user} -constraints { - nt testwinevent DISABLED + nt testwinevent } -body { # Note: this test is currently disabled because of a bug in file normalize # for names of the form ~xxx that returns the wrong dir on Windows. @@ -377,7 +488,7 @@ test winDialog-5.12.2 {tk_getSaveFile: initial directory: ~user} -constraints { Click ok } return $x -} -result [file normalize [file join ~$::env(USERNAME) "5 12 2"]] +} -result [file normalize [file join $::env(USERPROFILE) "5 12 2"]] test winDialog-5.12.3 {tk_getSaveFile: initial directory: .} -constraints { nt testwinevent diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 0188296..d7f63fb 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -1102,7 +1102,7 @@ ParseOFNOptions( for (i = 1; i < objc; i += 2) { int index; const char *string; - Tcl_Obj *valuePtr = objv[i + 1]; + Tcl_Obj *valuePtr; if (Tcl_GetIndexFromObjStruct(interp, objv[i], options, sizeof(struct Options), "option", 0, &index) != TCL_OK) { @@ -1112,19 +1112,25 @@ ParseOFNOptions( */ if (strcmp(Tcl_GetString(objv[i]), "-xpstyle")) goto error_return; - if (Tcl_GetBooleanFromObj(interp, valuePtr, + if (i + 1 == objc) { + Tcl_SetResult(interp, "value for \"-xpstyle\" missing", TCL_STATIC); + Tcl_SetErrorCode(interp, "TK", "FILEDIALOG", "VALUE", NULL); + goto error_return; + } + if (Tcl_GetBooleanFromObj(interp, objv[i+1], &optsPtr->forceXPStyle) != TCL_OK) goto error_return; continue; } else if (i + 1 == objc) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "value for \"%s\" missing", options[index].name)); - Tcl_SetErrorCode(interp, "TK", "FILEDIALOG", "VALUE", NULL); - goto error_return; + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "value for \"%s\" missing", options[index].name)); + Tcl_SetErrorCode(interp, "TK", "FILEDIALOG", "VALUE", NULL); + goto error_return; } + valuePtr = objv[i + 1]; string = Tcl_GetString(valuePtr); switch (options[index].value) { case FILE_DEFAULT: @@ -1185,6 +1191,7 @@ error_return: /* interp should already hold error */ /* On error, we need to clean up anything we might have allocated */ CleanupOFNOptions(optsPtr); return TCL_ERROR; + } @@ -1322,7 +1329,11 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr, goto vamoose; if (filterPtr) { - flags |= FOS_STRICTFILETYPES; + /* + * Causes -filetypes {{All *}} -defaultextension ext to return + * foo.ext.ext when foo is typed into the entry box + * flags |= FOS_STRICTFILETYPES; + */ hr = fdlgIf->lpVtbl->SetFileTypes(fdlgIf, nfilters, filterPtr); if (FAILED(hr)) goto vamoose; -- cgit v0.12 From f5d4ffd4633b850b12389d71358c75289cc61b2c Mon Sep 17 00:00:00 2001 From: ashok Date: Fri, 9 Oct 2015 04:44:27 +0000 Subject: Added missing tests for tk_getOpenFile -defaultextension --- tests/winDialog.test | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/winDialog.test b/tests/winDialog.test index 80a025c..49d9c17 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -391,6 +391,35 @@ test winDialog-5.7.6 {GetFileName: All/extension } -constraints { unset msg } -result bar.ext +test winDialog-5.7.7 {tk_getOpenFile: -defaultextension} -constraints { + nt testwinevent +} -body { + unset -nocomplain x + tcltest::makeFile "" "5 7 7.ext" [initialdir] + start {set x [tk_getOpenFile \ + -defaultextension ext \ + -initialdir [file nativename [initialdir]] \ + -initialfile "5 7 7" -title Foo]} + then { + Click ok + } + return $x +} -result [file join [initialdir] "5 7 7.ext"] + +test winDialog-5.7.8 {tk_getOpenFile: -defaultextension} -constraints { + nt testwinevent +} -body { + unset -nocomplain x + tcltest::makeFile "" "5 7 8.ext" [initialdir] + start {set x [tk_getOpenFile \ + -defaultextension ext \ + -initialdir [file nativename [initialdir]] \ + -initialfile "5 7 8.ext" -title Foo]} + then { + Click ok + } + return $x +} -result [file join [initialdir] "5 7 8.ext"] test winDialog-5.8 {GetFileName: extension doesn't begin with .} -constraints { nt testwinevent -- cgit v0.12 From 40640915557de5d223efa4edaaa69c843cb138cd Mon Sep 17 00:00:00 2001 From: stu Date: Fri, 9 Oct 2015 13:19:57 +0000 Subject: Tk/OpenBSD/Sparc needs -fPIC. --- unix/configure | 2 +- unix/tcl.m4 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unix/configure b/unix/configure index 7934d9e..a03d1c0 100755 --- a/unix/configure +++ b/unix/configure @@ -5364,7 +5364,7 @@ fi ;; *) case "$arch" in - alpha|sparc64) + alpha|sparc|sparc64) SHLIB_CFLAGS="-fPIC" ;; *) diff --git a/unix/tcl.m4 b/unix/tcl.m4 index a6cb41b..f6713e7 100644 --- a/unix/tcl.m4 +++ b/unix/tcl.m4 @@ -1476,7 +1476,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ ;; *) case "$arch" in - alpha|sparc64) + alpha|sparc|sparc64) SHLIB_CFLAGS="-fPIC" ;; *) -- cgit v0.12 From f59d9bb55362d99baf3a6e42b9e567232de14c56 Mon Sep 17 00:00:00 2001 From: fvogel Date: Fri, 9 Oct 2015 19:58:30 +0000 Subject: Fixed bug [1815161] - .text count -ypixels wrong until widget is managed --- doc/text.n | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/text.n b/doc/text.n index 899a402..ed9bc83 100644 --- a/doc/text.n +++ b/doc/text.n @@ -976,11 +976,12 @@ each counting option given. Valid counting options are \fB\-chars\fR, \fB\-displaychars\fR, \fB\-displayindices\fR, \fB\-displaylines\fR, \fB\-indices\fR, \fB\-lines\fR, \fB\-xpixels\fR and \fB\-ypixels\fR. The default value, if no option is specified, is \fB\-indices\fR. There is an -additional possible option \fB\-update\fR which is a modifier. If given, then -all subsequent options ensure that any possible out of date information is -recalculated. This currently only has any effect for the \fB\-ypixels\fR count -(which, if \fB\-update\fR is not given, will use the text widget's current -cached value for each line). The count options are interpreted as follows: +additional possible option \fB\-update\fR which is a modifier. If given (and +if the text widget is managed by a geometry manager), then all subsequent +options ensure that any possible out of date information is recalculated. +This currently only has any effect for the \fB\-ypixels\fR count (which, if +\fB\-update\fR is not given, will use the text widget's current cached value +for each line). The count options are interpreted as follows: .RS .IP \fB\-chars\fR count all characters, whether elided or not. Do not count embedded windows or -- cgit v0.12 From 73f570edce09082a865ef4a9f58569be3b120197 Mon Sep 17 00:00:00 2001 From: ashok Date: Sat, 10 Oct 2015 10:33:16 +0000 Subject: Fix comment in test winDialog-5.12.2 --- tests/winDialog.test | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index 49d9c17..3dc73ac 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -504,10 +504,11 @@ test winDialog-5.12.1 {tk_getSaveFile: initial directory: ~} -constraints { test winDialog-5.12.2 {tk_getSaveFile: initial directory: ~user} -constraints { nt testwinevent } -body { - # Note: this test is currently disabled because of a bug in file normalize - # for names of the form ~xxx that returns the wrong dir on Windows. - # In particular (in Win8 at least) it returns /users/Default instead - # of /users/USERNAME... + + # Note: this test will fail on Tcl versions 8.6.4 and earlier due + # to a bug in file normalize for names of the form ~xxx that + # returns the wrong dir on Windows. In particular (in Win8 at + # least) it returned /users/Default instead of /users/USERNAME... unset -nocomplain x start {set x [tk_getSaveFile \ -- cgit v0.12 From e70967071c3cadbe8e53ee3136451edaf78c98c9 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 13 Oct 2015 13:47:58 +0000 Subject: Fix [908b78de9a6534d6]: winDialog.test terminates in error --- tests/winDialog.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index 3dc73ac..481ab42 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -518,7 +518,7 @@ test winDialog-5.12.2 {tk_getSaveFile: initial directory: ~user} -constraints { Click ok } return $x -} -result [file normalize [file join $::env(USERPROFILE) "5 12 2"]] +} -result [file normalize [file join ~$::env(USERNAME) "5 12 2"]] test winDialog-5.12.3 {tk_getSaveFile: initial directory: .} -constraints { nt testwinevent -- cgit v0.12 From ed0b129f932f0c4247574dec0afc0a0ecb5077a1 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 23 Oct 2015 07:21:41 +0000 Subject: Fix [908b78de9a] for OS X/X11 - which apparently doesn't set ::env(USERNAME) - as well. --- tests/winDialog.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/winDialog.test b/tests/winDialog.test index 481ab42..24441cf 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -512,13 +512,13 @@ test winDialog-5.12.2 {tk_getSaveFile: initial directory: ~user} -constraints { unset -nocomplain x start {set x [tk_getSaveFile \ - -initialdir ~$::env(USERNAME) \ + -initialdir ~$::tcl_platform(user) \ -initialfile "5 12 2" -title Foo]} then { Click ok } return $x -} -result [file normalize [file join ~$::env(USERNAME) "5 12 2"]] +} -result [file normalize [file join ~$::tcl_platform(user) "5 12 2"]] test winDialog-5.12.3 {tk_getSaveFile: initial directory: .} -constraints { nt testwinevent -- cgit v0.12 From 59b3eec3567e7cea0ab68d0ce47b667957fea948 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Mon, 26 Oct 2015 11:23:46 +0000 Subject: Fix for PNG rendering on OS X 10.11; thanks to Stephan Meier for patch --- macosx/tkMacOSXXStubs.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c index e03260f..a5f1c60 100644 --- a/macosx/tkMacOSXXStubs.c +++ b/macosx/tkMacOSXXStubs.c @@ -863,6 +863,7 @@ XGetImage( int format) { NSBitmapImageRep *bitmap_rep; + NSUInteger bitmap_fmt; XImage * imagePtr = NULL; char * bitmap = NULL; char * image_data=NULL; @@ -881,9 +882,10 @@ XGetImage( } bitmap_rep = BitmapRepFromDrawableRect(d, x, y,width, height); + bitmap_fmt = [bitmap_rep bitmapFormat]; if ( bitmap_rep == Nil || - [bitmap_rep bitmapFormat] != 0 || + (bitmap_fmt != 0 && bitmap_fmt != 1) || [bitmap_rep samplesPerPixel] != 4 || [bitmap_rep isPlanar] != 0 ) { TkMacOSXDbgMsg("XGetImage: Failed to construct NSBitmapRep"); @@ -894,9 +896,8 @@ XGetImage( NSImage* ns_image = [[NSImage alloc]initWithSize:image_size]; [ns_image addRepresentation:bitmap_rep]; - /* Assume premultiplied nonplanar data with 4 bytes per pixel and alpha last.*/ - if ( [bitmap_rep bitmapFormat] == 0 && - [bitmap_rep isPlanar ] == 0 && + /* Assume premultiplied nonplanar data with 4 bytes per pixel.*/ + if ( [bitmap_rep isPlanar ] == 0 && [bitmap_rep samplesPerPixel] == 4 ) { bytes_per_row = [bitmap_rep bytesPerRow]; size = bytes_per_row*height; @@ -906,14 +907,27 @@ XGetImage( bitmap = ckalloc(size); /* Oddly enough, the bitmap has the top row at the beginning, - and the pixels are in BGRA format. + and the pixels are in BGRA or ABGR format. */ - for (row=0, n=0; row Date: Sat, 7 Nov 2015 18:41:19 +0000 Subject: Fix for issues with bitmap rendering and mouse events in Tk-Cocoa; thanks to Marc Culler for patches --- macosx/tkMacOSXDraw.c | 90 +++++++++++++++++++++++++-------------------- macosx/tkMacOSXMouseEvent.c | 58 +++++++++++++++++++++-------- macosx/tkMacOSXPrivate.h | 1 + 3 files changed, 94 insertions(+), 55 deletions(-) diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 5f31a2c..185d65a 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -141,7 +141,7 @@ BitmapRepFromDrawableRect( if ( mac_drawable->flags & TK_IS_PIXMAP ) { /* This means that the MacDrawable is functioning as a Tk Pixmap, so its view - field is NULL. It's context field should point to a CGImage. + field is NULL. */ cg_context = GetCGContextForDrawable(drawable); CGRect image_rect = CGRectMake(x, y, width, height); @@ -199,10 +199,10 @@ XCopyArea( Display *display, /* Display. */ Drawable src, /* Source drawable. */ Drawable dst, /* Destination drawable. */ - GC gc, /* GC to use. */ + GC gc, /* GC to use. */ int src_x, /* X & Y, width & height */ int src_y, /* define the source rectangle */ - unsigned int width, /* that will be copied. */ + unsigned int width, /* that will be copied. */ unsigned int height, int dest_x, /* Dest X & Y on dest rect. */ int dest_y) @@ -282,10 +282,10 @@ XCopyPlane( Display *display, /* Display. */ Drawable src, /* Source drawable. */ Drawable dst, /* Destination drawable. */ - GC gc, /* GC to use. */ + GC gc, /* GC to use. */ int src_x, /* X & Y, width & height */ int src_y, /* define the source rectangle */ - unsigned int width, /* that will be copied. */ + unsigned int width, /* that will be copied. */ unsigned int height, int dest_x, /* Dest X & Y on dest rect. */ int dest_y, @@ -293,6 +293,7 @@ XCopyPlane( { TkMacOSXDrawingContext dc; MacDrawable *srcDraw = (MacDrawable *) src; + MacDrawable *dstDraw = (MacDrawable *) dst; display->request++; if (!width || !height) { @@ -306,33 +307,47 @@ XCopyPlane( if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { return; } - if (dc.context) { + CGContextRef context = dc.context; + if (context) { CGImageRef img = TkMacOSXCreateCGImageWithDrawable(src); - if (img) { TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask; unsigned long imageBackground = gc->background; - - if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP && - clipPtr->value.pixmap == src) { - imageBackground = TRANSPARENT_PIXEL << 24; + if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP){ + CGImageRef mask = TkMacOSXCreateCGImageWithDrawable(clipPtr->value.pixmap); + CGRect rect = CGRectMake(dest_x, dest_y, width, height); + rect = CGRectOffset(rect, dstDraw->xOff, dstDraw->yOff); + CGContextSaveGState(context); + /* Move the origin of the destination to top left. */ + CGContextTranslateCTM(context, 0, rect.origin.y + CGRectGetMaxY(rect)); + CGContextScaleCTM(context, 1, -1); + /* Fill with the background color, clipping to the mask. */ + CGContextClipToMask(context, rect, mask); + TkMacOSXSetColorInContext(gc, gc->background, dc.context); + CGContextFillRect(dc.context, rect); + /* Fill with the foreground color, clipping to the intersection of img and mask. */ + CGContextClipToMask(context, rect, img); + TkMacOSXSetColorInContext(gc, gc->foreground, context); + CGContextFillRect(context, rect); + CGContextRestoreGState(context); + CGImageRelease(mask); + CGImageRelease(img); + } else { + DrawCGImage(dst, gc, dc.context, img, gc->foreground, imageBackground, + CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height), + CGRectMake(src_x, src_y, width, height), + CGRectMake(dest_x, dest_y, width, height)); + CGImageRelease(img); } - DrawCGImage(dst, gc, dc.context, img, gc->foreground, - imageBackground, CGRectMake(0, 0, - srcDraw->size.width, srcDraw->size.height), - CGRectMake(src_x, src_y, width, height), - CGRectMake(dest_x, dest_y, width, height)); - CFRelease(img); - } else { + } else { /* no image */ TkMacOSXDbgMsg("Invalid source drawable"); } } else { - TkMacOSXDbgMsg("Invalid destination drawable"); + TkMacOSXDbgMsg("Invalid destination drawable - could not get a bitmap context."); } TkMacOSXRestoreDrawingContext(&dc); - } else { - XCopyArea(display, src, dst, gc, src_x, src_y, width, height, dest_x, - dest_y); + } else { /* source drawable is a window, not a Pixmap */ + XCopyArea(display, src, dst, gc, src_x, src_y, width, height, dest_x, dest_y); } } @@ -356,16 +371,16 @@ XCopyPlane( int TkPutImage( unsigned long *colors, /* Unused on Macintosh. */ - int ncolors, /* Unused on Macintosh. */ + int ncolors, /* Unused on Macintosh. */ Display* display, /* Display. */ Drawable d, /* Drawable to place image on. */ - GC gc, /* GC to use. */ + GC gc, /* GC to use. */ XImage* image, /* Image to place. */ int src_x, /* Source X & Y. */ int src_y, int dest_x, /* Destination X & Y. */ int dest_y, - unsigned int width, /* Same width & height for both */ + unsigned int width, /* Same width & height for both */ unsigned int height) /* distination and source. */ { TkMacOSXDrawingContext dc; @@ -431,11 +446,12 @@ CreateCGImageWithXImage( * BW image */ + /* Reverses the sense of the bits */ static const CGFloat decodeWB[2] = {1, 0}; + decode = decodeWB; bitsPerComponent = 1; bitsPerPixel = 1; - decode = decodeWB; if (image->bitmap_bit_order != MSBFirst) { char *srcPtr = image->data + image->xoffset; char *endPtr = srcPtr + len; @@ -445,22 +461,20 @@ CreateCGImageWithXImage( *destPtr++ = xBitReverseTable[(unsigned char)(*(srcPtr++))]; } } else { - data = memcpy(ckalloc(len), image->data + image->xoffset, - len); + data = memcpy(ckalloc(len), image->data + image->xoffset, len); } if (data) { provider = CGDataProviderCreateWithData(data, data, len, releaseData); } if (provider) { img = CGImageMaskCreate(image->width, image->height, bitsPerComponent, - bitsPerPixel, image->bytes_per_line, - provider, decode, 0); + bitsPerPixel, image->bytes_per_line, provider, decode, 0); } } else if (image->format == ZPixmap && image->bits_per_pixel == 32) { /* * Color image */ - + CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); bitsPerComponent = 8; @@ -476,6 +490,7 @@ CreateCGImageWithXImage( img = CGImageCreate(image->width, image->height, bitsPerComponent, bitsPerPixel, image->bytes_per_line, colorspace, bitmapInfo, provider, decode, 0, kCGRenderingIntentDefault); + CFRelease(provider); } if (colorspace) { CFRelease(colorspace); @@ -483,10 +498,6 @@ CreateCGImageWithXImage( } else { TkMacOSXDbgMsg("Unsupported image type"); } - if (provider) { - CFRelease(provider); - } - return img; } @@ -660,8 +671,7 @@ GetCGContextForDrawable( kCGBitmapByteOrderDefault; #endif char *data; - CGRect bounds = CGRectMake(0, 0, macDraw->size.width, - macDraw->size.height); + CGRect bounds = CGRectMake(0, 0, macDraw->size.width, macDraw->size.height); if (macDraw->flags & TK_IS_BW_PIXMAP) { bitsPerPixel = 8; @@ -738,6 +748,7 @@ DrawCGImage( if (CGImageIsMask(image)) { /*CGContextSaveGState(context);*/ if (macDraw->flags & TK_IS_BW_PIXMAP) { + /* Set fill color to black, background comes from the context, or is transparent. */ if (imageBackground != TRANSPARENT_PIXEL << 24) { CGContextClearRect(context, dstBounds); } @@ -750,6 +761,7 @@ DrawCGImage( TkMacOSXSetColorInContext(gc, imageForeground, context); } } + #ifdef TK_MAC_DEBUG_IMAGE_DRAWING CGContextSaveGState(context); CGContextSetLineWidth(context, 1.0); @@ -768,9 +780,9 @@ DrawCGImage( dstBounds.origin.x, dstBounds.origin.y, dstBounds.size.width, dstBounds.size.height); #else /* TK_MAC_DEBUG_IMAGE_DRAWING */ + CGContextSaveGState(context); - CGContextTranslateCTM(context, 0, - dstBounds.origin.y + CGRectGetMaxY(dstBounds)); + CGContextTranslateCTM(context, 0, dstBounds.origin.y + CGRectGetMaxY(dstBounds)); CGContextScaleCTM(context, 1, -1); CGContextDrawImage(context, dstBounds, image); CGContextRestoreGState(context); diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 8c0a2e6..31038b5 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -34,6 +34,18 @@ enum { NSWindowWillMoveEventType = 20 }; +/* + * In OS X 10.6 an NSEvent of type NSMouseMoved would always have a non-Nil + * window attribute when the mouse was inside a window. As of 10.8 this + * behavior had changed. The new behavior was that if the mouse were ever + * moved outside of a window, all subsequent NSMouseMoved NSEvents would have a + * Nil window attribute. To work around this we remember which window the + * mouse is in by saving the window attribute of each NSEvent of type + * NSMouseEntered. If an NSEvent has a Nil window attribute we use our saved + * window. It may be the case that the mouse has actually left the window, but + * this is harmless since Tk will ignore the event in that case. + */ + @implementation TKApplication(TKMouseEvent) - (NSEvent *) tkProcessMouseEvent: (NSEvent *) theEvent { @@ -49,12 +61,11 @@ enum { switch (type) { case NSMouseEntered: + /* Remember which window has the mouse. */ + _windowWithMouse = [theEvent window]; + break; case NSMouseExited: case NSCursorUpdate: -#if 0 - trackingArea = [theEvent trackingArea]; - /* fall through */ -#endif case NSLeftMouseDown: case NSLeftMouseUp: case NSRightMouseDown: @@ -65,14 +76,6 @@ enum { case NSRightMouseDragged: case NSOtherMouseDragged: case NSMouseMoved: -#if 0 - eventNumber = [theEvent eventNumber]; - if (!trackingArea) { - clickCount = [theEvent clickCount]; - buttonNumber = [theEvent buttonNumber]; - } - /* fall through */ -#endif case NSTabletPoint: case NSTabletProximity: case NSScrollWheel: @@ -85,13 +88,36 @@ enum { /* Create an Xevent to add to the Tk queue. */ win = [theEvent window]; NSPoint global, local = [theEvent locationInWindow]; - if (win) { +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + /* convertBaseToScreen and convertScreenToBase were deprecated in 10.7. */ + NSRect pointrect; + pointrect.origin = local; + pointrect.size.width = 0; + pointrect.size.height = 0; +#endif + if (win) { /* local will be in window coordinates. */ +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + global = [win convertRectToScreen:pointrect].origin; +#else global = [win convertBaseToScreen:local]; +#endif local.y = [win frame].size.height - local.y; global.y = tkMacOSXZeroScreenHeight - global.y; - } else { - local.y = tkMacOSXZeroScreenHeight - local.y; - global = local; + } else { /* local will be in screen coordinates. */ + if (_windowWithMouse ) { + win = _windowWithMouse; + global = local; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + local = [win convertRectFromScreen:pointrect].origin; +#else + local = [win convertScreenToBase:local]; +#endif + local.y = [win frame].size.height - local.y; + global.y = tkMacOSXZeroScreenHeight - global.y; + } else { /* We have no window. Use the screen???*/ + local.y = tkMacOSXZeroScreenHeight - local.y; + global = local; + } } Window window = TkMacOSXGetXWindow(win); diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 2de3673..1d20081 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -274,6 +274,7 @@ VISIBILITY_HIDDEN TKMenu *_defaultMainMenu, *_defaultApplicationMenu; NSArray *_defaultApplicationMenuItems, *_defaultWindowsMenuItems; NSArray *_defaultHelpMenuItems; + NSWindow *_windowWithMouse; } @end @interface TKApplication(TKInit) -- cgit v0.12 From a7dfb1b21893c1ab01d02b00e7f9e1b7ebd0198c Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sun, 8 Nov 2015 22:01:01 +0000 Subject: Cleanup of last patch to Tk-Cocoa --- macosx/tkMacOSXDraw.c | 2 +- macosx/tkMacOSXKeyEvent.c | 36 +++++++++-------- macosx/tkMacOSXMouseEvent.c | 94 +++++++++++++++++++++++++++++--------------- macosx/tkMacOSXPrivate.h | 20 +++++++++- macosx/tkMacOSXSubwindows.c | 4 -- macosx/tkMacOSXWindowEvent.c | 15 ------- 6 files changed, 101 insertions(+), 70 deletions(-) diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 185d65a..3e12b36 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -1492,7 +1492,7 @@ TkScrollWindow( { Drawable drawable = Tk_WindowId(tkwin); MacDrawable *macDraw = (MacDrawable *) drawable; - NSView *view = TkMacOSXDrawableView(macDraw); + TKContentView *view = (TKContentView *)TkMacOSXDrawableView(macDraw); CGRect srcRect, dstRect; HIShapeRef dmgRgn = NULL, extraRgn = NULL; NSRect bounds, visRect, scrollSrc, scrollDst; diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index df9dd8a..8521beb 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -227,7 +227,7 @@ static unsigned isFunctionKey(unsigned int code); -@implementation TKContentView(TKKeyEvent) +@implementation TKContentView /* implementation (called through interpretKeyEvents:]). */ /* : called when done composing; @@ -293,22 +293,6 @@ static unsigned isFunctionKey(unsigned int code); } -/* delete display of composing characters [not in ] */ -- (void)deleteWorkingText -{ - if (privateWorkingText == nil) - return; - if (NS_KEYLOG) - NSLog(@"deleteWorkingText len = %lu\n", - (unsigned long)[privateWorkingText length]); - [privateWorkingText release]; - privateWorkingText = nil; - processingCompose = NO; - - //PENDING: delete working text -} - - - (BOOL)hasMarkedText { return privateWorkingText != nil; @@ -418,6 +402,24 @@ static unsigned isFunctionKey(unsigned int code); @end +@implementation TKContentView(TKKeyEvent) +/* delete display of composing characters [not in ] */ +- (void)deleteWorkingText +{ + if (privateWorkingText == nil) + return; + if (NS_KEYLOG) + NSLog(@"deleteWorkingText len = %lu\n", + (unsigned long)[privateWorkingText length]); + [privateWorkingText release]; + privateWorkingText = nil; + processingCompose = NO; + + //PENDING: delete working text +} +@end + + /* * Set up basic fields in xevent for keyboard input. diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 31038b5..4046359 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -28,12 +28,53 @@ static int GenerateButtonEvent(MouseEventData *medPtr); static unsigned int ButtonModifiers2State(UInt32 buttonState, UInt32 keyModifiers); +#pragma mark NSWindow(TKMouseEvent) + +/* Conversion of coordinates between window and screen */ +@interface NSWindow(TKWm) +- (NSPoint) convertPointToScreen:(NSPoint)point; +- (NSPoint) convertPointFromScreen:(NSPoint)point; +@end + +@implementation NSWindow(TKMouseEvent) +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 +- (NSPoint) convertPointToScreen: (NSPoint) point +{ + return [self convertBaseToScreen:point]; +} +- (NSPoint) convertPointFromScreen: (NSPoint)point +{ + return [self convertScreenToBase:point]; +} +@end +#else +- (NSPoint) convertPointToScreen: (NSPoint) point +{ + NSRect pointrect; + pointrect.origin = point; + pointrect.size.width = 0; + pointrect.size.height = 0; + return [self convertRectToScreen:pointrect].origin; +} +- (NSPoint) convertPointFromScreen: (NSPoint)point +{ + NSRect pointrect; + pointrect.origin = point; + pointrect.size.width = 0; + pointrect.size.height = 0; + return [self convertRectFromScreen:pointrect].origin; +} +@end +#endif + +#pragma mark - + + #pragma mark TKApplication(TKMouseEvent) enum { NSWindowWillMoveEventType = 20 }; - /* * In OS X 10.6 an NSEvent of type NSMouseMoved would always have a non-Nil * window attribute when the mouse was inside a window. As of 10.8 this @@ -52,8 +93,8 @@ enum { #ifdef TK_MAC_DEBUG_EVENTS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent); #endif - id win; - NSEventType type = [theEvent type]; + id win; + NSEventType type = [theEvent type]; #if 0 NSTrackingArea *trackingArea = nil; NSInteger eventNumber, clickCount, buttonNumber; @@ -62,7 +103,13 @@ enum { switch (type) { case NSMouseEntered: /* Remember which window has the mouse. */ + if (_windowWithMouse) { + [_windowWithMouse release]; + } _windowWithMouse = [theEvent window]; + if (_windowWithMouse) { + [_windowWithMouse retain]; + } break; case NSMouseExited: case NSCursorUpdate: @@ -87,31 +134,17 @@ enum { /* Create an Xevent to add to the Tk queue. */ win = [theEvent window]; + NSWindow *nswindow = (NSWindow *)win; NSPoint global, local = [theEvent locationInWindow]; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 - /* convertBaseToScreen and convertScreenToBase were deprecated in 10.7. */ - NSRect pointrect; - pointrect.origin = local; - pointrect.size.width = 0; - pointrect.size.height = 0; -#endif if (win) { /* local will be in window coordinates. */ -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 - global = [win convertRectToScreen:pointrect].origin; -#else - global = [win convertBaseToScreen:local]; -#endif + global = [nswindow convertPointToScreen: local]; local.y = [win frame].size.height - local.y; global.y = tkMacOSXZeroScreenHeight - global.y; } else { /* local will be in screen coordinates. */ if (_windowWithMouse ) { win = _windowWithMouse; global = local; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 - local = [win convertRectFromScreen:pointrect].origin; -#else - local = [win convertScreenToBase:local]; -#endif + local = [nswindow convertPointFromScreen: local]; local.y = [win frame].size.height - local.y; global.y = tkMacOSXZeroScreenHeight - global.y; } else { /* We have no window. Use the screen???*/ @@ -569,19 +602,18 @@ TkpWarpPointer( } /* - * Tell the OSX core to generate the events to make it happen. This is - * fairly ugly, but means that under most circumstances we'll register all - * the events that would normally be generated correctly. If we use - * CGWarpMouseCursorPosition instead, strange things happen. + * Tell the OSX core to generate the events to make it happen. */ - buttonState = (GetCurrentEvent() && Tk_MacOSXIsAppInFront()) - ? GetCurrentEventButtonState() : GetCurrentButtonState(); - - CGPostMouseEvent(pt, 1 /* generate motion events */, 5, - buttonState&1 ? 1 : 0, buttonState&2 ? 1 : 0, - buttonState&4 ? 1 : 0, buttonState&8 ? 1 : 0, - buttonState&16 ? 1 : 0); + buttonState = [NSEvent pressedMouseButtons]; + CGEventType type = kCGEventMouseMoved; + CGEventRef theEvent = CGEventCreateMouseEvent(NULL, + type, + pt, + buttonState); + CGWarpMouseCursorPosition(pt); + CGEventPost(kCGHIDEventTap, theEvent); + CFRelease(theEvent); } /* diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 1d20081..9cdc27c 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -301,10 +301,10 @@ VISIBILITY_HIDDEN @interface TKContentView : NSView { @private /*Remove private API calls.*/ - #if 0 +#if 0 id _savedSubviews; BOOL _subviewsSetAside; - #endif +#endif NSString *privateWorkingText; } @end @@ -313,6 +313,18 @@ VISIBILITY_HIDDEN - (void) deleteWorkingText; @end +@interface TKContentView(TKWindowEvent) +- (void) drawRect: (NSRect) rect; +- (void) generateExposeEvents: (HIShapeRef) shape; +- (void) generateExposeEvents: (HIShapeRef) shape childrenOnly: (int) childrenOnly; +- (void) viewDidEndLiveResize; +- (void) tkToolbarButton: (id) sender; +- (BOOL) isOpaque; +- (BOOL) wantsDefaultClipping; +- (BOOL) acceptsFirstResponder; +- (void) keyDown: (NSEvent *) theEvent; +@end + VISIBILITY_HIDDEN @interface TKWindow : NSWindow @end @@ -345,4 +357,8 @@ VISIBILITY_HIDDEN keyEquivalentModifierMask:(NSUInteger)keyEquivalentModifierMask; @end +/* Helper functions from tkMacOSXDeprecations.c */ + +extern NSPoint convertWindowToScreen( NSWindow *window, NSPoint point); + #endif /* _TKMACPRIV */ diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 2a88422..72ef39c 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -805,10 +805,6 @@ TkMacOSXUpdateClipRgn( /* * TODO: Here we should handle out of process embedding. */ - } else if (winPtr->wmInfoPtr->attributes & - kWindowResizableAttribute) { - NSWindow *w = TkMacOSXDrawableWindow(winPtr->window); - } macWin->aboveVisRgn = HIShapeCreateCopy(rgn); diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 15e86ca..7f1cf90 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -780,21 +780,6 @@ Tk_MacOSXIsAppInFront(void) * */ -@interface TKContentView(TKWindowEvent) -- (void) drawRect: (NSRect) rect; -- (void) generateExposeEvents: (HIShapeRef) shape; -- (void) generateExposeEvents: (HIShapeRef) shape childrenOnly: (int) childrenOnly; -- (void) viewDidEndLiveResize; -- (void) tkToolbarButton: (id) sender; -- (BOOL) isOpaque; -- (BOOL) wantsDefaultClipping; -- (BOOL) acceptsFirstResponder; -- (void) keyDown: (NSEvent *) theEvent; -@end - -@implementation TKContentView -@end - /*Restrict event processing to Expose events.*/ static Tk_RestrictAction ExposeRestrictProc( -- cgit v0.12 From f56728f92c68f0ebbc445ee1e3daeda392780922 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Wed, 25 Nov 2015 03:13:02 +0000 Subject: Remove multiple deprecated internal API calls on OS X; streamline Apple Events implementation; thanks to Marc Culler for extensive patches --- generic/tkText.h | 2 +- macosx/tkMacOSXDialog.c | 179 ++++++++--- macosx/tkMacOSXDraw.c | 2 +- macosx/tkMacOSXFont.c | 18 +- macosx/tkMacOSXHLEvents.c | 747 +++++++++++++++++-------------------------- macosx/tkMacOSXMenu.c | 2 +- macosx/tkMacOSXMouseEvent.c | 116 ++----- macosx/tkMacOSXPrivate.h | 27 +- macosx/tkMacOSXWindowEvent.c | 13 +- macosx/tkMacOSXWm.c | 42 +++ macosx/tkMacOSXXStubs.c | 16 +- 11 files changed, 566 insertions(+), 598 deletions(-) diff --git a/generic/tkText.h b/generic/tkText.h index 99a4888..78a99a9 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -168,7 +168,7 @@ typedef struct TkTextSegment { int size; /* Size of this segment (# of bytes of index * space it occupies). */ union { - char chars[1]; /* Characters that make up character info. + char chars[2]; /* Characters that make up character info. * Actual length varies to hold as many * characters as needed.*/ TkTextToggle toggle; /* Information about tag toggle. */ diff --git a/macosx/tkMacOSXDialog.c b/macosx/tkMacOSXDialog.c index 4b19260..ca17195 100644 --- a/macosx/tkMacOSXDialog.c +++ b/macosx/tkMacOSXDialog.c @@ -14,6 +14,17 @@ #include "tkMacOSXPrivate.h" #include "tkFileFilter.h" +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 +#define modalOK NSOKButton +#define modalCancel NSCancelButton +#else +#define modalOK NSModalResponseOK +#define modalCancel NSModalResponseCancel +#endif +#define modalOther -1 +#define modalError -2 + + static const char *const colorOptionStrings[] = { "-initialcolor", "-parent", "-title", NULL }; @@ -130,6 +141,23 @@ static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = { [TYPE_YESNO] = {5, 6, 0}, [TYPE_YESNOCANCEL] = {5, 6, 4}, }; + +/* + * Construct a file URL from directory and filename. Either may + * be nil. If both are nil, returns nil. + */ +#if MAC_OS_X_VERSION_MIN_REQUIRED > 1050 +static NSURL *getFileURL(NSString *directory, NSString *filename) { + NSURL *url = nil; + if (directory) { + url = [NSURL fileURLWithPath:directory]; + } + if (filename) { + url = [NSURL URLWithString:filename relativeToURL:url]; + } + return url; +} +#endif #pragma mark TKApplication(TKDialog) @@ -149,12 +177,12 @@ static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = { if (callbackInfo->multiple) { resultObj = Tcl_NewListObj(0, NULL); - for (NSString *name in [(NSOpenPanel*)panel filenames]) { + for (NSURL *url in [(NSOpenPanel*)panel URLs]) { Tcl_ListObjAppendElement(callbackInfo->interp, resultObj, - Tcl_NewStringObj([name UTF8String], -1)); + Tcl_NewStringObj([[url path] UTF8String], -1)); } } else { - resultObj = Tcl_NewStringObj([[panel filename] UTF8String], -1); + resultObj = Tcl_NewStringObj([[[panel URL]path] UTF8String], -1); } if (callbackInfo->cmdObj) { Tcl_Obj **objv, **tmpv; @@ -189,7 +217,7 @@ static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = { { AlertCallbackInfo *callbackInfo = contextInfo; - if (returnCode != NSAlertErrorReturn) { + if (returnCode >= NSAlertFirstButtonReturn) { Tcl_Obj *resultObj = Tcl_NewStringObj(alertButtonStrings[ alertNativeButtonIndexAndTypeToButtonIndex[callbackInfo-> typeIndex][returnCode - NSAlertFirstButtonReturn]], -1); @@ -309,7 +337,7 @@ Tk_ChooseColorObjCmd( [colorPanel setColor:initialColor]; } returnCode = [NSApp runModalForWindow:colorPanel]; - if (returnCode == NSOKButton) { + if (returnCode == modalOK) { color = [[colorPanel color] colorUsingColorSpace: [NSColorSpace genericRGBColorSpace]]; numberOfComponents = [color numberOfComponents]; @@ -369,7 +397,7 @@ Tk_GetOpenFileObjCmd( NSWindow *parent; NSMutableArray *fileTypes = nil; NSOpenPanel *panel = [NSOpenPanel openPanel]; - NSInteger returnCode = NSAlertErrorReturn; + NSInteger modalReturnCode = modalError; TkInitFileFilters(&fl); for (i = 1; i < objc; i += 2) { @@ -439,6 +467,7 @@ Tk_GetOpenFileObjCmd( break; } } + [panel setAllowsMultipleSelection:multiple]; if (fl.filters) { fileTypes = [NSMutableArray array]; for (FileFilter *filterPtr = fl.filters; filterPtr; @@ -471,7 +500,7 @@ Tk_GetOpenFileObjCmd( } } } - [panel setAllowsMultipleSelection:multiple]; + [panel setAllowedFileTypes:fileTypes]; if (cmdObj) { callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo)); if (Tcl_IsShared(cmdObj)) { @@ -484,19 +513,37 @@ Tk_GetOpenFileObjCmd( 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]; +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + [panel beginSheetForDirectory:directory + file:filename + types:fileTypes + modalForWindow:parent + modalDelegate:NSApp + didEndSelector: + @selector(tkFilePanelDidEnd:returnCode:contextInfo:) + contextInfo:callbackInfo]; +#else + [panel setAllowedFileTypes:fileTypes]; + [panel setDirectoryURL:getFileURL(directory, filename)]; + [panel beginSheetModalForWindow:parent + completionHandler:^(NSInteger returnCode) + { [NSApp tkFilePanelDidEnd:panel + returnCode:returnCode + contextInfo:callbackInfo ]; } ]; +#endif + modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:panel]; } else { - returnCode = [panel runModalForDirectory:directory file:filename - types:fileTypes]; - [NSApp tkFilePanelDidEnd:panel returnCode:returnCode +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + modalReturnCode = [panel runModalForDirectory:directory + file:filename]; +#else + [panel setDirectoryURL:getFileURL(directory, filename)]; + modalReturnCode = [panel runModal]; +#endif + [NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode contextInfo:callbackInfo]; } - result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR; + result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR; if (typeVariablePtr && result == TCL_OK) { /* * The -typevariable option is not really supported. @@ -548,7 +595,7 @@ Tk_GetSaveFileObjCmd( NSWindow *parent; NSMutableArray *fileTypes = nil; NSSavePanel *panel = [NSSavePanel savePanel]; - NSInteger returnCode = NSAlertErrorReturn; + NSInteger modalReturnCode = modalError; TkInitFileFilters(&fl); for (i = 1; i < objc; i += 2) { @@ -665,18 +712,34 @@ Tk_GetSaveFileObjCmd( 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]; +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + [panel beginSheetForDirectory:directory + file:filename + modalForWindow:parent + modalDelegate:NSApp + didEndSelector: + @selector(tkFilePanelDidEnd:returnCode:contextInfo:) + contextInfo:callbackInfo]; +#else + [panel setDirectoryURL:getFileURL(directory, filename)]; + [panel beginSheetModalForWindow:parent + completionHandler:^(NSInteger returnCode) + { [NSApp tkFilePanelDidEnd:panel + returnCode:returnCode + contextInfo:callbackInfo ]; } ]; +#endif + modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:panel]; } else { - returnCode = [panel runModalForDirectory:directory file:filename]; - [NSApp tkFilePanelDidEnd:panel returnCode:returnCode +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + modalReturnCode = [panel runModalForDirectory:directory file:filename]; +#else + [panel setDirectoryURL:getFileURL(directory, filename)]; + modalReturnCode = [panel runModal]; +#endif + [NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode contextInfo:callbackInfo]; } - result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR; + result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR; end: TkFreeFileFilters(&fl); @@ -719,7 +782,7 @@ Tk_ChooseDirectoryObjCmd( NSString *message, *title; NSWindow *parent; NSOpenPanel *panel = [NSOpenPanel openPanel]; - NSInteger returnCode = NSAlertErrorReturn; + NSInteger modalReturnCode = modalError; for (i = 1; i < objc; i += 2) { if (Tcl_GetIndexFromObjStruct(interp, objv[i], chooseOptionStrings, @@ -787,18 +850,33 @@ Tk_ChooseDirectoryObjCmd( 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:) +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + [panel beginSheetForDirectory:directory + file:filename + modalForWindow:parent + modalDelegate:NSApp + didEndSelector: @selector(tkFilePanelDidEnd:returnCode:contextInfo:) contextInfo:callbackInfo]; - returnCode = cmdObj ? NSAlertOtherReturn : - [NSApp runModalForWindow:panel]; +#else + [panel setDirectoryURL:getFileURL(directory, filename)]; + [panel beginSheetModalForWindow:parent + completionHandler:^(NSInteger returnCode) + { [NSApp tkFilePanelDidEnd:panel + returnCode:returnCode + contextInfo:callbackInfo ]; } ]; +#endif + modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:panel]; } else { - returnCode = [panel runModalForDirectory:directory file:filename]; - [NSApp tkFilePanelDidEnd:panel returnCode:returnCode +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + modalReturnCode = [panel runModalForDirectory:directory file:nil]; +#else + [panel setDirectoryURL:getFileURL(directory, filename)]; + modalReturnCode = [panel runModal]; +#endif + [NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode contextInfo:callbackInfo]; } - result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR; + result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR; end: return result; @@ -899,7 +977,7 @@ TkMacOSXStandardAboutPanelObjCmd( Tcl_WrongNumArgs(interp, 1, objv, NULL); return TCL_ERROR; } - [NSApp orderFrontStandardAboutPanelWithOptions:nil]; + [NSApp orderFrontStandardAboutPanelWithOptions:[NSDictionary dictionary]]; return TCL_OK; } @@ -937,7 +1015,7 @@ Tk_MessageBoxObjCmd( NSWindow *parent; NSArray *buttons; NSAlert *alert = [NSAlert new]; - NSInteger returnCode = NSAlertErrorReturn; + NSInteger modalReturnCode = 1; iconIndex = ICON_INFO; typeIndex = TYPE_OK; @@ -1064,17 +1142,26 @@ Tk_MessageBoxObjCmd( 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]]; +#if MAC_OS_X_VERSION_MIN_REQUIRED > 1090 + [alert beginSheetModalForWindow:parent + completionHandler:^(NSModalResponse returnCode) + { [NSApp tkAlertDidEnd:alert + returnCode:returnCode + contextInfo:callbackInfo ]; } ]; +#else + [alert beginSheetModalForWindow:parent + modalDelegate:NSApp + didEndSelector:@selector(tkAlertDidEnd:returnCode:contextInfo:) + contextInfo:callbackInfo]; +#endif + modalReturnCode = cmdObj ? 0 : + [NSApp runModalForWindow:[alert window]]; } else { - returnCode = [alert runModal]; - [NSApp tkAlertDidEnd:alert returnCode:returnCode + modalReturnCode = [alert runModal]; + [NSApp tkAlertDidEnd:alert returnCode:modalReturnCode contextInfo:callbackInfo]; } - result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR; + result = (modalReturnCode < 1) ? TCL_OK : TCL_ERROR; end: [alert release]; return result; diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 4728fea..ed8c428 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -675,7 +675,7 @@ GetCGContextForDrawable( if (macDraw->flags & TK_IS_BW_PIXMAP) { bitsPerPixel = 8; - bitmapInfo = kCGImageAlphaOnly; + bitmapInfo = (CGBitmapInfo)kCGImageAlphaOnly; } else { colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); bitsPerPixel = 32; diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c index 45a68f7..54b0fb8 100644 --- a/macosx/tkMacOSXFont.c +++ b/macosx/tkMacOSXFont.c @@ -15,6 +15,19 @@ #include "tkMacOSXPrivate.h" #include "tkMacOSXFont.h" +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 +#define defaultOrientation kCTFontDefaultOrientation +#define verticalOrientation kCTFontVerticalOrientation +#else +#define defaultOrientation kCTFontOrientationDefault +#define verticalOrientation kCTFontOrientationVertical +#endif +#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100 +#define fixedPitch kCTFontUserFixedPitchFontType +#else +#define fixedPitch kCTFontUIFontUserFixedPitch +#endif + /* #ifdef TK_MAC_DEBUG #define TK_MAC_DEBUG_FONTS @@ -270,7 +283,7 @@ InitFont( fmPtr->fixed = [nsFont advancementForGlyph:glyphs[0]].width == [nsFont advancementForGlyph:glyphs[1]].width; bounds = NSRectFromCGRect(CTFontGetBoundingRectsForGlyphs((CTFontRef) - nsFont, kCTFontDefaultOrientation, ch, boundingRects, nCh)); + nsFont, defaultOrientation, ch, boundingRects, nCh)); kern = [nsFont advancementForGlyph:glyphs[2]].width - [fontPtr->nsFont advancementForGlyph:glyphs[2]].width; } @@ -382,8 +395,7 @@ TkpFontPkgInit( systemFont++; } TkInitFontAttributes(&fa); - nsFont = (NSFont*) CTFontCreateUIFontForLanguage( - kCTFontUserFixedPitchFontType, 11, NULL); + nsFont = (NSFont*) CTFontCreateUIFontForLanguage(fixedPitch, 11, NULL); if (nsFont) { GetTkFontAttributesForNSFont(nsFont, &fa); CFRelease(nsFont); diff --git a/macosx/tkMacOSXHLEvents.c b/macosx/tkMacOSXHLEvents.c index daf860f..47033b0 100644 --- a/macosx/tkMacOSXHLEvents.c +++ b/macosx/tkMacOSXHLEvents.c @@ -7,12 +7,15 @@ * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen + * Copyright (c) 2015 Marc Culler * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tkMacOSXPrivate.h" +#include +#define URL_MAX_LENGTH (17 + MAXPATHLEN) /* * This is a Tcl_Event structure that the Quit AppleEvent handler uses to @@ -30,154 +33,32 @@ typedef struct KillEvent { * Static functions used only in this file. */ -static OSErr QuitHandler(const AppleEvent *event, - AppleEvent *reply, SRefCon handlerRefcon); -static OSErr OappHandler(const AppleEvent *event, - AppleEvent *reply, SRefCon handlerRefcon); -static OSErr RappHandler(const AppleEvent *event, - AppleEvent *reply, SRefCon handlerRefcon); -static OSErr OdocHandler(const AppleEvent *event, - AppleEvent *reply, SRefCon handlerRefcon); -static OSErr PrintHandler(const AppleEvent *event, - AppleEvent *reply, SRefCon handlerRefcon); -static OSErr ScriptHandler(const AppleEvent *event, - AppleEvent *reply, SRefCon handlerRefcon); -static OSErr PrefsHandler(const AppleEvent *event, - AppleEvent *reply, SRefCon handlerRefcon); -static int MissedAnyParameters(const AppleEvent *theEvent); -static int ReallyKillMe(Tcl_Event *eventPtr, int flags); -static OSStatus FSRefToDString(const FSRef *fsref, Tcl_DString *ds); +static void tkMacOSXProcessFiles(NSAppleEventDescriptor* event, + NSAppleEventDescriptor* replyEvent, + Tcl_Interp *interp, + char* procedure); +static int MissedAnyParameters(const AppleEvent *theEvent); +static int ReallyKillMe(Tcl_Event *eventPtr, int flags); #pragma mark TKApplication(TKHLEvents) @implementation TKApplication(TKHLEvents) - (void) terminate: (id) sender { - QuitHandler(NULL, NULL, (SRefCon) _eventInterp); + [self handleQuitApplicationEvent:Nil withReplyEvent:Nil]; } - (void) preferences: (id) sender { - PrefsHandler(NULL, NULL, (SRefCon) _eventInterp); + [self handleShowPreferencesEvent:Nil withReplyEvent:Nil]; } -@end - -#pragma mark - - -/* - *---------------------------------------------------------------------- - * - * TkMacOSXInitAppleEvents -- - * - * Initilize the Apple Events on the Macintosh. This registers the core - * event handlers. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ -void -TkMacOSXInitAppleEvents( - Tcl_Interp *interp) /* Interp to handle basic events. */ +- (void) handleQuitApplicationEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent { - AEEventHandlerUPP OappHandlerUPP, RappHandlerUPP, OdocHandlerUPP; - AEEventHandlerUPP PrintHandlerUPP, QuitHandlerUPP, ScriptHandlerUPP; - AEEventHandlerUPP PrefsHandlerUPP; - static Boolean initialized = FALSE; - - if (!initialized) { - initialized = TRUE; - - /* - * Install event handlers for the core apple events. - */ - - QuitHandlerUPP = NewAEEventHandlerUPP(QuitHandler); - ChkErr(AEInstallEventHandler, kCoreEventClass, kAEQuitApplication, - QuitHandlerUPP, (SRefCon) interp, false); - - OappHandlerUPP = NewAEEventHandlerUPP(OappHandler); - ChkErr(AEInstallEventHandler, kCoreEventClass, kAEOpenApplication, - OappHandlerUPP, (SRefCon) interp, false); - - RappHandlerUPP = NewAEEventHandlerUPP(RappHandler); - ChkErr(AEInstallEventHandler, kCoreEventClass, kAEReopenApplication, - RappHandlerUPP, (SRefCon) interp, false); - - OdocHandlerUPP = NewAEEventHandlerUPP(OdocHandler); - ChkErr(AEInstallEventHandler, kCoreEventClass, kAEOpenDocuments, - OdocHandlerUPP, (SRefCon) interp, false); - - PrintHandlerUPP = NewAEEventHandlerUPP(PrintHandler); - ChkErr(AEInstallEventHandler, kCoreEventClass, kAEPrintDocuments, - PrintHandlerUPP, (SRefCon) interp, false); - - PrefsHandlerUPP = NewAEEventHandlerUPP(PrefsHandler); - ChkErr(AEInstallEventHandler, kCoreEventClass, kAEShowPreferences, - PrefsHandlerUPP, (SRefCon) interp, false); - - if (interp) { - ScriptHandlerUPP = NewAEEventHandlerUPP(ScriptHandler); - ChkErr(AEInstallEventHandler, kAEMiscStandards, kAEDoScript, - ScriptHandlerUPP, (SRefCon) interp, false); - } - } -} - -/* - *---------------------------------------------------------------------- - * - * TkMacOSXDoHLEvent -- - * - * Dispatch incomming highlevel events. - * - * Results: - * None. - * - * Side effects: - * Depends on the incoming event. - * - *---------------------------------------------------------------------- - */ - -int -TkMacOSXDoHLEvent( - void *theEvent) -{ - return AEProcessAppleEvent((EventRecord *)theEvent); -} - -/* - *---------------------------------------------------------------------- - * - * QuitHandler -- - * - * This is the 'quit' core Apple event handler. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static OSErr -QuitHandler( - const AppleEvent *event, - AppleEvent *reply, - SRefCon handlerRefcon) -{ - Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon; KillEvent *eventPtr; - if (interp) { + if (_eventInterp) { /* * Call the exit command from the event loop, since you are not * supposed to call ExitToShell in an Apple Event Handler. We put this @@ -188,233 +69,221 @@ QuitHandler( eventPtr = ckalloc(sizeof(KillEvent)); eventPtr->header.proc = ReallyKillMe; - eventPtr->interp = interp; + eventPtr->interp = _eventInterp; Tcl_QueueEvent((Tcl_Event *) eventPtr, TCL_QUEUE_HEAD); } - return noErr; } - -/* - *---------------------------------------------------------------------- - * - * OappHandler -- - * - * This is the 'oapp' core Apple event handler. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ -static OSErr -OappHandler( - const AppleEvent *event, - AppleEvent *reply, - SRefCon handlerRefcon) +- (void) handleOpenApplicationEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent { - Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon; + Tcl_Interp *interp = _eventInterp; if (interp && - Tcl_FindCommand(interp, "::tk::mac::OpenApplication", NULL, 0)){ - int code = Tcl_EvalEx(interp, "::tk::mac::OpenApplication", -1, TCL_EVAL_GLOBAL); + Tcl_FindCommand(_eventInterp, "::tk::mac::OpenApplication", NULL, 0)){ + int code = Tcl_EvalEx(_eventInterp, "::tk::mac::OpenApplication", + -1, TCL_EVAL_GLOBAL); if (code != TCL_OK) { - Tcl_BackgroundException(interp, code); + Tcl_BackgroundException(_eventInterp, code); } } - return noErr; } - -/* - *---------------------------------------------------------------------- - * - * RappHandler -- - * - * This is the 'rapp' core Apple event handler. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ -static OSErr -RappHandler( - const AppleEvent *event, - AppleEvent *reply, - SRefCon handlerRefcon) +- (void) handleReopenApplicationEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent { - Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon; +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 ProcessSerialNumber thePSN = {0, kCurrentProcess}; - OSStatus err = ChkErr(SetFrontProcess, &thePSN); - - if (interp && Tcl_FindCommand(interp, + SetFrontProcess(&thePSN); +#else + [[NSApplication sharedApplication] activateIgnoringOtherApps: YES]; +#endif + if (_eventInterp && Tcl_FindCommand(_eventInterp, "::tk::mac::ReopenApplication", NULL, 0)) { - int code = Tcl_EvalEx(interp, "::tk::mac::ReopenApplication", -1, TCL_EVAL_GLOBAL); + int code = Tcl_EvalEx(_eventInterp, "::tk::mac::ReopenApplication", + -1, TCL_EVAL_GLOBAL); if (code != TCL_OK){ - Tcl_BackgroundException(interp, code); + Tcl_BackgroundException(_eventInterp, code); } } - return err; } - -/* - *---------------------------------------------------------------------- - * - * PrefsHandler -- - * - * This is the 'pref' core Apple event handler. Called when the user - * selects 'Preferences...' in MacOS X - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ -static OSErr -PrefsHandler( - const AppleEvent *event, - AppleEvent *reply, - SRefCon handlerRefcon) +- (void) handleShowPreferencesEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent { - Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon; - - if (interp && - Tcl_FindCommand(interp, "::tk::mac::ShowPreferences", NULL, 0)){ - int code = Tcl_EvalEx(interp, "::tk::mac::ShowPreferences", -1, TCL_EVAL_GLOBAL); + if (_eventInterp && + Tcl_FindCommand(_eventInterp, "::tk::mac::ShowPreferences", NULL, 0)){ + int code = Tcl_EvalEx(_eventInterp, "::tk::mac::ShowPreferences", + -1, TCL_EVAL_GLOBAL); if (code != TCL_OK) { - Tcl_BackgroundException(interp, code); + Tcl_BackgroundException(_eventInterp, code); } } - return noErr; } - -/* - *---------------------------------------------------------------------- - * - * OdocHandler -- - * - * This is the 'odoc' core Apple event handler. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ -static OSErr -OdocHandler( - const AppleEvent *event, - AppleEvent *reply, - SRefCon handlerRefcon) +- (void) handleOpenDocumentsEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent { - Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon; - AEDescList fileSpecList; - FSRef file; - DescType type; - Size actual; - long count, index; - AEKeyword keyword; - Tcl_DString command, pathName; - int code; + tkMacOSXProcessFiles(event, replyEvent, _eventInterp, "::tk::mac::OpenDocument"); +} - /* - * Don't bother if we don't have an interp or the open document procedure - * doesn't exist. - */ +- (void) handlePrintDocumentsEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent +{ + tkMacOSXProcessFiles(event, replyEvent, _eventInterp, "::tk::mac::PrintDocument"); +} - if (!interp || - !Tcl_FindCommand(interp, "::tk::mac::OpenDocument", NULL, 0)) { - return noErr; - } +- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent +{ + OSStatus err; + const AEDesc *theDesc = nil; + DescType type = 0, initialType = 0; + Size actual; + int tclErr = -1; + char URLBuffer[1 + URL_MAX_LENGTH]; + char errString[128]; + char typeString[5]; /* - * If we get any errors while retrieving our parameters we just return with - * no error. + * The DoScript event receives one parameter that should be text data or a + * fileURL. */ - if (ChkErr(AEGetParamDesc, event, keyDirectObject, typeAEList, - &fileSpecList) != noErr) { - return noErr; + theDesc = [event aeDesc]; + if (theDesc == nil) { + return; } - if (MissedAnyParameters(event) != noErr) { - return noErr; + + err = AEGetParamPtr(theDesc, keyDirectObject, typeWildCard, &initialType, + NULL, 0, NULL); + if (err != noErr) { + sprintf(errString, "AEDoScriptHandler: GetParamDesc error %d", (int)err); + AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar, + errString, strlen(errString)); + return; } - if (ChkErr(AECountItems, &fileSpecList, &count) != noErr) { - return noErr; + + if (MissedAnyParameters((AppleEvent*)theDesc)) { + sprintf(errString, "AEDoScriptHandler: extra parameters"); + AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar, + errString, strlen(errString)); + return; } - /* - * Convert our parameters into a script to evaluate, skipping things that - * we can't handle right. - */ - - Tcl_DStringInit(&command); - Tcl_DStringAppend(&command, "::tk::mac::OpenDocument", -1); - for (index = 1; index <= count; index++) { - if (ChkErr(AEGetNthPtr, &fileSpecList, index, typeFSRef, &keyword, - &type, (Ptr) &file, sizeof(FSRef), &actual) != noErr) { - continue; + if (initialType == typeFileURL || initialType == typeAlias) { + /* + * The descriptor can be coerced to a file url. Source the file, or + * pass the path as a string argument to ::tk::mac::DoScriptFile if + * that procedure exists. + */ + err = AEGetParamPtr(theDesc, keyDirectObject, typeFileURL, &type, + (Ptr) URLBuffer, URL_MAX_LENGTH, &actual); + if (err == noErr && actual > 0){ + URLBuffer[actual] = '\0'; + NSString *urlString = [NSString stringWithUTF8String:(char*)URLBuffer]; + NSURL *fileURL = [NSURL URLWithString:urlString]; + Tcl_DString command; + Tcl_DStringInit(&command); + if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptFile", NULL, 0)){ + Tcl_DStringAppend(&command, "::tk::mac::DoScriptFile", -1); + } else { + Tcl_DStringAppend(&command, "source", -1); + } + Tcl_DStringAppendElement(&command, [[fileURL path] UTF8String]); + tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command), + Tcl_DStringLength(&command), TCL_EVAL_GLOBAL); } - - if (ChkErr(FSRefToDString, &file, &pathName) == noErr) { - Tcl_DStringAppendElement(&command, Tcl_DStringValue(&pathName)); - Tcl_DStringFree(&pathName); + } else if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type, + NULL, 0, &actual)) { + if (actual > 0) { + /* + * The descriptor can be coerced to UTF8 text. Evaluate as Tcl, or + * or pass the text as a string argument to ::tk::mac::DoScriptText + * if that procedure exists. + */ + char *data = ckalloc(actual + 1); + if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type, + data, actual, NULL)) { + if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptText", NULL, 0)){ + Tcl_DString command; + Tcl_DStringInit(&command); + Tcl_DStringAppend(&command, "::tk::mac::DoScriptText", -1); + Tcl_DStringAppendElement(&command, data); + tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command), + Tcl_DStringLength(&command), TCL_EVAL_GLOBAL); + } else { + tclErr = Tcl_EvalEx(_eventInterp, data, actual, TCL_EVAL_GLOBAL); + } + } + ckfree(data); + } + } else { + /* + * The descriptor can not be coerced to a fileURL or UTF8 text. + */ + for (int i = 0; i < 4; i++) { + typeString[i] = ((char*)&initialType)[3-i]; } + typeString[4] = '\0'; + sprintf(errString, "AEDoScriptHandler: invalid script type '%s', " + "must be coercable to 'furl' or 'utf8'", typeString); + AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar, errString, + strlen(errString)); } - /* - * Now handle the event by evaluating a script. + * If we ran some Tcl code, put the result in the reply. */ - - code = Tcl_EvalEx(interp, Tcl_DStringValue(&command), - Tcl_DStringLength(&command), TCL_EVAL_GLOBAL); - if (code != TCL_OK) { - Tcl_BackgroundException(interp, code); + if (tclErr >= 0) { + int reslen; + const char *result = + Tcl_GetStringFromObj(Tcl_GetObjResult(_eventInterp), &reslen); + if (tclErr == TCL_OK) { + AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyDirectObject, typeChar, + result, reslen); + } else { + AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar, + result, reslen); + AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorNumber, typeSInt32, + (Ptr) &tclErr,sizeof(int)); + } } - Tcl_DStringFree(&command); - return noErr; + return; } - +@end + +#pragma mark - + /* *---------------------------------------------------------------------- * - * PrintHandler -- + * TkMacOSXProcessFiles -- * - * This is the 'pdoc' core Apple event handler. + * Extract a list of fileURLs from an AppleEvent and call the specified + * procedure with the file paths as arguments. * * Results: * None. * * Side effects: - * None. + * The event is handled by running the procedure. * *---------------------------------------------------------------------- */ -static OSErr -PrintHandler( - const AppleEvent * event, - AppleEvent * reply, - SRefCon handlerRefcon) +static void +tkMacOSXProcessFiles( + NSAppleEventDescriptor* event, + NSAppleEventDescriptor* replyEvent, + Tcl_Interp *interp, + char* procedure) { - Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon; - AEDescList fileSpecList; - FSRef file; + Tcl_Encoding utf8 = Tcl_GetEncoding(NULL, "utf-8"); + const AEDesc *fileSpecDesc = nil; + AEDesc contents; + char URLString[1 + URL_MAX_LENGTH]; + NSURL *fileURL; DescType type; Size actual; long count, index; @@ -423,47 +292,67 @@ PrintHandler( int code; /* - * Don't bother if we don't have an interp or the print document procedure - * doesn't exist. + * Do nothing if we don't have an interpreter or the procedure doesn't exist. */ - if (!interp || - !Tcl_FindCommand(interp, "::tk::mac::PrintDocument", NULL, 0)) { - return noErr; + if (!interp || !Tcl_FindCommand(interp, procedure, NULL, 0)) { + return; } - + + fileSpecDesc = [event aeDesc]; + if (fileSpecDesc == nil ) { + return; + } + /* - * If we get any errors while retrieving our parameters we just return with - * no error. + * The AppleEvent's descriptor should either contain a value of + * typeObjectSpecifier or typeAEList. In the first case, the descriptor + * can be treated as a list of size 1 containing a value which can be + * coerced into a fileURL. In the second case we want to work with the list + * itself. Values in the list will be coerced into fileURL's if possible; + * otherwise they will be ignored. */ - - if (ChkErr(AEGetParamDesc, event, keyDirectObject, typeAEList, - &fileSpecList) != noErr) { - return noErr; - } - if (ChkErr(MissedAnyParameters, event) != noErr) { - return noErr; + + /* Get a copy of the AppleEvent's descriptor. */ + AEGetParamDesc(fileSpecDesc, keyDirectObject, typeWildCard, &contents); + if (contents.descriptorType == typeAEList) { + fileSpecDesc = &contents; } - if (ChkErr(AECountItems, &fileSpecList, &count) != noErr) { - return noErr; + + if (AECountItems(fileSpecDesc, &count) != noErr) { + AEDisposeDesc(&contents); + return; } - + + /* + * Construct a Tcl command which calls the procedure, passing the + * paths contained in the AppleEvent as arguments. + */ + Tcl_DStringInit(&command); - Tcl_DStringAppend(&command, "::tk::mac::PrintDocument", -1); + Tcl_DStringAppend(&command, procedure, -1); + for (index = 1; index <= count; index++) { - if (ChkErr(AEGetNthPtr, &fileSpecList, index, typeFSRef, &keyword, - &type, (Ptr) &file, sizeof(FSRef), &actual) != noErr) { + if (noErr != AEGetNthPtr(fileSpecDesc, index, typeFileURL, &keyword, + &type, (Ptr) URLString, URL_MAX_LENGTH, &actual)) { continue; } - - if (ChkErr(FSRefToDString, &file, &pathName) == noErr) { - Tcl_DStringAppendElement(&command, Tcl_DStringValue(&pathName)); - Tcl_DStringFree(&pathName); + if (type != typeFileURL) { + continue; + } + URLString[actual] = '\0'; + fileURL = [NSURL URLWithString:[NSString stringWithUTF8String:(char*)URLString]]; + if (fileURL == nil) { + continue; } + Tcl_ExternalToUtfDString(utf8, [[fileURL path] UTF8String], -1, &pathName); + Tcl_DStringAppendElement(&command, Tcl_DStringValue(&pathName)); + Tcl_DStringFree(&pathName); } + AEDisposeDesc(&contents); /* - * Now handle the event by evaluating a script. + * Handle the event by evaluating the Tcl expression we constructed. */ code = Tcl_EvalEx(interp, Tcl_DStringValue(&command), @@ -472,18 +361,19 @@ PrintHandler( Tcl_BackgroundException(interp, code); } Tcl_DStringFree(&command); - return noErr; + return; } /* *---------------------------------------------------------------------- * - * ScriptHandler -- + * TkMacOSXInitAppleEvents -- * - * This handler process the script event. + * Register AppleEvent handlers with the NSAppleEventManager for + * this NSApplication. * * Results: - * Schedules the given event to be processed. + * None. * * Side effects: * None. @@ -491,112 +381,91 @@ PrintHandler( *---------------------------------------------------------------------- */ -static OSErr -ScriptHandler( - const AppleEvent *event, - AppleEvent *reply, - SRefCon handlerRefcon) +void +TkMacOSXInitAppleEvents( + Tcl_Interp *interp) /* not used */ { - OSStatus theErr; - AEDescList theDesc; - Size size; - int tclErr = -1; - Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon; - char errString[128]; + NSAppleEventManager *aeManager = [NSAppleEventManager sharedAppleEventManager]; + static Boolean initialized = FALSE; - /* - * The do script event receives one parameter that should be data or a - * file. - */ + if (!initialized) { + initialized = TRUE; - theErr = AEGetParamDesc(event, keyDirectObject, typeWildCard, - &theDesc); - if (theErr != noErr) { - sprintf(errString, "AEDoScriptHandler: GetParamDesc error %d", - (int)theErr); - theErr = AEPutParamPtr(reply, keyErrorString, typeChar, errString, - strlen(errString)); - } else if (MissedAnyParameters(event)) { - /* - * Return error if parameter is missing. - */ + [aeManager setEventHandler:NSApp + andSelector:@selector(handleQuitApplicationEvent:withReplyEvent:) + forEventClass:kCoreEventClass andEventID:kAEQuitApplication]; - sprintf(errString, "AEDoScriptHandler: extra parameters"); - AEPutParamPtr(reply, keyErrorString, typeChar, errString, - strlen(errString)); - theErr = -1771; - } else if (theDesc.descriptorType == (DescType) typeAlias && - AEGetParamPtr(event, keyDirectObject, typeFSRef, NULL, NULL, - 0, &size) == noErr && size == sizeof(FSRef)) { - /* - * We've had a file sent to us. Source it. - */ + [aeManager setEventHandler:NSApp + andSelector:@selector(handleOpenApplicationEvent:withReplyEvent:) + forEventClass:kCoreEventClass andEventID:kAEOpenApplication]; - FSRef file; - theErr = AEGetParamPtr(event, keyDirectObject, typeFSRef, NULL, &file, - size, NULL); - if (theErr == noErr) { - Tcl_DString scriptName; + [aeManager setEventHandler:NSApp + andSelector:@selector(handleReopenApplicationEvent:withReplyEvent:) + forEventClass:kCoreEventClass andEventID:kAEReopenApplication]; - theErr = FSRefToDString(&file, &scriptName); - if (theErr == noErr) { - Tcl_Obj *pathName = - Tcl_NewStringObj(Tcl_DStringValue(&scriptName), -1); - Tcl_DStringFree(&scriptName); + [aeManager setEventHandler:NSApp + andSelector:@selector(handleShowPreferencesEvent:withReplyEvent:) + forEventClass:kCoreEventClass andEventID:kAEShowPreferences]; - tclErr = Tcl_FSEvalFile(interp, pathName); - Tcl_DecrRefCount(pathName); - } else { - sprintf(errString, "AEDoScriptHandler: file not found"); - AEPutParamPtr(reply, keyErrorString, typeChar, errString, - strlen(errString)); - } - } - } else if (AEGetParamPtr(event, keyDirectObject, typeUTF8Text, NULL, NULL, - 0, &size) == noErr && size) { - /* - * We've had some data sent to us. Evaluate it. - */ + [aeManager setEventHandler:NSApp + andSelector:@selector(handleOpenDocumentsEvent:withReplyEvent:) + forEventClass:kCoreEventClass andEventID:kAEOpenDocuments]; - char *data = ckalloc(size + 1); - theErr = AEGetParamPtr(event, keyDirectObject, typeUTF8Text, NULL, data, - size, NULL); - if (theErr == noErr) { - tclErr = Tcl_EvalEx(interp, data, size, TCL_EVAL_GLOBAL); - } - } else { - /* - * Umm, don't recognize what we've got... - */ + [aeManager setEventHandler:NSApp + andSelector:@selector(handleOpenDocumentsEvent:withReplyEvent:) + forEventClass:kCoreEventClass andEventID:kAEPrintDocuments]; - sprintf(errString, "AEDoScriptHandler: invalid script type '%-4.4s', " - "must be 'alis' or coercable to 'utf8'", - (char*) &theDesc.descriptorType); - AEPutParamPtr(reply, keyErrorString, typeChar, errString, - strlen(errString)); - theErr = -1770; + [aeManager setEventHandler:NSApp + andSelector:@selector(handleDoScriptEvent:withReplyEvent:) + forEventClass:kAEMiscStandards andEventID:kAEDoScript]; } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXDoHLEvent -- + * + * Dispatch an AppleEvent. + * + * Results: + * None. + * + * Side effects: + * Depend on the AppleEvent. + * + *---------------------------------------------------------------------- + */ - /* - * If we actually go to run Tcl code - put the result in the reply. +int +TkMacOSXDoHLEvent( + void *theEvent) +{ + /* According to the NSAppleEventManager reference: + * "The theReply parameter always specifies a reply Apple event, never + * nil. However, the handler should not fill out the reply if the + * descriptor type for the reply event is typeNull, indicating the sender + * does not want a reply." + * The specified way to build such a non-nil descriptor is used here. But + * on OSX 10.11, the compiler nonetheless generates a warning. I am + * supressing the warning here -- maybe the warnings will stop in a future + * compiler release. */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" +#endif - if (tclErr >= 0) { - int reslen; - const char *result = - Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &reslen); + NSAppleEventDescriptor* theReply = [NSAppleEventDescriptor nullDescriptor]; + NSAppleEventManager *aeManager = [NSAppleEventManager sharedAppleEventManager]; - if (tclErr == TCL_OK) { - AEPutParamPtr(reply, keyDirectObject, typeChar, result, reslen); - } else { - AEPutParamPtr(reply, keyErrorString, typeChar, result, reslen); - AEPutParamPtr(reply, keyErrorNumber, typeSInt32, (Ptr) &tclErr, - sizeof(int)); - } - } + return [aeManager dispatchRawAppleEvent:(const AppleEvent*)theEvent + withRawReply: (AppleEvent *)theReply + handlerRefCon: (SRefCon)0]; - AEDisposeDesc(&theDesc); - return theErr; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif } /* @@ -604,8 +473,8 @@ ScriptHandler( * * ReallyKillMe -- * - * This proc tries to kill the shell by running exit, called from an - * event scheduled by the "Quit" AppleEvent handler. + * This procedure tries to kill the shell by running exit, called from + * an event scheduled by the "Quit" AppleEvent handler. * * Results: * Runs the "exit" command which might kill the shell. @@ -665,37 +534,7 @@ MissedAnyParameters( return (err != errAEDescNotFound); } -/* - *---------------------------------------------------------------------- - * - * FSRefToDString -- - * - * Get a POSIX path from an FSRef. - * - * Results: - * In the parameter ds. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static OSStatus -FSRefToDString( - const FSRef *fsref, - Tcl_DString *ds) -{ - UInt8 fileName[PATH_MAX+1]; - OSStatus err; - err = ChkErr(FSRefMakePath, fsref, fileName, sizeof(fileName)); - if (err == noErr) { - Tcl_ExternalToUtfDString(NULL, (char*) fileName, -1, ds); - } - return err; -} - /* * Local Variables: * mode: objc diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index ed22640..0c078ce 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -792,7 +792,7 @@ TkpPostMenu( NSRect frame = NSMakeRect(x + 9, tkMacOSXZeroScreenHeight - y - 9, 1, 1); frame.origin = [view convertPoint: - [win convertScreenToBase:frame.origin] fromView:nil]; + [win convertPointFromScreen:frame.origin] fromView:nil]; NSMenu *menu = (NSMenu *) menuPtr->platformData; NSPopUpButtonCell *popUpButtonCell = [[NSPopUpButtonCell alloc] diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 1fdbc52..c4197f7 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -26,49 +26,7 @@ typedef struct { static int GenerateButtonEvent(MouseEventData *medPtr); static unsigned int ButtonModifiers2State(UInt32 buttonState, - UInt32 keyModifiers); - -#pragma mark NSWindow(TKMouseEvent) - -/* Conversion of coordinates between window and screen */ -@interface NSWindow(TKWm) -- (NSPoint) convertPointToScreen:(NSPoint)point; -- (NSPoint) convertPointFromScreen:(NSPoint)point; -@end - -@implementation NSWindow(TKMouseEvent) -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 -- (NSPoint) convertPointToScreen: (NSPoint) point -{ - return [self convertBaseToScreen:point]; -} -- (NSPoint) convertPointFromScreen: (NSPoint)point -{ - return [self convertScreenToBase:point]; -} -@end -#else -- (NSPoint) convertPointToScreen: (NSPoint) point -{ - NSRect pointrect; - pointrect.origin = point; - pointrect.size.width = 0; - pointrect.size.height = 0; - return [self convertRectToScreen:pointrect].origin; -} -- (NSPoint) convertPointFromScreen: (NSPoint)point -{ - NSRect pointrect; - pointrect.origin = point; - pointrect.size.width = 0; - pointrect.size.height = 0; - return [self convertRectFromScreen:pointrect].origin; -} -@end -#endif - -#pragma mark - - + UInt32 keyModifiers); #pragma mark TKApplication(TKMouseEvent) @@ -77,14 +35,12 @@ enum { }; /* * In OS X 10.6 an NSEvent of type NSMouseMoved would always have a non-Nil - * window attribute when the mouse was inside a window. As of 10.8 this - * behavior had changed. The new behavior was that if the mouse were ever - * moved outside of a window, all subsequent NSMouseMoved NSEvents would have a - * Nil window attribute. To work around this we remember which window the - * mouse is in by saving the window attribute of each NSEvent of type - * NSMouseEntered. If an NSEvent has a Nil window attribute we use our saved - * window. It may be the case that the mouse has actually left the window, but - * this is harmless since Tk will ignore the event in that case. + * window attribute pointing to the active window. As of 10.8 this behavior + * had changed. The new behavior was that if the mouse were ever moved outside + * of a window, all subsequent NSMouseMoved NSEvents would have a Nil window + * attribute. To work around this the TKApplication remembers the last non-Nil + * window that it received in a mouse event. If it receives an NSEvent with a + * Nil window attribute then the saved window is used. */ @implementation TKApplication(TKMouseEvent) @@ -93,24 +49,14 @@ enum { #ifdef TK_MAC_DEBUG_EVENTS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent); #endif - id win; - NSEventType type = [theEvent type]; + NSWindow* eventWindow = [theEvent window]; + NSEventType eventType = [theEvent type]; #if 0 NSTrackingArea *trackingArea = nil; NSInteger eventNumber, clickCount, buttonNumber; #endif - - switch (type) { + switch (eventType) { case NSMouseEntered: - /* Remember which window has the mouse. */ - if (_windowWithMouse) { - [_windowWithMouse release]; - } - _windowWithMouse = [theEvent window]; - if (_windowWithMouse) { - [_windowWithMouse retain]; - } - break; case NSMouseExited: case NSCursorUpdate: case NSLeftMouseDown: @@ -127,25 +73,31 @@ enum { case NSTabletProximity: case NSScrollWheel: break; - default: /* Unrecognized mouse event. */ return theEvent; } + /* Remember the window in case we need it next time. */ + if (eventWindow && eventWindow != _windowWithMouse) { + if (_windowWithMouse) { + [_windowWithMouse release]; + } + _windowWithMouse = eventWindow; + [_windowWithMouse retain]; + } + /* Create an Xevent to add to the Tk queue. */ - win = [theEvent window]; - NSWindow *nswindow = (NSWindow *)win; NSPoint global, local = [theEvent locationInWindow]; - if (win) { /* local will be in window coordinates. */ - global = [nswindow convertPointToScreen: local]; - local.y = [win frame].size.height - local.y; + if (eventWindow) { /* local will be in window coordinates. */ + global = [eventWindow convertPointToScreen: local]; + local.y = [eventWindow frame].size.height - local.y; global.y = tkMacOSXZeroScreenHeight - global.y; } else { /* local will be in screen coordinates. */ if (_windowWithMouse ) { - win = _windowWithMouse; + eventWindow = _windowWithMouse; global = local; - local = [nswindow convertPointFromScreen: local]; - local.y = [win frame].size.height - local.y; + local = [eventWindow convertPointFromScreen: local]; + local.y = [eventWindow frame].size.height - local.y; global.y = tkMacOSXZeroScreenHeight - global.y; } else { /* We have no window. Use the screen???*/ local.y = tkMacOSXZeroScreenHeight - local.y; @@ -153,7 +105,7 @@ enum { } } - Window window = TkMacOSXGetXWindow(win); + Window window = TkMacOSXGetXWindow(eventWindow); Tk_Window tkwin = window ? Tk_IdToWindow(TkGetDisplayList()->display, window) : NULL; if (!tkwin) { @@ -181,7 +133,7 @@ enum { if (err == noErr) { state |= (buttons & ((1<<5) - 1)) << 8; } else if (button < 5) { - switch (type) { + switch (eventType) { case NSLeftMouseDown: case NSRightMouseDown: case NSLeftMouseDragged: @@ -218,12 +170,12 @@ enum { state |= Mod4Mask; } - if (type != NSScrollWheel) { + if (eventType != NSScrollWheel) { #ifdef TK_MAC_DEBUG_EVENTS TKLog(@"UpdatePointer %p x %f.0 y %f.0 %d", tkwin, global.x, global.y, state); #endif Tk_UpdatePointer(tkwin, global.x, global.y, state); - } else { + } else { /* handle scroll wheel event */ CGFloat delta; int coarseDelta; XEvent xEvent; @@ -239,7 +191,8 @@ enum { delta = [theEvent deltaY]; if (delta != 0.0) { - coarseDelta = (delta > -1.0 && delta < 1.0) ? (signbit(delta) ? -1 : 1) : lround(delta); + coarseDelta = (delta > -1.0 && delta < 1.0) ? + (signbit(delta) ? -1 : 1) : lround(delta); xEvent.xbutton.state = state; xEvent.xkey.keycode = coarseDelta; xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); @@ -247,7 +200,8 @@ enum { } delta = [theEvent deltaX]; if (delta != 0.0) { - coarseDelta = (delta > -1.0 && delta < 1.0) ? (signbit(delta) ? -1 : 1) : lround(delta); + coarseDelta = (delta > -1.0 && delta < 1.0) ? + (signbit(delta) ? -1 : 1) : lround(delta); xEvent.xbutton.state = state | ShiftMask; xEvent.xkey.keycode = coarseDelta; xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); @@ -418,7 +372,7 @@ XQueryPointer( if (win) { NSPoint local; - local = [win convertScreenToBase:global]; + local = [win convertPointFromScreen:global]; local.y = [win frame].size.height - local.y; if (macWin->winPtr && macWin->winPtr->wmInfoPtr) { local.x -= macWin->winPtr->wmInfoPtr->xInParent; @@ -516,7 +470,7 @@ TkGenerateButtonEvent( if (win) { NSPoint local = NSMakePoint(x, tkMacOSXZeroScreenHeight - y); - local = [win convertScreenToBase:local]; + local = [win convertPointFromScreen:local]; local.y = [win frame].size.height - local.y; if (macWin->winPtr && macWin->winPtr->wmInfoPtr) { local.x -= macWin->winPtr->wmInfoPtr->xInParent; diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 9cdc27c..d0a52ee 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -296,6 +296,24 @@ VISIBILITY_HIDDEN - (void)tkProvidePasteboard:(TkDisplay *)dispPtr; - (void)tkCheckPasteboard; @end +@interface TKApplication(TKHLEvents) +- (void) terminate: (id) sender; +- (void) preferences: (id) sender; +- (void) handleQuitApplicationEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent; +- (void) handleOpenApplicationEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent; +- (void) handleReopenApplicationEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent; +- (void) handleShowPreferencesEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent; +- (void) handleOpenDocumentsEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent; +- (void) handlePrintDocumentsEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent; +- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event + withReplyEvent: (NSAppleEventDescriptor *)replyEvent; +@end VISIBILITY_HIDDEN @interface TKContentView : NSView { @@ -329,6 +347,11 @@ VISIBILITY_HIDDEN @interface TKWindow : NSWindow @end +@interface NSWindow(TKWm) +- (NSPoint) convertPointToScreen:(NSPoint)point; +- (NSPoint) convertPointFromScreen:(NSPoint)point; +@end + #pragma mark NSMenu & NSMenuItem Utilities @interface NSMenu(TKUtils) @@ -357,8 +380,4 @@ VISIBILITY_HIDDEN keyEquivalentModifierMask:(NSUInteger)keyEquivalentModifierMask; @end -/* Helper functions from tkMacOSXDeprecations.c */ - -extern NSPoint convertWindowToScreen( NSWindow *window, NSPoint point); - #endif /* _TKMACPRIV */ diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 7f1cf90..851358d 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -745,15 +745,16 @@ TkWmProtocolEventProc( int Tk_MacOSXIsAppInFront(void) { - OSStatus err; - ProcessSerialNumber frontPsn, ourPsn = {0, kCurrentProcess}; Boolean isFrontProcess = true; +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + ProcessSerialNumber frontPsn, ourPsn = {0, kCurrentProcess}; - err = ChkErr(GetFrontProcess, &frontPsn); - if (err == noErr) { - ChkErr(SameProcess, &frontPsn, &ourPsn, &isFrontProcess); + if (noErr == GetFrontProcess(&frontPsn)){ + SameProcess(&frontPsn, &ourPsn, &isFrontProcess); } - +#else + isFrontProcess = [NSRunningApplication currentApplication].active; +#endif return (isFrontProcess == true); } diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 417f130..fb58904 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -196,6 +196,48 @@ static int tkMacOSXWmAttrNotifyVal = 0; static Tcl_HashTable windowTable; static int windowHashInit = false; + + +#pragma mark NSWindow(TKWm) + +/* + * Conversion of coordinates between window and screen. + */ + +@implementation NSWindow(TKWm) +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 +- (NSPoint) convertPointToScreen: (NSPoint) point +{ + return [self convertBaseToScreen:point]; +} +- (NSPoint) convertPointFromScreen: (NSPoint)point +{ + return [self convertScreenToBase:point]; +} +@end +#else +- (NSPoint) convertPointToScreen: (NSPoint) point +{ + NSRect pointrect; + pointrect.origin = point; + pointrect.size.width = 0; + pointrect.size.height = 0; + return [self convertRectToScreen:pointrect].origin; +} +- (NSPoint) convertPointFromScreen: (NSPoint)point +{ + NSRect pointrect; + pointrect.origin = point; + pointrect.size.width = 0; + pointrect.size.height = 0; + return [self convertRectFromScreen:pointrect].origin; +} +@end +#endif + +#pragma mark - + + /* * Forward declarations for procedures defined in this file: */ diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c index a5f1c60..e87bb39 100644 --- a/macosx/tkMacOSXXStubs.c +++ b/macosx/tkMacOSXXStubs.c @@ -181,7 +181,21 @@ TkpOpenDisplay( NSAppKitVersionNumber); } display->vendor = vendor; - Gestalt(gestaltSystemVersion, (SInt32 *) &display->release); + { + int major, minor, patch; + +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 + Gestalt(gestaltSystemVersionMajor, (SInt32*)&major); + Gestalt(gestaltSystemVersionMinor, (SInt32*)&minor); + Gestalt(gestaltSystemVersionBugFix, (SInt32*)&patch); +#else + NSOperatingSystemVersion systemVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; + major = systemVersion.majorVersion; + minor = systemVersion.minorVersion; + patch = systemVersion.patchVersion; +#endif + display->release = major << 16 | minor << 8 | patch; + } /* * These screen bits never change -- cgit v0.12 -- cgit v0.12 From c1b04b28e254278324baf30b73f1400b4fec2f5d Mon Sep 17 00:00:00 2001 From: fvogel Date: Wed, 25 Nov 2015 07:22:53 +0000 Subject: Ooops... removed debug traces unintentionally left in the merge mark... --- generic/tkText.c | 8 -------- generic/tkTextDisp.c | 35 +---------------------------------- 2 files changed, 1 insertion(+), 42 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index dfcd294..4edf652 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -35,10 +35,6 @@ #include "tkText.h" -#define LOG(toVar,what) \ - Tcl_SetVar2(textPtr->interp, toVar, NULL, (what), \ - TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT) - /* * Used to avoid having to allocate and deallocate arrays on the fly for * commonly used functions. Must be > 0. @@ -608,9 +604,7 @@ CreateWidget( TkTextCreateDInfo(textPtr); TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, 0, 0, &startIndex); -LOG("debug", "In createWidget, before"); TkTextSetYView(textPtr, &startIndex, 0); -LOG("debug", "In createWidget, after"); textPtr->exportSelection = 1; textPtr->pickEvent.type = LeaveNotify; textPtr->undo = textPtr->sharedTextPtr->undo; @@ -2658,9 +2652,7 @@ InsertChars( lineAndByteIndex[resetViewCount], 0, &newTop); TkTextIndexForwBytes(tPtr, &newTop, lineAndByteIndex[resetViewCount+1], &newTop); -LOG("debug", "In InsertChars, before"); TkTextSetYView(tPtr, &newTop, 0); -LOG("debug", "In InsertChars, after"); } } resetViewCount += 2; diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 722a137..02666d0 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -5088,14 +5088,12 @@ TkTextSetYView( int bottomY, close, lineIndex; TkTextIndex tmpIndex, rounded; int lineHeight; -char buffer[3 * TCL_INTEGER_SPACE + 1]; /* * If the specified position is the extra line at the end of the text, * round it back to the last real line. */ -LOG("debug", "\nENTERING TkTextSetYView"); lineIndex = TkBTreeLinesTo(textPtr, indexPtr->linePtr); if (lineIndex == TkBTreeNumLines(indexPtr->tree, textPtr)) { TkTextIndexBackChars(textPtr, indexPtr, 1, &rounded, COUNT_INDICES); @@ -5138,10 +5136,7 @@ LOG("debug", "\nENTERING TkTextSetYView"); } dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr); if (dlPtr != NULL) { -LOG("debug", "It's on screen"); -sprintf(buffer, "dlPtr->y: %d dlPtr->height: %d dInfoPtr->maxY: %d", dlPtr->y, dlPtr->height, dInfoPtr->maxY); -LOG("debug", buffer); - if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) { + if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) { /* * Part of the line hangs off the bottom of the screen; pretend * the whole line is off-screen. @@ -5149,10 +5144,6 @@ LOG("debug", buffer); dlPtr = NULL; } else { -TkTextPrintIndex(textPtr, &dlPtr->index, buffer); -LOG("debug", buffer); -TkTextPrintIndex(textPtr, indexPtr, buffer); -LOG("debug", buffer); if (TkTextIndexCmp(&dlPtr->index, indexPtr) <= 0) { if (dInfoPtr->dLinePtr == dlPtr && dInfoPtr->topPixelOffset != 0) { /* @@ -5176,16 +5167,9 @@ LOG("debug", buffer); * If the line is not close, place it in the center of the window. */ -LOG("debug", "Not yet on screen"); tmpIndex = *indexPtr; -TkTextPrintIndex(textPtr, &tmpIndex, buffer); -LOG("debug", buffer); TkTextFindDisplayLineEnd(textPtr, &tmpIndex, 0, NULL); -TkTextPrintIndex(textPtr, &tmpIndex, buffer); -LOG("debug", buffer); lineHeight = CalculateDisplayLineHeight(textPtr, &tmpIndex, NULL, NULL); - sprintf(buffer, "lineHeight: %d", lineHeight); -LOG("debug", buffer); /* * It would be better if 'bottomY' were calculated using the actual height @@ -5194,14 +5178,11 @@ LOG("debug", buffer); bottomY = (dInfoPtr->y + dInfoPtr->maxY + lineHeight)/2; close = (dInfoPtr->maxY - dInfoPtr->y)/3; -sprintf(buffer, "bottomY: %d close: %d", bottomY, close); -LOG("debug", buffer); if (close < 3*textPtr->charHeight) { close = 3*textPtr->charHeight; } if (dlPtr != NULL) { int overlap; -LOG("debug", "Above the top of the screen"); /* * The desired line is above the top of screen. If it is "close" to @@ -5220,7 +5201,6 @@ LOG("debug", "Above the top of the screen"); } } else { int overlap; -LOG("debug", "Below the top of the screen"); /* * The desired line is below the bottom of the screen. If it is @@ -5230,14 +5210,8 @@ LOG("debug", "Below the top of the screen"); MeasureUp(textPtr, indexPtr, close + lineHeight - textPtr->charHeight/2, &tmpIndex, &overlap); -TkTextPrintIndex(textPtr, &tmpIndex, buffer); -LOG("debug", buffer); -sprintf(buffer, "overlap: %d", overlap); -LOG("debug", buffer); if (FindDLine(textPtr, dInfoPtr->dLinePtr, &tmpIndex) != NULL) { bottomY = dInfoPtr->maxY - dInfoPtr->y; -sprintf(buffer, "New bottomY: %d", bottomY); -LOG("debug", buffer); } } @@ -5249,15 +5223,8 @@ LOG("debug", buffer); * of the window. */ -TkTextPrintIndex(textPtr, indexPtr, buffer); -LOG("debug", buffer); MeasureUp(textPtr, indexPtr, bottomY, &textPtr->topIndex, &dInfoPtr->newTopPixelOffset); -//dInfoPtr->newTopPixelOffset = 0; -TkTextPrintIndex(textPtr, &textPtr->topIndex, buffer); -LOG("debug", buffer); -sprintf(buffer, "newTopPixelOffset: %d", dInfoPtr->newTopPixelOffset); -LOG("debug", buffer); scheduleUpdate: if (!(dInfoPtr->flags & REDRAW_PENDING)) { -- cgit v0.12 From 6aad9c9b454d5334c3e36cd2bf623dae8369defe Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Mon, 7 Dec 2015 02:02:44 +0000 Subject: Fix for zombie windows on El Capitan/OS X 10.11; thanks to Marc Culler for patch --- macosx/tkMacOSXDialog.c | 2 +- macosx/tkMacOSXDraw.c | 16 ++++++++++++---- macosx/tkMacOSXInit.c | 6 +----- macosx/tkMacOSXNotify.c | 3 ++- macosx/tkMacOSXSubwindows.c | 3 ++- macosx/tkMacOSXWm.c | 46 ++++++++++++++++++++++++++++++++++++++++----- macosx/tkMacOSXXStubs.c | 7 ++++--- 7 files changed, 63 insertions(+), 20 deletions(-) diff --git a/macosx/tkMacOSXDialog.c b/macosx/tkMacOSXDialog.c index ca17195..0889ee5 100644 --- a/macosx/tkMacOSXDialog.c +++ b/macosx/tkMacOSXDialog.c @@ -1161,7 +1161,7 @@ Tk_MessageBoxObjCmd( [NSApp tkAlertDidEnd:alert returnCode:modalReturnCode contextInfo:callbackInfo]; } - result = (modalReturnCode < 1) ? TCL_OK : TCL_ERROR; + result = (modalReturnCode >= NSAlertFirstButtonReturn) ? TCL_OK : TCL_ERROR; end: [alert release]; return result; diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index ed8c428..bcc7afe 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -138,6 +138,7 @@ BitmapRepFromDrawableRect( CGImageRef cg_image=NULL, sub_cg_image=NULL; NSBitmapImageRep *bitmap_rep=NULL; NSView *view=NULL; + NSAutoreleasePool *pool = [NSAutoreleasePool new]; if ( mac_drawable->flags & TK_IS_PIXMAP ) { /* This means that the MacDrawable is functioning as a Tk Pixmap, so its view @@ -174,6 +175,7 @@ BitmapRepFromDrawableRect( } else { TkMacOSXDbgMsg("Invalid source drawable"); } + [pool drain]; return bitmap_rep; } @@ -1568,7 +1570,6 @@ TkScrollWindow( /* Belt and suspenders: make the AppKit request a redraw when it gets control again. */ - [view setNeedsDisplay:YES]; } } else { dmgRgn = HIShapeCreateEmpty(); @@ -1635,6 +1636,7 @@ TkMacOSXSetupDrawingContext( int dontDraw = 0, isWin = 0; TkMacOSXDrawingContext dc = {}; CGRect clipBounds; + NSAutoreleasePool *pool = [NSAutoreleasePool new]; dc.clipRgn = TkMacOSXGetClipRgn(d); if (!dontDraw) { @@ -1765,6 +1767,7 @@ end: dc.clipRgn = NULL; } *dcPtr = dc; + [pool drain]; return !dontDraw; } @@ -1788,6 +1791,7 @@ void TkMacOSXRestoreDrawingContext( TkMacOSXDrawingContext *dcPtr) { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; if (dcPtr->context) { CGContextSynchronize(dcPtr->context); [[dcPtr->view window] setViewsNeedDisplay:YES]; @@ -1804,6 +1808,7 @@ TkMacOSXRestoreDrawingContext( #ifdef TK_MAC_DEBUG bzero(dcPtr, sizeof(TkMacOSXDrawingContext)); #endif /* TK_MAC_DEBUG */ + [pool drain]; } /* @@ -1829,7 +1834,8 @@ TkMacOSXGetClipRgn( { MacDrawable *macDraw = (MacDrawable *) drawable; HIShapeRef clipRgn = NULL; - + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) { TkMacOSXUpdateClipRgn(macDraw->winPtr); #ifdef TK_MAC_DEBUG_DRAWING @@ -1854,7 +1860,7 @@ TkMacOSXGetClipRgn( } else if (macDraw->visRgn) { clipRgn = HIShapeCreateCopy(macDraw->visRgn); } - + [pool drain]; return clipRgn; } @@ -1907,7 +1913,8 @@ TkpClipDrawableToRect( { MacDrawable *macDraw = (MacDrawable *) d; NSView *view = TkMacOSXDrawableView(macDraw); - + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + if (macDraw->drawRgn) { CFRelease(macDraw->drawRgn); macDraw->drawRgn = NULL; @@ -1940,6 +1947,7 @@ TkpClipDrawableToRect( macDraw->flags &= ~TK_FOCUSED_VIEW; } } + [pool drain]; } /* diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index e861089..98e6824 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -253,10 +253,7 @@ TkpInit( } #endif - static NSAutoreleasePool *pool = nil; - if (!pool) { - pool = [NSAutoreleasePool new]; - } + NSAutoreleasePool *pool = [NSAutoreleasePool new]; [[NSUserDefaults standardUserDefaults] registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], @@ -327,7 +324,6 @@ TkpInit( TkMacOSXUseAntialiasedText(interp, -1); TkMacOSXInitCGDrawing(interp, TRUE, 0); [pool drain]; - pool = [NSAutoreleasePool new]; /* * FIXME: Close stdin & stdout for remote debugging otherwise we will diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 1d4c6c5..3fe59bd 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -220,7 +220,7 @@ TkMacOSXEventsSetupProc( if (flags & TCL_WINDOW_EVENTS && ![[NSRunLoop currentRunLoop] currentMode]) { static const Tcl_Time zeroBlockTime = { 0, 0 }; - + NSAutoreleasePool *pool = [NSAutoreleasePool new]; /* Call this with dequeue=NO -- just checking if the queue is empty. */ NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] @@ -229,6 +229,7 @@ TkMacOSXEventsSetupProc( if (currentEvent && currentEvent.type > 0) { Tcl_SetMaxBlockTime(&zeroBlockTime); } + [pool drain]; } } diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 72ef39c..d23ba85 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -318,7 +318,7 @@ XResizeWindow( unsigned int height) { MacDrawable *macWin = (MacDrawable *) window; - + NSAutoreleasePool *pool= [NSAutoreleasePool new]; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { NSWindow *w = macWin->winPtr->wmInfoPtr->window; @@ -333,6 +333,7 @@ XResizeWindow( } else { MoveResizeWindow(macWin); } + [pool drain]; } /* diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index fb58904..5ec38ca 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -386,6 +386,7 @@ static void RemapWindows(TkWindow *winPtr, @end @implementation TKWindow(TKWm) + - (BOOL) canBecomeKeyWindow { TkWindow *winPtr = TkMacOSXGetTkWindow(self); @@ -395,16 +396,38 @@ static void RemapWindows(TkWindow *winPtr, kWindowNoActivatesAttribute)) ? NO : YES; } +#if DEBUG_ZOMBIES - (id) retain { -#if DEBUG_ZOMBIES + id result = [super retain]; const char *title = [[self title] UTF8String]; - if (title != NULL) { - printf("Retaining %s with count %lu\n", title, [self retainCount]); + if (title == nil) { + title = "unnamed window"; } -#endif - return [super retain]; + printf("Retained <%s>. Count is: %lu\n", title, [self retainCount]); + return result; +} + +- (id) autorelease +{ + id result = [super autorelease]; + const char *title = [[self title] UTF8String]; + if (title == nil) { + title = "unnamed window"; + } + printf("Autoreleased <%s>. Count is %lu\n", title, [self retainCount]); + return result; +} + +- (oneway void) release { + const char *title = [[self title] UTF8String]; + if (title == nil) { + title = "unnamed window"; + } + printf("Releasing <%s>. Count is %lu\n", title, [self retainCount]); + [super release]; } +#endif @end #pragma mark - @@ -842,6 +865,15 @@ TkWmDeadWindow( if (winPtr->window) { ((MacDrawable *) winPtr->window)->view = nil; } +#if DEBUG_ZOMBIES + { + const char *title = [[window title] UTF8String]; + if (title == nil) { + title = "unnamed window"; + } + printf("Closing <%s>. Count is: %lu\n", title, [window retainCount]); + } +#endif [window release]; wmPtr->window = NULL; /* Activate the highest window left on the screen. */ @@ -5507,6 +5539,8 @@ TkMacOSXMakeRealWindowExist( */ } + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + WindowClass macClass = wmPtr->macClass; wmPtr->attributes &= (tkAlwaysValidAttributes | macClassAttrs[macClass].validAttrs); @@ -5590,6 +5624,8 @@ TkMacOSXMakeRealWindowExist( TkMacOSXRegisterOffScreenWindow((Window) macWin, window); macWin->flags |= TK_HOST_EXISTS; + + [pool drain]; } /* diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c index e87bb39..c39d42d 100644 --- a/macosx/tkMacOSXXStubs.c +++ b/macosx/tkMacOSXXStubs.c @@ -142,7 +142,7 @@ TkpOpenDisplay( static NSRect maxBounds = {{0, 0}, {0, 0}}; static char vendor[25] = ""; NSArray *cgVers; - NSAutoreleasePool *pool; + if (gMacDisplay != NULL) { if (strcmp(gMacDisplay->display->display_name, display_name) == 0) { @@ -152,6 +152,8 @@ TkpOpenDisplay( } } + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + display = ckalloc(sizeof(Display)); screen = ckalloc(sizeof(Screen)); bzero(display, sizeof(Display)); @@ -166,7 +168,6 @@ TkpOpenDisplay( display->default_screen = 0; display->display_name = (char *) macScreenName; - pool = [NSAutoreleasePool new]; cgVers = [[[NSBundle bundleWithIdentifier:@"com.apple.CoreGraphics"] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] componentsSeparatedByString:@"."]; @@ -184,7 +185,7 @@ TkpOpenDisplay( { int major, minor, patch; -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 +#if MAC_OS_X_VERSION_MIN_REQUIRED < 10100 Gestalt(gestaltSystemVersionMajor, (SInt32*)&major); Gestalt(gestaltSystemVersionMinor, (SInt32*)&minor); Gestalt(gestaltSystemVersionBugFix, (SInt32*)&patch); -- cgit v0.12 From 656997252224e4bbfea9417b0ab6d1eca66f5a02 Mon Sep 17 00:00:00 2001 From: fvogel Date: Fri, 11 Dec 2015 10:44:56 +0000 Subject: Reverted [aaf6b1a3a0] --- tests/spinbox.test | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/spinbox.test b/tests/spinbox.test index 0f41379..b8170c5 100644 --- a/tests/spinbox.test +++ b/tests/spinbox.test @@ -3775,6 +3775,22 @@ test spinbox-22.3 {spinbox config, -from changes SF bug 559078} -body { destroy .e } -result {6} +test spinbox-23.1 {selection present while disabled, bug 637828} -body { + spinbox .e + .e insert end 0123456789 + .e select from 3 + .e select to 6 + set out [.e selection present] + .e configure -state disabled +# still return 1 when disabled, because 'selection get' will work, +# but selection cannot be changed (new behavior since 8.4) + .e select to 9 + lappend out [.e selection present] [selection get] +} -cleanup { + destroy .e +} -result {1 1 345} + + # Collected comments about lacks from the test # XXX Still need to write tests for SpinboxBlinkProc, SpinboxFocusProc, # and SpinboxTextVarProc. -- cgit v0.12 From f98486f81600c792bfb248f8f8eb87058f2d1040 Mon Sep 17 00:00:00 2001 From: oehhar Date: Mon, 14 Dec 2015 10:00:01 +0000 Subject: Support to paste file list (e.g. support CF_HDROPtype) Ticket [9fcc519a7c] --- win/tkWinClipboard.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) mode change 100644 => 100755 win/tkWinClipboard.c diff --git a/win/tkWinClipboard.c b/win/tkWinClipboard.c old mode 100644 new mode 100755 index 2501688..a616af5 --- a/win/tkWinClipboard.c +++ b/win/tkWinClipboard.c @@ -12,6 +12,7 @@ #include "tkWinInt.h" #include "tkSelect.h" +#include /* for DROPFILES */ static void UpdateClipboard(HWND hwnd); @@ -52,7 +53,7 @@ TkSelGetSelection( Tcl_DString ds; HGLOBAL handle; Tcl_Encoding encoding; - int result, locale; + int result, locale, noBackslash = 0; if ((selection != Tk_InternAtom(tkwin, "CLIPBOARD")) || (target != XA_STRING) @@ -132,7 +133,37 @@ TkSelGetSelection( if (encoding) { Tcl_FreeEncoding(encoding); } - + } else if (IsClipboardFormatAvailable(CF_HDROP)) { + DROPFILES *drop; + + handle = GetClipboardData(CF_HDROP); + if (!handle) { + CloseClipboard(); + goto error; + } + Tcl_DStringInit(&ds); + drop = (DROPFILES *) GlobalLock(handle); + if (drop->fWide) { + WCHAR *fname = (WCHAR *) ((char *) drop + drop->pFiles); + Tcl_DString dsTmp; + int count = 0, len; + + while (*fname != 0) { + if (count) { + Tcl_DStringAppend(&ds, "\n", 1); + } + len = Tcl_UniCharLen((Tcl_UniChar *) fname); + Tcl_DStringInit(&dsTmp); + Tcl_UniCharToUtfDString((Tcl_UniChar *) fname, len, &dsTmp); + Tcl_DStringAppend(&ds, Tcl_DStringValue(&dsTmp), + Tcl_DStringLength(&dsTmp)); + Tcl_DStringFree(&dsTmp); + fname += len + 1; + count++; + } + noBackslash = (count > 0); + } + GlobalUnlock(handle); } else { CloseClipboard(); goto error; @@ -146,7 +177,9 @@ TkSelGetSelection( while (*data) { if (data[0] == '\r' && data[1] == '\n') { data++; - } else { + } else if (noBackslash && data[0] == '\\') { + data++; + *destPtr++ = '/'; } else { *destPtr++ = *data++; } } -- cgit v0.12 From 63f1bed7bb0c9cdd0a7171121ae98f5c8c33224e Mon Sep 17 00:00:00 2001 From: oehhar Date: Mon, 14 Dec 2015 10:32:33 +0000 Subject: Test winDialog-5.12.7 failed if first item in home folder was not a file->corrected --- tests/winDialog.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 tests/winDialog.test diff --git a/tests/winDialog.test b/tests/winDialog.test old mode 100644 new mode 100755 index 24441cf..c8c36bf --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -594,7 +594,7 @@ test winDialog-5.12.6 {tk_getSaveFile: initial directory: relative} -constraints test winDialog-5.12.7 {tk_getOpenFile: initial directory: ~} -constraints { nt testwinevent } -body { - set fn [file tail [lindex [glob ~/*] 0]] + set fn [file tail [lindex [glob -types f ~/*] 0]] unset -nocomplain x start {set x [tk_getOpenFile \ -initialdir ~ \ -- cgit v0.12 From 11483b44ac56938fe3548e59216eca6886180a0b Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 14 Dec 2015 10:32:48 +0000 Subject: minor formatting --- win/tkWinClipboard.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/win/tkWinClipboard.c b/win/tkWinClipboard.c index a616af5..200883f 100755 --- a/win/tkWinClipboard.c +++ b/win/tkWinClipboard.c @@ -135,7 +135,7 @@ TkSelGetSelection( } } else if (IsClipboardFormatAvailable(CF_HDROP)) { DROPFILES *drop; - + handle = GetClipboardData(CF_HDROP); if (!handle) { CloseClipboard(); @@ -147,7 +147,7 @@ TkSelGetSelection( WCHAR *fname = (WCHAR *) ((char *) drop + drop->pFiles); Tcl_DString dsTmp; int count = 0, len; - + while (*fname != 0) { if (count) { Tcl_DStringAppend(&ds, "\n", 1); @@ -179,7 +179,8 @@ TkSelGetSelection( data++; } else if (noBackslash && data[0] == '\\') { data++; - *destPtr++ = '/'; } else { + *destPtr++ = '/'; + } else { *destPtr++ = *data++; } } -- cgit v0.12 From c23b714ab089bf546c9cc37188f29274b4e4991a Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Tue, 15 Dec 2015 02:50:56 +0000 Subject: Fix for some redraw issues on Tk-Cocoa on OS X 10.11; further refinement of memory management; thanks to Marc Culler for patches --- macosx/README | 61 +++++++++++++++++++++++++++++++++++++++ macosx/tkMacOSXDialog.c | 2 -- macosx/tkMacOSXDraw.c | 10 ------- macosx/tkMacOSXEvent.c | 5 ---- macosx/tkMacOSXFont.c | 7 +++-- macosx/tkMacOSXInit.c | 68 +++++++++++++++++++++++++++++-------------- macosx/tkMacOSXKeyEvent.c | 2 +- macosx/tkMacOSXMenu.c | 27 +++++------------ macosx/tkMacOSXNotify.c | 63 ++++++++++++++++++++-------------------- macosx/tkMacOSXPrivate.h | 3 ++ macosx/tkMacOSXSubwindows.c | 11 +------ macosx/tkMacOSXWindowEvent.c | 44 ++++++++++++++++++---------- macosx/tkMacOSXWm.c | 69 ++++++++++++++++++++++++++------------------ macosx/tkMacOSXXStubs.c | 6 ++-- 14 files changed, 227 insertions(+), 151 deletions(-) diff --git a/macosx/README b/macosx/README index 69be037..202dbbd 100644 --- a/macosx/README +++ b/macosx/README @@ -388,3 +388,64 @@ make overrides to the tk/macosx GNUmakefile, e.g. sudo make -C tk${ver}/macosx install \ TCL_FRAMEWORK_DIR=$HOME/Library/Frameworks TCLSH_DIR=$HOME/usr/bin The Makefile variables TCL_FRAMEWORK_DIR and TCLSH_DIR were added with Tk 8.4.3. + +4. About the event loop in Tk for Mac OSX +----------------------------------------- + +The main program in a typical OSX application looks like this (see *) + + void NSApplicationMain(int argc, char *argv[]) { + [NSApplication sharedApplication]; + [NSBundle loadNibNamed:@"myMain" owner:NSApp]; + [NSApp run]; + } + +The run method implements the event loop for the application. There +are three key steps in the run method. First it calls +[NSApp finishLaunching], which creates the bouncing application icon +and does other mysterious things. Second it creates an +NSAutoreleasePool. Third, it starts an event loop which drains the +NSAutoreleasePool every time the queue is empty, and replaces the +drained pool with a new one. This third step is essential to +preventing memory leaks, since the internal methods of Appkit objects +all assume that an autorelease pool is in scope and will be drained +when the event processing cycle ends. + +Mac OSX Tk does not call the [NSApp run] method at all. Instead it +uses the event loop built in to Tk. So we must take care to replicate +the important features of the method ourselves. Here is how this +works in outline. + +We add a private NSAUtoreleasePool* property to our subclass of +NSApplication. (The subclass is called TKApplication but can be +referenced with the global variable NSApp). The TkpInit +function calls [NSApp _setup] which initializes this property by +creating an NSAutoreleasePool. A bit later on, TkpInit calls +[NSAPP _setupEventLoop] which in turn calls the +[NSApp finishLaunching] method. + +Each time that Tcl processes an event in its queue, it calls a +platform specific function which, in the case of Mac OSX, is named +TkMacOSXEventsCheckProc. In the unix implementations of Tk, including +the Mac OSX version, this function collects events from an "event +source", and transfers them to the Tcl event queue. In Mac OSX the +event source is the NSApplication event queue. Each NSEvent is +converted to a Tcl event which is added to the Tcl event queue. The +NSEvent is also passed to [NSApp sendevent], which sends the event on +to the application's NSWindows, which send it to their NSViews, etc. +Since the CheckProc function gets called for every Tk event, it is an +appropriate place to drain the main NSAutoreleasePool and replace it +with a new pool. This is done by calling the method +[NSApp _resetAutoreleasePool], where _resetAutoreleasePool is a method +which we define for the subclass TKApplication. + +One minor caveat is that there are several steps of the Tk +initialization which precede the call to TkpInit. Notably, the font +package is initialized first. Since there is no NSAUtoreleasePool in +scope prior to calling TkpInit, the functions called in these +preliminary stages need to create and drain their own +NSAutoreleasePools whenever they call methods of Appkit objects +(e.g. NSFont). + +* https://developer.apple.com/library/mac/documentation/Cocoa/\ +Reference/ApplicationKit/Classes/NSApplication_Class diff --git a/macosx/tkMacOSXDialog.c b/macosx/tkMacOSXDialog.c index fb6e490..a3510f8 100644 --- a/macosx/tkMacOSXDialog.c +++ b/macosx/tkMacOSXDialog.c @@ -1733,9 +1733,7 @@ TkInitFontchooser( Tcl_SetAssocData(interp, "::tk::fontchooser", DeleteFontchooserData, fcdPtr); if (!fontPanelFontAttributes) { - NSAutoreleasePool *pool = [NSAutoreleasePool new]; fontPanelFontAttributes = [NSMutableDictionary new]; - [pool drain]; } return TCL_OK; } diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 10f7b9e..6a0b409 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -138,7 +138,6 @@ BitmapRepFromDrawableRect( CGImageRef cg_image=NULL, sub_cg_image=NULL; NSBitmapImageRep *bitmap_rep=NULL; NSView *view=NULL; - NSAutoreleasePool *pool = [NSAutoreleasePool new]; if ( mac_drawable->flags & TK_IS_PIXMAP ) { /* This means that the MacDrawable is functioning as a Tk Pixmap, so its view @@ -175,7 +174,6 @@ BitmapRepFromDrawableRect( } else { TkMacOSXDbgMsg("Invalid source drawable"); } - [pool drain]; return bitmap_rep; } @@ -1636,7 +1634,6 @@ TkMacOSXSetupDrawingContext( int dontDraw = 0, isWin = 0; TkMacOSXDrawingContext dc = {}; CGRect clipBounds; - NSAutoreleasePool *pool = [NSAutoreleasePool new]; dc.clipRgn = TkMacOSXGetClipRgn(d); if (!dontDraw) { @@ -1767,7 +1764,6 @@ end: dc.clipRgn = NULL; } *dcPtr = dc; - [pool drain]; return !dontDraw; } @@ -1791,7 +1787,6 @@ void TkMacOSXRestoreDrawingContext( TkMacOSXDrawingContext *dcPtr) { - NSAutoreleasePool *pool = [NSAutoreleasePool new]; if (dcPtr->context) { CGContextSynchronize(dcPtr->context); [[dcPtr->view window] setViewsNeedDisplay:YES]; @@ -1808,7 +1803,6 @@ TkMacOSXRestoreDrawingContext( #ifdef TK_MAC_DEBUG bzero(dcPtr, sizeof(TkMacOSXDrawingContext)); #endif /* TK_MAC_DEBUG */ - [pool drain]; } /* @@ -1834,7 +1828,6 @@ TkMacOSXGetClipRgn( { MacDrawable *macDraw = (MacDrawable *) drawable; HIShapeRef clipRgn = NULL; - NSAutoreleasePool *pool = [NSAutoreleasePool new]; if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) { TkMacOSXUpdateClipRgn(macDraw->winPtr); @@ -1860,7 +1853,6 @@ TkMacOSXGetClipRgn( } else if (macDraw->visRgn) { clipRgn = HIShapeCreateCopy(macDraw->visRgn); } - [pool drain]; return clipRgn; } @@ -1913,7 +1905,6 @@ TkpClipDrawableToRect( { MacDrawable *macDraw = (MacDrawable *) d; NSView *view = TkMacOSXDrawableView(macDraw); - NSAutoreleasePool *pool = [NSAutoreleasePool new]; if (macDraw->drawRgn) { CFRelease(macDraw->drawRgn); @@ -1947,7 +1938,6 @@ TkpClipDrawableToRect( macDraw->flags &= ~TK_FOCUSED_VIEW; } } - [pool drain]; } /* diff --git a/macosx/tkMacOSXEvent.c b/macosx/tkMacOSXEvent.c index db13249..7f3357f 100644 --- a/macosx/tkMacOSXEvent.c +++ b/macosx/tkMacOSXEvent.c @@ -128,10 +128,6 @@ enum { MODULE_SCOPE void TkMacOSXFlushWindows(void) { - /* This can be called from outside the Appkit event loop, - * so it needs its own AutoreleasePool. - */ - NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSArray *macWindows = [NSApp orderedWindows]; for (NSWindow *w in macWindows) { @@ -139,7 +135,6 @@ TkMacOSXFlushWindows(void) [w flushWindow]; } } - [pool drain]; } diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c index 54b0fb8..c48e56e 100644 --- a/macosx/tkMacOSXFont.c +++ b/macosx/tkMacOSXFont.c @@ -210,6 +210,7 @@ FindNSFont( nsFont = [fm convertFont:nsFont toSize:size]; nsFont = [fm convertFont:nsFont toHaveTrait:traits]; } + [nsFont retain]; #undef defaultFont return nsFont; } @@ -306,7 +307,7 @@ InitFont( [NSNumber numberWithInt:fmPtr->fixed ? 0 : 1], NSLigatureAttributeName, [NSNumber numberWithDouble:kern], NSKernAttributeName, nil]; - fontPtr->nsAttributes = [nsAttributes retain]; + fontPtr->nsAttributes = [nsAttributes retain]; #undef nCh } @@ -371,6 +372,7 @@ TkpFontPkgInit( NSFont *nsFont; TkFontAttributes fa; NSMutableCharacterSet *cs; + /* Since we called before TkpInit, we need our own autorelease pool. */ NSAutoreleasePool *pool = [NSAutoreleasePool new]; /* force this for now */ @@ -530,7 +532,7 @@ TkpGetFontFromAttributes( nsFont = FindNSFont(faPtr->family, traits, weight, points, 1); } if (!nsFont) { - Tcl_Panic("Could not deternmine NSFont from TkFontAttributes"); + Tcl_Panic("Could not determine NSFont from TkFontAttributes"); } if (tkFontPtr == NULL) { fontPtr = ckalloc(sizeof(MacFont)); @@ -675,7 +677,6 @@ TkpGetFontAttrsForChar( { MacFont *fontPtr = (MacFont *) tkfont; NSFont *nsFont = fontPtr->nsFont; - *faPtr = fontPtr->font.fa; if (nsFont && ![[nsFont coveredCharacterSet] characterIsMember:c]) { UTF16Char ch = c; diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index 98e6824..c658149 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -57,9 +57,19 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt @end @implementation TKApplication +#ifndef __clang__ +@synthesize poolProtected = _poolProtected; +#endif @end @implementation TKApplication(TKInit) +- (void) _resetAutoreleasePool +{ + if(![self poolProtected]) { + [_mainPool drain]; + _mainPool = [NSAutoreleasePool new]; + } +} #ifdef TK_MAC_DEBUG_NOTIFICATIONS - (void) _postedNotification: (NSNotification *) notification { @@ -86,16 +96,19 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt - (void) _setupEventLoop { - - /*Remove private API flags here.*/ + NSAutoreleasePool *pool = [NSAutoreleasePool new]; [self finishLaunching]; [self setWindowsNeedUpdate:YES]; + [pool drain]; } - (void) _setup: (Tcl_Interp *) interp { _eventInterp = interp; + _mainPool = nil; + [NSApp setPoolProtected:NO]; _defaultMainMenu = nil; + NSAutoreleasePool *pool = [NSAutoreleasePool new]; [self _setupMenus]; [self setDelegate:self]; #ifdef TK_MAC_DEBUG_NOTIFICATIONS @@ -104,12 +117,13 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt #endif [self _setupWindowNotifications]; [self _setupApplicationNotifications]; + [pool drain]; } - (NSString *) tkFrameworkImagePath: (NSString *) image { NSString *path = nil; - + NSAutoreleasePool *pool = [NSAutoreleasePool new]; if (tkLibPath[0] != '\0') { path = [[NSBundle bundleWithPath:[[NSString stringWithUTF8String: tkLibPath] stringByAppendingString:@"/../.."]] @@ -142,6 +156,8 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt } } #endif + [path retain]; + [pool drain]; return path; } @end @@ -168,6 +184,7 @@ static void SetApplicationIcon( ClientData clientData) { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSString *path = [NSApp tkFrameworkImagePath:@"Tk.icns"]; if (path) { NSImage *image = [[NSImage alloc] initWithContentsOfFile:path]; @@ -176,6 +193,7 @@ SetApplicationIcon( [image release]; } } + [pool drain]; } /* @@ -253,16 +271,19 @@ TkpInit( } #endif - NSAutoreleasePool *pool = [NSAutoreleasePool new]; - [[NSUserDefaults standardUserDefaults] registerDefaults: - [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:YES], - @"_NSCanWrapButtonTitles", - [NSNumber numberWithInt:-1], - @"NSStringDrawingTypesetterBehavior", - nil]]; - [TKApplication sharedApplication]; - [NSApp _setup:interp]; + { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + [[NSUserDefaults standardUserDefaults] registerDefaults: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], + @"_NSCanWrapButtonTitles", + [NSNumber numberWithInt:-1], + @"NSStringDrawingTypesetterBehavior", + nil]]; + [TKApplication sharedApplication]; + [pool drain]; + [NSApp _setup:interp]; + } /* Check whether we are a bundled executable: */ bundleRef = CFBundleGetMainBundle(); @@ -319,12 +340,15 @@ TkpInit( Tcl_DoWhenIdle(SetApplicationIcon, NULL); } - [NSApp _setupEventLoop]; - TkMacOSXInitAppleEvents(interp); - TkMacOSXUseAntialiasedText(interp, -1); - TkMacOSXInitCGDrawing(interp, TRUE, 0); - [pool drain]; - + { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + [NSApp _setupEventLoop]; + TkMacOSXInitAppleEvents(interp); + TkMacOSXUseAntialiasedText(interp, -1); + TkMacOSXInitCGDrawing(interp, TRUE, 0); + [pool drain]; + } + /* * FIXME: Close stdin & stdout for remote debugging otherwise we will * fight with gdb for stdin & stdout @@ -480,9 +504,8 @@ TkpDisplayWarning( MODULE_SCOPE void TkMacOSXDefaultStartupScript(void) { - CFBundleRef bundleRef; - - bundleRef = CFBundleGetMainBundle(); + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + CFBundleRef bundleRef = CFBundleGetMainBundle(); if (bundleRef != NULL) { CFURLRef appMainURL = CFBundleCopyResourceURL(bundleRef, @@ -506,6 +529,7 @@ TkMacOSXDefaultStartupScript(void) CFRelease(appMainURL); } } + [pool drain]; } /* diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index 8521beb..151b4f2 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -328,7 +328,7 @@ static unsigned isFunctionKey(unsigned int code); pt.y = caret_y; pt = [self convertPoint: pt toView: nil]; - pt = [[self window] convertBaseToScreen: pt]; + pt = [[self window] convertPointToScreen: pt]; pt.y -= caret_height; rect.origin = pt; diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 0c078ce..c7e3a78 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -258,10 +258,10 @@ static int ModifierCharWidth(Tk_Font tkfont); if (menuPtr && mePtr) { Tcl_Interp *interp = menuPtr->interp; - /*Add time for errors to fire if necessary. This is sub-optimal but avoids issues with Tcl/Cocoa event loop integration.*/ + /*Add time for errors to fire if necessary. This is sub-optimal + *but avoids issues with Tcl/Cocoa event loop integration. + */ Tcl_Sleep(100); - - NSAutoreleasePool *pool = [NSAutoreleasePool new]; Tcl_Preserve(interp); Tcl_Preserve(menuPtr); @@ -274,7 +274,6 @@ static int ModifierCharWidth(Tk_Font tkfont); } Tcl_Release(menuPtr); Tcl_Release(interp); - [pool drain]; } } } @@ -377,13 +376,6 @@ static int ModifierCharWidth(Tk_Font tkfont); @implementation TKApplication(TKMenu) -- (void) safeSetMainMenu: (NSMenu *) menu -{ - NSAutoreleasePool* pool = [NSAutoreleasePool new]; - [self setMainMenu: menu]; - [pool drain]; -} - - (void) menuBeginTracking: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS @@ -420,7 +412,7 @@ static int ModifierCharWidth(Tk_Font tkfont); if (!mePtr || !(mePtr->entryFlags & ENTRY_APPLE_MENU)) { applicationMenuItem = [NSMenuItem itemWithSubmenu: - [[_defaultApplicationMenu copy] autorelease]]; + [_defaultApplicationMenu copy]]; [menu insertItem:applicationMenuItem atIndex:0]; } [menu setSpecial:tkMainMenu]; @@ -428,7 +420,7 @@ static int ModifierCharWidth(Tk_Font tkfont); applicationMenu = (TKMenu *)[applicationMenuItem submenu]; if (![applicationMenu isSpecial:tkApplicationMenu]) { for (NSMenuItem *item in _defaultApplicationMenuItems) { - [applicationMenu addItem:[[item copy] autorelease]]; + [applicationMenu addItem:[item copy]]; } [applicationMenu setSpecial:tkApplicationMenu]; } @@ -438,15 +430,13 @@ static int ModifierCharWidth(Tk_Font tkfont); for (NSMenuItem *item in itemArray) { TkMenuEntry *mePtr = (TkMenuEntry *)[item tag]; TKMenu *submenu = (TKMenu *)[item submenu]; - if (mePtr && submenu) { if ((mePtr->entryFlags & ENTRY_WINDOWS_MENU) && ![submenu isSpecial:tkWindowsMenu]) { NSInteger index = 0; for (NSMenuItem *i in _defaultWindowsMenuItems) { - [submenu insertItem:[[i copy] autorelease] atIndex: - index++]; + [submenu insertItem:[i copy] atIndex:index++]; } [self setWindowsMenu:submenu]; [submenu setSpecial:tkWindowsMenu]; @@ -455,8 +445,7 @@ static int ModifierCharWidth(Tk_Font tkfont); NSInteger index = 0; for (NSMenuItem *i in _defaultHelpMenuItems) { - [submenu insertItem:[[i copy] autorelease] atIndex: - index++]; + [submenu insertItem:[i copy] atIndex:index++]; } [submenu setSpecial:tkHelpMenu]; } @@ -475,7 +464,7 @@ static int ModifierCharWidth(Tk_Font tkfont); [servicesMenuItem setSubmenu:_servicesMenu]; } [self setAppleMenu:applicationMenu]; - [self safeSetMainMenu:menu]; + [self setMainMenu:menu]; } @end diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 3fe59bd..06207e2 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -50,7 +50,7 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags); @end @implementation TKApplication(TKNotify) -/* Call super then redisplay all of our windows. */ +/* Display all windows each time an event is removed from the queue.*/ - (NSEvent *) nextEventMatchingMask: (NSUInteger) mask untilDate: (NSDate *) expiration inMode: (NSString *) mode dequeue: (BOOL) deqFlag @@ -59,9 +59,9 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags); untilDate:expiration inMode:mode dequeue:deqFlag]; - NSAutoreleasePool *pool = [NSAutoreleasePool new]; + /* Retain this event for later use. Must be released.*/ + [event retain]; [NSApp makeWindowsPerform:@selector(tkDisplayIfNeeded) inOrder:NO]; - [pool drain]; return event; } @@ -70,10 +70,8 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags); */ - (void) sendEvent: (NSEvent *) theEvent { - NSAutoreleasePool *pool = [NSAutoreleasePool new]; [super sendEvent:theEvent]; [NSApp tkCheckPasteboard]; - [pool drain]; } @end @@ -217,19 +215,21 @@ TkMacOSXEventsSetupProc( ClientData clientData, int flags) { - if (flags & TCL_WINDOW_EVENTS && - ![[NSRunLoop currentRunLoop] currentMode]) { + NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode]; + /* runloopMode will be nil if we are in the Tcl event loop. */ + if (flags & TCL_WINDOW_EVENTS && !runloopMode) { static const Tcl_Time zeroBlockTime = { 0, 0 }; - NSAutoreleasePool *pool = [NSAutoreleasePool new]; /* Call this with dequeue=NO -- just checking if the queue is empty. */ NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:GetRunLoopMode(TkMacOSXGetModalSession()) - dequeue:NO]; - if (currentEvent && currentEvent.type > 0) { - Tcl_SetMaxBlockTime(&zeroBlockTime); + untilDate:[NSDate distantPast] + inMode:GetRunLoopMode(TkMacOSXGetModalSession()) + dequeue:NO]; + if (currentEvent) { + if (currentEvent.type > 0) { + Tcl_SetMaxBlockTime(&zeroBlockTime); + } + [currentEvent release]; } - [pool drain]; } } @@ -256,13 +256,14 @@ TkMacOSXEventsCheckProc( int flags) { NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode]; + /* runloopMode will be nil if we are in the Tcl event loop. */ if (flags & TCL_WINDOW_EVENTS && !runloopMode) { - NSEvent *currentEvent = nil; NSEvent *testEvent = nil; NSModalSession modalSession; - + do { + [NSApp _resetAutoreleasePool]; modalSession = TkMacOSXGetModalSession(); testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] @@ -277,25 +278,25 @@ TkMacOSXEventsCheckProc( untilDate:[NSDate distantPast] inMode:GetRunLoopMode(modalSession) dequeue:YES]; - if (!currentEvent) { - break; /* No events are available. */ - } - NSAutoreleasePool *pool = [NSAutoreleasePool new]; - /* Generate Xevents. */ - int oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); - NSEvent *processedEvent = [NSApp tkProcessEvent:currentEvent]; - Tcl_SetServiceMode(oldServiceMode); - if (processedEvent) { /* Should always be non-NULL. */ + if (currentEvent) { + /* Generate Xevents. */ + int oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + NSEvent *processedEvent = [NSApp tkProcessEvent:currentEvent]; + Tcl_SetServiceMode(oldServiceMode); + if (processedEvent) { /* Should always be non-NULL. */ #ifdef TK_MAC_DEBUG_EVENTS - TKLog(@" event: %@", currentEvent); + TKLog(@" event: %@", currentEvent); #endif - if (modalSession) { - [NSApp _modalSession:modalSession sendEvent:currentEvent]; - } else { - [NSApp sendEvent:currentEvent]; + if (modalSession) { + [NSApp _modalSession:modalSession sendEvent:currentEvent]; + } else { + [NSApp sendEvent:currentEvent]; + } } + [currentEvent release]; + } else { + break; } - [pool drain]; } while (1); } } diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 90d5a9b..2a411f6 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -275,10 +275,13 @@ VISIBILITY_HIDDEN NSArray *_defaultApplicationMenuItems, *_defaultWindowsMenuItems; NSArray *_defaultHelpMenuItems; NSWindow *_windowWithMouse; + NSAutoreleasePool *_mainPool; } +@property BOOL poolProtected; @end @interface TKApplication(TKInit) - (NSString *)tkFrameworkImagePath:(NSString*)image; +- (void)_resetAutoreleasePool; @end @interface TKApplication(TKEvent) - (NSEvent *)tkProcessEvent:(NSEvent *)theEvent; diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index d23ba85..f026318 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -131,11 +131,6 @@ XMapWindow( { MacDrawable *macWin = (MacDrawable *) window; XEvent event; - /* - * This function can be called from outside the AppKit event - * loop, so it needs its own AutoreleasePool. - */ - NSAutoreleasePool* pool = [NSAutoreleasePool new]; /* * Under certain situations it's possible for this function to be called @@ -158,6 +153,7 @@ XMapWindow( if ( [win canBecomeKeyWindow] ) { [win makeKeyAndOrderFront:NSApp]; } + /* Why do we need this? (It is used by Carbon)*/ [win windowRef]; TkMacOSXApplyWindowAttributes(macWin->winPtr, win); } @@ -194,7 +190,6 @@ XMapWindow( event.xvisibility.type = VisibilityNotify; event.xvisibility.state = VisibilityUnobscured; NotifyVisibility(macWin->winPtr, &event); - [pool drain]; } /* @@ -318,7 +313,6 @@ XResizeWindow( unsigned int height) { MacDrawable *macWin = (MacDrawable *) window; - NSAutoreleasePool *pool= [NSAutoreleasePool new]; display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { NSWindow *w = macWin->winPtr->wmInfoPtr->window; @@ -333,7 +327,6 @@ XResizeWindow( } else { MoveResizeWindow(macWin); } - [pool drain]; } /* @@ -366,7 +359,6 @@ XMoveResizeWindow( display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { NSWindow *w = macWin->winPtr->wmInfoPtr->window; - if (w) { NSRect r = NSMakeRect(x + macWin->winPtr->wmInfoPtr->xInParent, tkMacOSXZeroScreenHeight - (y + @@ -407,7 +399,6 @@ XMoveWindow( display->request++; if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { NSWindow *w = macWin->winPtr->wmInfoPtr->window; - if (w) { [w setFrameTopLeftPoint:NSMakePoint(x, tkMacOSXZeroScreenHeight - y)]; } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 851358d..1150f2e 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -806,7 +806,7 @@ ConfigureRestrictProc( { const NSRect *rectsBeingDrawn; NSInteger rectsBeingDrawnCount; - + [self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount]; #ifdef TK_MAC_DEBUG_DRAWING @@ -840,7 +840,8 @@ ConfigureRestrictProc( -(void) setFrameSize: (NSSize)newsize { - if ( [self inLiveResize] ) { + [super setFrameSize: newsize]; + if ([self inLiveResize]) { NSWindow *w = [self window]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); Tk_Window tkwin = (Tk_Window) winPtr; @@ -849,17 +850,29 @@ ConfigureRestrictProc( ClientData oldArg; Tk_RestrictProc *oldProc; - /* Resize the NSView */ - [super setFrameSize: newsize]; - - /* Disable drawing until the window has been completely configured.*/ + /* This can be called from outside the Tk event loop. + * Since it calls Tcl_DoOneEvent, we need to make sure we + * don't clobber the AutoreleasePool set up by the caller. + */ + [NSApp setPoolProtected:YES]; + + /* + * Try to prevent flickers and flashes. + * + * This stops the flickers on OSX 10.11. But flashes still occur when + * the width of the window is 16, 32, 48, 64, 80, 96, 112, 256, 512, + * 768, ... :^( + */ + [w disableFlushWindow]; + + /* Disable Tk drawing until the window has been completely configured.*/ TkMacOSXSetDrawingEnabled(winPtr, 0); /* Generate and handle a ConfigureNotify event for the new size.*/ TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height, TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY); oldProc = Tk_RestrictEvents(ConfigureRestrictProc, NULL, &oldArg); - while ( Tk_DoOneEvent(TK_X_EVENTS|TK_DONT_WAIT) ) {} + while (Tk_DoOneEvent(TK_X_EVENTS|TK_DONT_WAIT)) {} Tk_RestrictEvents(oldProc, oldArg, &oldArg); /* Now that Tk has configured all subwindows we can create the clip regions. */ @@ -871,9 +884,10 @@ ConfigureRestrictProc( HIRect bounds = NSRectToCGRect([self bounds]); HIShapeRef shape = HIShapeCreateWithRect(&bounds); [self generateExposeEvents: shape]; - while ( Tk_DoOneEvent(TK_ALL_EVENTS|TK_DONT_WAIT) ) {} - } else { - [super setFrameSize: newsize]; + while (Tk_DoOneEvent(TK_ALL_EVENTS|TK_DONT_WAIT)) {} + [w enableFlushWindow]; + [w flushWindowIfNeeded]; + [NSApp setPoolProtected:NO]; } } @@ -891,12 +905,10 @@ ConfigureRestrictProc( [self generateExposeEvents: shape]; } -/* Core method of this class: generates expose events for redrawing. - * Whereas drawRect is intended to be called only from the Appkit event - * loop, this can be called from Tk. If the Tcl_ServiceMode is set to - * TCL_SERVICE_ALL then the expose events will be immediately removed - * from the Tcl event loop and processed. Typically, they should be queued, - * however. +/* Core method of this class: generates expose events for redrawing. If the + * Tcl_ServiceMode is set to TCL_SERVICE_ALL then the expose events will be + * immediately removed from the Tcl event loop and processed. Typically, they + * should be queued, however. */ - (void) generateExposeEvents: (HIShapeRef) shape { diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 5ec38ca..308ee11 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -404,18 +404,23 @@ static void RemapWindows(TkWindow *winPtr, if (title == nil) { title = "unnamed window"; } - printf("Retained <%s>. Count is: %lu\n", title, [self retainCount]); + if (DEBUG_ZOMBIES > 1){ + printf("Retained <%s>. Count is: %lu\n", title, [self retainCount]); + } return result; } - (id) autorelease { + static int xcount = 0; id result = [super autorelease]; const char *title = [[self title] UTF8String]; if (title == nil) { title = "unnamed window"; } - printf("Autoreleased <%s>. Count is %lu\n", title, [self retainCount]); + if (DEBUG_ZOMBIES > 1){ + printf("Autoreleased <%s>. Count is %lu\n", title, [self retainCount]); + } return result; } @@ -424,9 +429,24 @@ static void RemapWindows(TkWindow *winPtr, if (title == nil) { title = "unnamed window"; } - printf("Releasing <%s>. Count is %lu\n", title, [self retainCount]); + if (DEBUG_ZOMBIES > 1){ + printf("Releasing <%s>. Count is %lu\n", title, [self retainCount]); + } [super release]; } + +- (void) dealloc { + const char *title = [[self title] UTF8String]; + if (title == nil) { + title = "unnamed window"; + } + if (DEBUG_ZOMBIES > 0){ + printf(">>>> Freeing <%s>. Count is %lu\n", title, [self retainCount]); + } + [super dealloc]; +} + + #endif @end @@ -541,7 +561,6 @@ FrontWindowAtPoint( int x, int y) { NSPoint p = NSMakePoint(x, tkMacOSXZeroScreenHeight - y); - NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSArray *windows = [NSApp orderedWindows]; TkWindow *front = NULL; @@ -551,7 +570,6 @@ FrontWindowAtPoint( break; } } - [pool drain]; return front; } @@ -855,7 +873,6 @@ TkWmDeadWindow( NSWindow *window = wmPtr->window; if (window && !Tk_IsEmbedded(winPtr) ) { - NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSWindow *parent = [window parentWindow]; if (parent) { [parent removeChildWindow:window]; @@ -865,26 +882,30 @@ TkWmDeadWindow( if (winPtr->window) { ((MacDrawable *) winPtr->window)->view = nil; } -#if DEBUG_ZOMBIES +#if DEBUG_ZOMBIES > 0 { const char *title = [[window title] UTF8String]; if (title == nil) { title = "unnamed window"; } - printf("Closing <%s>. Count is: %lu\n", title, [window retainCount]); + printf(">>>> Closing <%s>. Count is: %lu\n", title, [window retainCount]); } #endif [window release]; wmPtr->window = NULL; - /* Activate the highest window left on the screen. */ - NSArray *windows = [NSApp orderedWindows]; - if ( [windows count] > 0 ) { - NSWindow *front = [windows objectAtIndex:0]; - if ( front && [front canBecomeKeyWindow] ) { - [front makeKeyAndOrderFront:NSApp]; - } - } - [pool drain]; + + /* Activate the highest window left on the screen. */ + NSArray *windows = [NSApp orderedWindows]; + if ( [windows count] > 0 ) { + NSWindow *front = [windows objectAtIndex:0]; + if ( front && [front canBecomeKeyWindow] ) { + [front makeKeyAndOrderFront:NSApp]; + } + } +#if DEBUG_ZOMBIES > 0 + fprintf(stderr, "================= Pool dump ===================\n"); + [NSAutoreleasePool showPools]; +#endif } ckfree(wmPtr); winPtr->wmInfoPtr = NULL; @@ -5538,9 +5559,6 @@ TkMacOSXMakeRealWindowExist( * TODO: Here we should handle out of process embedding. */ } - - NSAutoreleasePool *pool = [NSAutoreleasePool new]; - WindowClass macClass = wmPtr->macClass; wmPtr->attributes &= (tkAlwaysValidAttributes | macClassAttrs[macClass].validAttrs); @@ -5574,10 +5592,10 @@ TkMacOSXMakeRealWindowExist( NSWindow *window = [[winClass alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:YES]; if (!window) { - Tcl_Panic("couldn't allocate new Mac window"); + Tcl_Panic("couldn't allocate new Mac window"); } TKContentView *contentView = [[TKContentView alloc] - initWithFrame:NSZeroRect]; + initWithFrame:NSZeroRect]; [window setContentView:contentView]; [contentView release]; [window setDelegate:NSApp]; @@ -5612,7 +5630,7 @@ TkMacOSXMakeRealWindowExist( [window setDocumentEdited:NO]; wmPtr->window = window; - macWin->view = contentView; + macWin->view = window.contentView; TkMacOSXApplyWindowAttributes(winPtr, window); NSRect geometry = InitialWindowBounds(winPtr, window); @@ -5621,11 +5639,8 @@ TkMacOSXMakeRealWindowExist( geometry.origin.y = tkMacOSXZeroScreenHeight - (geometry.origin.y + geometry.size.height); [window setFrame:geometry display:NO]; - TkMacOSXRegisterOffScreenWindow((Window) macWin, window); macWin->flags |= TK_HOST_EXISTS; - - [pool drain]; } /* @@ -6018,7 +6033,6 @@ TkpChangeFocus( if (Tk_IsTopLevel(winPtr) && !Tk_IsEmbedded(winPtr) ){ NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); - NSAutoreleasePool *pool = [NSAutoreleasePool new]; TkWmRestackToplevel(winPtr, Above, NULL); if (force ) { [NSApp activateIgnoringOtherApps:YES]; @@ -6026,7 +6040,6 @@ TkpChangeFocus( if ( win && [win canBecomeKeyWindow] ) { [win makeKeyAndOrderFront:NSApp]; } - [pool drain]; } /* diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c index c39d42d..53d1eb8 100644 --- a/macosx/tkMacOSXXStubs.c +++ b/macosx/tkMacOSXXStubs.c @@ -142,8 +142,8 @@ TkpOpenDisplay( static NSRect maxBounds = {{0, 0}, {0, 0}}; static char vendor[25] = ""; NSArray *cgVers; - - + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + if (gMacDisplay != NULL) { if (strcmp(gMacDisplay->display->display_name, display_name) == 0) { return gMacDisplay; @@ -152,8 +152,6 @@ TkpOpenDisplay( } } - NSAutoreleasePool *pool = [NSAutoreleasePool new]; - display = ckalloc(sizeof(Display)); screen = ckalloc(sizeof(Screen)); bzero(display, sizeof(Display)); -- cgit v0.12 -- cgit v0.12 From b0403585584cc0e6e4518f2cd03ac46fa21db2f9 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 17 Dec 2015 15:03:11 +0000 Subject: spacing --- macosx/tkMacOSXInit.c | 2 +- macosx/tkMacOSXNotify.c | 2 +- macosx/tkMacOSXWindowEvent.c | 6 +++--- macosx/tkMacOSXXStubs.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index c658149..997d306 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -348,7 +348,7 @@ TkpInit( TkMacOSXInitCGDrawing(interp, TRUE, 0); [pool drain]; } - + /* * FIXME: Close stdin & stdout for remote debugging otherwise we will * fight with gdb for stdin & stdout diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 06207e2..1455688 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -261,7 +261,7 @@ TkMacOSXEventsCheckProc( NSEvent *currentEvent = nil; NSEvent *testEvent = nil; NSModalSession modalSession; - + do { [NSApp _resetAutoreleasePool]; modalSession = TkMacOSXGetModalSession(); diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 1150f2e..95ebb25 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -806,7 +806,7 @@ ConfigureRestrictProc( { const NSRect *rectsBeingDrawn; NSInteger rectsBeingDrawnCount; - + [self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount]; #ifdef TK_MAC_DEBUG_DRAWING @@ -855,7 +855,7 @@ ConfigureRestrictProc( * don't clobber the AutoreleasePool set up by the caller. */ [NSApp setPoolProtected:YES]; - + /* * Try to prevent flickers and flashes. * @@ -864,7 +864,7 @@ ConfigureRestrictProc( * 768, ... :^( */ [w disableFlushWindow]; - + /* Disable Tk drawing until the window has been completely configured.*/ TkMacOSXSetDrawingEnabled(winPtr, 0); diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c index 53d1eb8..5d6ffb9 100644 --- a/macosx/tkMacOSXXStubs.c +++ b/macosx/tkMacOSXXStubs.c @@ -143,7 +143,7 @@ TkpOpenDisplay( static char vendor[25] = ""; NSArray *cgVers; NSAutoreleasePool *pool = [NSAutoreleasePool new]; - + if (gMacDisplay != NULL) { if (strcmp(gMacDisplay->display->display_name, display_name) == 0) { return gMacDisplay; -- cgit v0.12 From 1ce29cc9feab7c14297627f4306c8e1db96bfd09 Mon Sep 17 00:00:00 2001 From: oehhar Date: Thu, 7 Jan 2016 17:20:57 +0000 Subject: Prefix "system" of all Windows System Colors was documented --- doc/colors.n | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/colors.n b/doc/colors.n index d121248..dc7007b 100644 --- a/doc/colors.n +++ b/doc/colors.n @@ -933,19 +933,19 @@ On Windows, the following additional system colors are available .RS .DS .ta 6c -3dDarkShadow Highlight -3dLight HighlightText -ActiveBorder InactiveBorder -ActiveCaption InactiveCaption -AppWorkspace InactiveCaptionText -Background InfoBackground -ButtonFace InfoText -ButtonHighlight Menu -ButtonShadow MenuText -ButtonText Scrollbar -CaptionText Window -DisabledText WindowFrame -GrayText WindowText +system3dDarkShadow systemHighlight +system3dLight systemHighlightText +systemActiveBorder systemInactiveBorder +systemActiveCaption systemInactiveCaption +systemAppWorkspace systemInactiveCaptionText +systemBackground systemInfoBackground +systemButtonFace systemInfoText +systemButtonHighlight systemMenu +systemButtonShadow systemMenuText +systemButtonText systemScrollbar +systemCaptionText systemWindow +systemDisabledText systemWindowFrame +systemGrayText systemWindowText .DE .RE .SH "SEE ALSO" -- cgit v0.12