From 89022786e10d8bd3a7eb44f2053e1e31d6fcb0b0 Mon Sep 17 00:00:00 2001 From: "dgp@users.sourceforge.net" Date: Tue, 11 Sep 2007 17:46:39 +0000 Subject: * generic/tkConsole.c: Revised calls to Tcl_InitStubs() and * generic/tkMain.c: [package require Tcl] so that Tk Says What * generic/tkWindow.c: It Means using the new facilties of [package] * library/tk.tcl: in Tcl 8.5 about what version(s) of Tcl it * unix/Makefile.in: is willing to work with. [Bug 1578344]. * win/Makefile.in: * win/makefile.vc: --- ChangeLog | 10 ++++++++++ generic/tkConsole.c | 4 ++-- generic/tkMain.c | 4 ++-- generic/tkWindow.c | 4 ++-- library/tk.tcl | 9 ++++++--- unix/Makefile.in | 9 ++++----- win/Makefile.in | 10 +++++----- win/makefile.vc | 5 ++--- 8 files changed, 33 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 11e3805..281f44a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-09-11 Don Porter + + * generic/tkConsole.c: Revised calls to Tcl_InitStubs() and + * generic/tkMain.c: [package require Tcl] so that Tk Says What + * generic/tkWindow.c: It Means using the new facilties of [package] + * library/tk.tcl: in Tcl 8.5 about what version(s) of Tcl it + * unix/Makefile.in: is willing to work with. [Bug 1578344]. + * win/Makefile.in: + * win/makefile.vc: + 2007-09-10 Jeff Hobbs * unix/README: typo corrections [Bug 1788682] diff --git a/generic/tkConsole.c b/generic/tkConsole.c index 1996825..f5969ee 100644 --- a/generic/tkConsole.c +++ b/generic/tkConsole.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. * - * RCS: @(#) $Id: tkConsole.c,v 1.32 2007/09/10 13:35:42 dgp Exp $ + * RCS: @(#) $Id: tkConsole.c,v 1.33 2007/09/11 17:46:41 dgp Exp $ */ #include "tk.h" @@ -233,7 +233,7 @@ Tk_InitConsoleChannels( * only an issue when Tk is loaded dynamically. */ - if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { + if (Tcl_InitStubs(interp, TCL_PATCH_LEVEL, 0) == NULL) { return; } diff --git a/generic/tkMain.c b/generic/tkMain.c index 3f15415..19ec30a 100644 --- a/generic/tkMain.c +++ b/generic/tkMain.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkMain.c,v 1.25 2007/09/10 13:35:42 dgp Exp $ + * RCS: @(#) $Id: tkMain.c,v 1.26 2007/09/11 17:46:41 dgp Exp $ */ #include @@ -110,7 +110,7 @@ Tk_MainEx( * only an issue when Tk is loaded dynamically. */ - if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { + if (Tcl_InitStubs(interp, TCL_PATCH_LEVEL, 0) == NULL) { abort(); } diff --git a/generic/tkWindow.c b/generic/tkWindow.c index 541b533..bda5079 100644 --- a/generic/tkWindow.c +++ b/generic/tkWindow.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWindow.c,v 1.83 2007/09/10 13:35:42 dgp Exp $ + * RCS: @(#) $Id: tkWindow.c,v 1.84 2007/09/11 17:46:41 dgp Exp $ */ #include "tkInt.h" @@ -2948,7 +2948,7 @@ Initialize( * only an issue when Tk is loaded dynamically. */ - if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { + if (Tcl_InitStubs(interp, TCL_PATCH_LEVEL, 0) == NULL) { return TCL_ERROR; } diff --git a/library/tk.tcl b/library/tk.tcl index 8ac9efa..c8d8587 100644 --- a/library/tk.tcl +++ b/library/tk.tcl @@ -3,7 +3,7 @@ # Initialization script normally executed in the interpreter for each # Tk-based application. Arranges class bindings for widgets. # -# RCS: @(#) $Id: tk.tcl,v 1.63 2007/05/18 19:21:59 dgp Exp $ +# RCS: @(#) $Id: tk.tcl,v 1.64 2007/09/11 17:46:41 dgp Exp $ # # Copyright (c) 1992-1994 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. @@ -12,8 +12,11 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. -# Insist on running with compatible versions of Tcl and Tk. -package require -exact Tcl 8.5a7 +package require Tcl 8.5 ;# Guard against [source] in an 8.4- interp + ;# before using 8.5 [package] features. +# Insist on running with compatible version of Tcl +package require Tcl 8.5a7-8.6 +# Verify that we have Tk binary and script components from the same release package require -exact Tk 8.5a7 # Create a ::tk namespace diff --git a/unix/Makefile.in b/unix/Makefile.in index 4e2e8fa..bc105f4 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -5,7 +5,7 @@ # "autoconf" program (constructs like "@foo@" will get replaced in the # actual Makefile. # -# RCS: @(#) $Id: Makefile.in,v 1.136 2007/09/06 19:34:02 dgp Exp $ +# RCS: @(#) $Id: Makefile.in,v 1.137 2007/09/11 17:46:41 dgp Exp $ # Current Tk version; used in various names. @@ -706,11 +706,10 @@ install-binaries: $(TK_LIB_FILE) $(TK_STUB_LIB_FILE) $(TK_BUILD_EXP_FILE) wish echo "Creating package index $(PKG_INDEX)"; \ rm -f $(PKG_INDEX); \ (\ - echo "if {![package vsatisfies [package provide Tcl] $(TCLVERSION)]} { return }";\ - echo "if {[package vcompare [package provide Tcl]\ - $(TCLVERSION)$(TCLPATCHL)] != 0} { return }";\ + echo "if {[catch {package present Tcl\ + $(TCLVERSION)$(TCLPATCHL)}]} { return }";\ relative=`echo | awk '{ORS=" "; split("$(TK_PKG_DIR)",a,"/"); for (f in a) {print ".."}}'`;\ - echo "package ifneeded Tk $(MAJOR_VERSION).$(MINOR_VERSION)$(TCLPATCHL)\ + echo "package ifneeded Tk $(MAJOR_VERSION).$(MINOR_VERSION)$(PATCH_LEVEL)\ [list load [file join \$$dir $${relative}$(TK_LIB_FILE)] Tk]";\ ) > $(PKG_INDEX); \ fi diff --git a/win/Makefile.in b/win/Makefile.in index 9acbbba..29c6d66 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -4,11 +4,12 @@ # "autoconf" program (constructs like "@foo@" will get replaced in the # actual Makefile. # -# RCS: @(#) $Id: Makefile.in,v 1.73 2007/05/14 20:58:28 dgp Exp $ +# RCS: @(#) $Id: Makefile.in,v 1.74 2007/09/11 17:46:42 dgp Exp $ TCLVERSION = @TCL_VERSION@ TCLPATCHL = @TCL_PATCH_LEVEL@ VERSION = @TK_VERSION@ +PATCH_LEVEL = @TK_PATCH_LEVEL@ #---------------------------------------------------------------- # Things you can change to personalize the Makefile for your own @@ -479,10 +480,9 @@ install-binaries: binaries @echo "Creating package index $(PKG_INDEX)"; @$(RM) $(PKG_INDEX); @(\ - echo "if {![package vsatisfies [package provide Tcl] $(TCLVERSION)]} { return }";\ - echo "if {[package vcompare [package provide Tcl]\ - $(TCLVERSION)$(TCLPATCHL)] != 0} { return }";\ - echo "package ifneeded Tk $(VERSION)$(TCLPATCHL)\ + echo "if {[catch {package present Tcl\ + $(TCLVERSION)$(TCLPATCHL)]} { return }";\ + echo "package ifneeded Tk $(VERSION)$(PATCH_LEVEL)\ [list load [file join \$$dir .. .. bin $(TK_DLL_FILE)] Tk]";\ ) > $(PKG_INDEX); @for i in tkConfig.sh $(TK_LIB_FILE) $(TK_STUB_LIB_FILE); \ diff --git a/win/makefile.vc b/win/makefile.vc index 54d9fe2..c3bca2a 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -12,7 +12,7 @@ # Copyright (c) 2001-2004 David Gravereaux. # #------------------------------------------------------------------------------ -# RCS: @(#) $Id: makefile.vc,v 1.103 2007/05/15 23:20:17 patthoyts Exp $ +# RCS: @(#) $Id: makefile.vc,v 1.104 2007/09/11 17:46:42 dgp Exp $ #------------------------------------------------------------------------------ # Check to see we are configured to build with MSVC (MSDEVDIR or MSVCDIR) @@ -963,8 +963,7 @@ install-binaries: !if !$(STATIC_BUILD) @echo creating package index @type << > $(OUT_DIR)\pkgIndex.tcl -if {![package vsatisfies [package provide Tcl] $(TCL_DOTVERSION)]} { return } -if {[package vcompare [package provide Tcl] $(TCL_DOTVERSION)$(TCL_PATCHLEVEL)] != 0} { return } +if {[catch {package present Tcl $(TCL_DOTVERSION)$(TCL_PATCHLEVEL)]} { return } package ifneeded Tk $(DOTVERSION)$(TCL_PATCHLEVEL) [list load [file join $$dir .. .. bin $(TKLIBNAME)] Tk] << @$(CPY) $(OUT_DIR)\pkgIndex.tcl "$(SCRIPT_INSTALL_DIR)\" -- cgit v0.12 lude /* 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) (T