OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / tk8.6.12 / macosx / README
1 Tcl/Tk macOS README
2 ----------------------
3
4 This is the README file for the macOS/Darwin version of Tcl/Tk.
5
6 1. Where to go for support
7 --------------------------
8
9 - The tcl-mac mailing list on sourceforge is the best place to ask questions
10 specific to Tcl & Tk on macOS:
11         http://lists.sourceforge.net/lists/listinfo/tcl-mac
12 (this page also has a link to searchable archives of the list, please check them
13 before asking on the list, many questions have already been answered).
14
15 - For general Tcl/Tk questions, the newsgroup comp.lang.tcl is your best bet:
16         http://groups.google.com/group/comp.lang.tcl/
17
18 - The Tcl'ers Wiki also has many pages dealing with Tcl & Tk on macOS, see
19         https://wiki.tcl-lang.org/page/MacOS
20
21 - Please report bugs with Tk on macOS to the tracker:
22         https://core.tcl-lang.org/tk/reportlist
23
24 2. Using Tcl/Tk on macOS
25 ---------------------------
26
27 - There are two versions of Tk available on macOS: TkAqua using the native
28 aqua widgets and look&feel, and TkX11 using the traditional unix X11 widgets.
29 TkX11 requires an X11 server to be installed, such as XQuartz (available from www.xquartz.org).
30 TkAqua and TkX11 can be distinguished at runtime via [tk windowingsystem].
31
32 - At a minimum, macOS 10.3 is required to run Tcl and TkX11.
33 TkAqua requires macOS 10.6 or later.
34
35 - Unless weak-linking is used, Tcl/Tk built on macOS 10.x will not run on
36 10.y with y < x; on the other hand Tcl/Tk built on 10.y will always run on 10.x
37 with y <= x (but without any of the fixes and optimizations that would be
38 available in a binary built on 10.x).
39 Weak-linking is available on OS X 10.2 or later, it additionally allows Tcl/Tk
40 built on 10.x to run on any 10.y with x > y >= z (for a chosen z >= 2).
41
42 - Wish checks the Resources/Scripts directory in its application bundle for a
43 file called AppMain.tcl, if found it is used as the startup script and the
44 Scripts folder is added to the auto_path. This can be used to emulate the old
45 OS9 TclTk droplets.
46
47 - If standard input is a special file of zero length (e.g. /dev/null), Wish
48 brings up the Tk console window at startup. This is the case when double
49 clicking Wish in the Finder (or using 'open Wish.app' from the Terminal).
50
51 - Tcl extensions can be installed in any of:
52         $HOME/Library/Tcl /Library/Tcl
53         $HOME/Library/Frameworks /Library/Frameworks
54         (searched in that order).
55 Given a potential package directory $pkg, Tcl on OSX checks for the file
56 $pkg/Resources/Scripts/pkgIndex.tcl as well as the usual $pkg/pkgIndex.tcl.
57 This allows building extensions as frameworks with all script files contained in
58 the Resources/Scripts directory of the framework.
59
60 - The 'deploy' target of macosx/GNUmakefile installs the html manpages into the
61 standard documentation location in the Tcl/Tk frameworks:
62         Tcl.framework/Resources/Documentation/Reference/Tcl
63         Tk.framework/Resources/Documentation/Reference/Tk
64 No nroff manpages are installed by default by the GNUmakefile.
65
66 - The Tcl and Tk frameworks can be installed in any of the system's standard
67 framework directories:
68         $HOME/Library/Frameworks /Library/Frameworks
69
70 - ${prefix}/bin/wish8.x is a script that calls a copy of 'Wish' contained in
71         Tk.framework/Resources
72
73 - if 'Wish' is started from the Finder or via 'open', $argv may contain a
74 "-psn_XXXX" argument. This is the process serial number, you may need to filter
75 it out for cross platform compatibility of your scripts.
76
77 - the env array is different when Wish is started from the Finder (i.e. via
78 LaunchServices) than when it (or tclsh) is invoked from the Terminal, in
79 particular PATH may not be what you expect. (Wish started by LaunchServices
80 inherits loginwindow's environment variables, which are essentially those set in
81 $HOME/.MacOSX/environment.plist, and are unrelated to those set in your shell).
82
83 - TkAqua provides access to native OS X images via the Tk native bitmap facility
84 (including any image file readable by NSImage). A native bitmap name is
85 interpreted as follows (in order):
86     - predefined builtin 32x32 icon name (stop, caution, document, etc)
87     - name defined by [tk::mac::iconBitmap]
88     - NSImage named image name
89     - NSImage url string
90     - 4-char OSType of IconServices icon
91 the syntax of [tk::mac::iconBitmap] is as follows:
92         tk::mac::iconBitmap name width height -kind value
93 where -kind is one of
94     -file           icon of file at given path
95     -fileType       icon of given file type
96     -osType         icon of given 4-char OSType file type
97     -systemType     icon for given IconServices 4-char OSType
98     -namedImage     named NSImage for given name
99     -imageFile      image at given path
100 This support was added with the Cocoa-based Tk 8.5.7.
101
102 - TkAqua cursor names are interpred as follows (in order):
103     - standard or platform-specific Tk cursor name (c.f. cursors.n)
104     - @path to any image file readable by NSImage
105     - NSImage named image name
106 Support for the latter two was added with the Cocoa-based Tk 8.5.7.
107
108 - The standard Tk dialog commands [tk_getOpenFile], [tk_chooseDirectory],
109 [tk_getSaveFile] and [tk_messageBox] all take an additional optional -command
110 parameter on TkAqua. If it is present, the given command prefix is evaluated at
111 the global level when the dialog closes, with the dialog command's result
112 appended (the dialog command itself returning an emtpy result). If the -parent
113 option is also present, the dialog is configured as a modeless (window-modal)
114 sheet attached to the parent window and the dialog command returns immediately.
115 Support for -command was added with the Cocoa-based Tk 8.5.7.
116
117 - The TkAqua-specific [tk::mac::standardAboutPanel] command brings the standard
118 Cocoa about panel to the front, with all its information filled in from your
119 application bundle files (i.e. standard about panel with no options specified).
120 See Apple Technote TN2179 and the AppKit documentation for -[NSApplication
121 orderFrontStandardAboutPanelWithOptions:] for details on the Info.plist keys and
122 app bundle files used by the about panel.
123 This support was added with the Cocoa-based Tk 8.5.7.
124
125 - TkAqua has three special menu names that give access to the standard
126 Application, Window and Help menus, see menu.n for details.  By default, the
127 platform-specific standard Help menu item "YourApp Help" performs the default
128 Cocoa action of showing the Help Book configured in the application's
129 Info.plist (or displaying an alert if no Help Book is set). This action can be
130 customized by defining a procedure named [tk::mac::ShowHelp]. If present, this
131 procedure is invoked instead by the standard Help menu item.  Support for the
132 Window menu and [tk::mac::ShowHelp] was added with the Cocoa-based Tk 8.5.7.
133
134 - The TkAqua-specific command [tk::unsupported::MacWindowStyle style] is used to
135 get and set macOS-specific toplevel window class and attributes. Note that
136 the window class and many attributes have to be set before the window is first
137 mapped for the change to have any effect.
138 The command has the following syntax:
139         tk::unsupported::MacWindowStyle style window ?class? ?attributes?
140 The 2 argument form returns a list of the current class and attributes for the
141 given window. The 3 argument form sets the class for the given window using the
142 default attributes for that class. The 4 argument form sets the class and the
143 list of attributes for the given window.
144 Window class names:
145     document, modal, floating, utility, toolbar, simple, help, overlay
146 Window attribute names:
147     standardDocument, standardFloating, resizable, fullZoom, horizontalZoom,
148     verticalZoom, closeBox, collapseBox, toolbarButton, sideTitlebar,
149     noTitleBar, unifiedTitleAndToolbar, metal, hud, noShadow, doesNotCycle,
150     noActivates, hideOnSuspend, inWindowMenu, ignoreClicks, doesNotHide,
151     canJoinAllSpaces, moveToActiveSpace, nonActivating
152
153 Note that not all attributes are valid for all window classes.  Support for the
154 3 argument form was added with the Cocoa-based Tk 8.5.7, at the same time
155 support for some legacy Carbon-specific classes and attributes was removed
156 (they are still accepted by the command but no longer have any effect).
157
158 - Another command available in the tk::unsupported::MacWindowStyle namespace is:
159   tk::unsupported::MacWindowStyle tabbingid window ?newId?
160 which can be used to get or set the tabbingIdentifier for the NSWindow
161 associated with a Tk Window.  See section 3 for details.
162
163 - The command:
164   tk::unsupported::MacWindowStyle appearance window ?newAppearance?
165 is available when Tk is built and run on macOS 10.14 (Mojave) or later.  In
166 that case the Ttk widgets all support the "Dark Mode" appearance which was
167 introduced in 10.14. The command accepts the following values for the optional
168 newAppearance option: "aqua", "darkaqua", or "auto".  If the appearance is set
169 to aqua or darkaqua then the window will be displayed with the corresponding
170 appearance independent of any preferences settings.  If it is set to "auto"
171 the appearance will be determined by the preferences.  This command can be
172 used to opt out of Dark Mode on a per-window basis. It may be best to run the "update" command before setting the appearance property, to allow the event loop to run.
173
174
175 - To determine the current appearance of a window in macOS 10.14 (Mojave) and
176 higher, one can use the command:
177   tk::unsupported::MacWindowStyle isdark window?
178 The boolean return value is true if the window is currently displayed with the
179 dark appearance.
180
181 - If you want to use Remote Debugging with Xcode, you need to set the
182 environment variable XCNOSTDIN to 1 in the Executable editor for Wish. That will
183 cause us to force closing stdin & stdout.  Otherwise, given how Xcode launches
184 Wish remotely, they will be left open and then Wish & gdb will fight for stdin.
185
186 3. FullScreen, Split View and Tabbed Windows
187 --------------------------------------------
188
189 Since the release of OSX 10.6 (Snow Leopard) a steadily expanding sequence of
190 high level window operations have been added to Apple's window manager.  These
191 operations are launched by user actions which are handled directly by the
192 window manager; they are not initiated by the application.  In some, but not
193 all cases, the application is notified before and after the operations are
194 carried out.
195
196 In OSX releases up to and including 10.6 there were three buttons with
197 stoplight colors located on the left side of a window's title bar.  The
198 function of the green button was to "zoom" or "maximize" the window, i.e. to
199 expand the window so that it fills the entire screen, while preserving the
200 appearance of the window including its title bar.  The release of OSX 10.7
201 (Lion) introduced the "FullScreen" window which not only filled the screen but
202 also hid the window's title bar and the menu bar which normally appears at the
203 top of the screen. These hidden objects would only become visible when the
204 mouse hovered near the top of the screen.  FullScreen mode was initiated by
205 pressing a button showing two outward pointing arrows located on the right side
206 of the title bar; it was terminated by pressing a similar button with inward
207 pointing arrows on the right hand side of the menu bar.  In OSX 10.10
208 (Yosemite) the FullScreen button was removed. The green button was repurposed
209 to cause a window to become a FullScreen window. To zoom a window the user had
210 to hold down the option key while pressing the green button.  The release of
211 OSX 10.11 added a third function to the green button: to create two half-screen
212 windows with hidden title bars and a hidden menu bar, called Split View
213 windows.  If the green button is held down for one second its window expands to
214 fill half of the screen.  It can be moved to one side or the other with the
215 mouse.  The opposite side shows thumbnail images of other windows.  Selecting
216 one of the thumbnails expands its window to fill that half of the screen.  The
217 divider between the two windows can be moved to adjust the percentage of the
218 screen occupied by each of the two tiles.  In OSX 10.12 (Sierra) Tabbed windows
219 were introduced.  These allow an application with multiple windows to display
220 its windows as tabs within a single window frame.  Clicking on a tab brings its
221 window into view.  Tabs can be rearranged by dragging.  Dragging a tab to the
222 desktop turns it into a separate window.  Items in the Window menu can be used
223 to cycle through the tabs, move tabbed windows to separate windows, or merge a
224 set of separate windows as tabs in the same window frame.
225
226 Tk now fully supports all of these high level window operations on any system
227 where the operation exists.  The FullScreen and Split View windows are handled
228 automatically with no action required on the part of the programmer.  Tabbed
229 windows, on the other hand, require some attention from the programmer.
230 Because many of the operations with tabs are handled through the application's
231 Window menu, it is essential that an application provide a Windows menu to
232 avoid presenting a confusing interface to the user. This cannot be ignored, in
233 part because the systemwide Dock Preferences offers an option to always attempt
234 to open application windows as tabs. An application which does not provide a
235 Window menu will necessarily present a confusing interface to any user who has
236 selected this option.
237
238 A further complication is that it is not neccessarily appropriate for all of an
239 application's windows to be grouped together as tabs in the same frame.  In
240 fact, the Apple guidelines insist that windows which are grouped together as
241 tabs should be similar to each other.  The mechanism provided for arranging
242 this was to assign to each NSwindow a tabbingIdentifier, and to require that
243 all windows grouped together as tabs in the same window frame must have the
244 same tabbingIdentifier.  A tabbingIdentifier is implemented as an arbitrary
245 string, and a system-generated default tabbingIdentifier is provided to all new
246 windows.
247
248 Tk provides a means for getting and setting the tabbingIdentifier of
249 the NSWindow underlying a Tk Window. This is handled by the command
250
251 tk::unsupported::MacWindowStyle tabbingid window ?newId?
252
253 (This command generates an error if used on OSX 10.11 or earlier, since the
254 tabbingIdentifier does not exist on those systems.)  The command returns the
255 tabbingIdentifier which had been assigned to the window prior to execution of
256 the command.  If the optional newId argument is omitted, the window's
257 tabbingIdentifier is not changed.  Otherwise it is set to the string specified
258 by the argument.
259
260 Since NSWindows can only be grouped together as tabs if they all have the same
261 tabbingIdentifier, one can prevent a window from becoming a tab by giving it a
262 unique tabbingIdentifier. This is independent of any preferences setting. To
263 ensure that we maintain consistency, changing the tabbingIdentifier of a window
264 which is already displayed as a tab will also cause it to become a separate
265 window.
266
267 4. Ttk, Dark Mode and semantic colors
268 ---------------------------------------
269
270 With the release of OSX 10.14 (Mojave), Apple introduced the DarkAqua
271 appearance.  Part of the implementation of the Dark Mode was to make
272 some of the named NSColors have dynamic values.  Apple calls these
273 "semantic colors" because the name does not specify a specific color,
274 but rather refers to the context in which the color should be used.
275 Tk now provides the following semantic colors as system colors:
276 systemTextColor, systemTextBackgroundColor, systemSelectedTextColor,
277 systemSelectedTextBackgroundColor, systemControlTextColor,
278 systemDisabledControlTextColor, systemLabelColor, systemLinkColor, and
279 systemControlAccentColor.  All of these except the last three were
280 present in OSX 10.0 (and those three are simulated in systems where they
281 do not exist).  The change in 10.14 was that the RGB color value of
282 these colors became dynamic, meaning that the color value can change
283 when the application appearance changes.  In particular, when a user
284 selects Dark Mode in the system preferences these colors change
285 appearance.  For example systemTextColor is dark in Aqua and light in
286 DarkAqua.  One additional color, systemSelectedTabTextColor, does not
287 exist in macOS but is used by Tk to match the different colors used
288 for Notebook tab text in different OS versions.
289
290 The default background and foreground colors of most of the Tk widgets
291 have been set to semantic colors, which means that the widgets will change
292 appearance, and remain usable, when Dark Mode is selected in the system
293 preferences.  However, to get a close match to the native Dark Mode style it
294 is recommended to use Ttk widgets when possible.
295
296 Apple's tab view and GroupBox objects delimit their content by
297 displaying it within a rounded rectangle with a background color that
298 contrasts with the background of the containing object.  This means
299 that the background color of a Ttk widget depends on how deeply it is
300 nested inside of other widgets that use contrasting backgrounds.  To
301 support this, there are 8 contrasting system colors named
302 systemWindowBackgroundColor, and systemWindowBackgroundColor1 - 7.
303 The systemWindowBackgroundColor is the standard background for a
304 dialog window and the others match the contrasting background colors
305 used in ttk::notebooks and ttk::labelframes which are nested to the
306 corresponding depth.
307
308 5. Building Tcl/Tk on macOS
309 ------------------------------
310
311 - macOS 10.6 is required to build TkAqua and TkX11.  The XCode application provides everything needed to build Tk, but it is not necessary to install the full XCode.
312 It suffices to install the Command Line Tools package, which can be done
313 by running the command:
314 xcode-select --install
315
316 - Tcl/Tk are most easily built as macOS frameworks via GNUmakefile in
317 tcl/macosx and tk/macosx (see below for details), but can also be built with the
318 standard unix configure and make buildsystem in tcl/unix resp. tk/unix as on any
319 other unix platform (indeed, the GNUmakefiles are just wrappers around the unix
320 buildsystem).
321 The macOS specific configure flags are --enable-aqua, --enable-framework and
322 --disable-corefoundation (which disables CF and notably reverts to the standard
323 select based notifier). Note that --enable-aqua is incompatible with
324 --disable-corefoundation (for both Tcl and Tk configure).
325
326 - It was once possible to build with the Xcode IDE via the projects in
327 tk/macosx, but this has not been tested recently. Take care to use the
328 project matching your DevTools and OS version:
329         Tk.xcode:                   for Xcode 3.1 on 10.5
330         Tk.xcodeproj:               for Xcode 3.2 on 10.6
331 These have the following targets:
332         Tk:                         calls through to tk/macosx/GNUMakefile,
333                                     requires a corresponding build of the Tcl
334                                     target of tcl/macosx/Tcl.xcode.
335         tktest:                     static build of TkAqua tktest for debugging.
336         tktest-X11:                 static build of TkX11 tktest for debugging.
337 The following build configurations are available:
338         Debug:                      debug build for the active architecture,
339                                     with Fix & Continue enabled.
340         Debug clang:                use clang compiler.
341         Debug llvm-gcc:             use llvm-gcc compiler.
342         Debug gcc40:                use gcc 4.0 compiler.
343         DebugNoGC:                  disable Objective-C garbage collection.
344         DebugNoFixAndContinue:      disable Fix & Continue.
345         DebugUnthreaded:            disable threading.
346         DebugNoCF:                  disable corefoundation (X11 only).
347         DebugNoCFUnthreaded:        disable corefoundation an threading.
348         DebugMemCompile:            enable memory and bytecode debugging.
349         DebugLeaks:                 define PURIFY.
350         DebugGCov:                  enable generation of gcov data files.
351         Debug64bit:                 configure with --enable-64bit (requires
352                                     building on a 64bit capable processor).
353         Release:                    release build for the active architecture.
354         ReleaseUniversal:           32/64-bit universal build.
355         ReleaseUniversal clang:     use clang compiler.
356         ReleaseUniversal llvm-gcc:  use llvm-gcc compiler.
357         ReleaseUniversal gcc40:     use gcc 4.0 compiler.
358         ReleaseUniversal10.5SDK:    build against the 10.5 SDK (with 10.5
359                                     deployment target).
360         Note that the non-SDK configurations have their deployment target set to
361         10.5 (Tk.xcode) resp. 10.6 (Tk.xcodeproj).
362 The Xcode projects refer to the toplevel tcl and tk source directories via the
363 the TCL_SRCROOT and TK_SRCROOT user build settings, by default these are set to
364 the project-relative paths '../../tcl' and '../../tk', if your source
365 directories are named differently, e.g. '../../tcl8.6' and '../../tk8.6', you
366 need to manually change the TCL_SRCROOT and TK_SRCROOT settings by editing your
367 ${USER}.pbxuser file (located inside the Tk.xcodeproj bundle directory) with a
368 text editor.
369
370 - To enable weak-linking, set the MACOSX_DEPLOYMENT_TARGET environment variable
371 to the minimal OS version the binaries should be able to run on, e.g:
372         export MACOSX_DEPLOYMENT_TARGET=10.6
373 This requires at least gcc 3.1; with gcc 4 or later, set/add to CFLAGS instead:
374         export CFLAGS="-mmacosx-version-min=10.6"
375 Support for weak-linking was added with 8.4.14/8.5a5.
376
377 Detailed Instructions for building with macosx/GNUmakefile
378 ----------------------------------------------------------
379
380 - Unpack the Tcl and Tk source release archives and place the tcl and tk source
381 trees in a common parent directory.
382 [ If you don't want have the two source trees in one directory, you'll need to ]
383 [ create the following symbolic link for the build to work as setup by default ]
384 [      ln -fs /path_to_tcl/build /path_to_tk/build                             ]
385 [ (where /path_to_{tcl,tk} is the directory containing the tcl resp. tk tree)  ]
386 [ or you can pass an argument of BUILD_DIR=/somewhere to the tcl and tk make.  ]
387
388 - The following instructions assume the Tcl and Tk source trees are named
389 "tcl${ver}" and "tk${ver}" (where ${ver} is a shell variable containing the
390 Tcl/Tk version number, e.g. '8.6').
391 Setup this shell variable as follows:
392         ver="8.6"
393 If you are building from CVS, omit this step (CVS source tree names usually do
394 not contain a version number).
395
396 - Setup environment variables as desired, e.g. for a universal build on 10.5:
397         CFLAGS="-arch i386 -arch x86_64 -arch ppc -mmacosx-version-min=10.5"
398         export CFLAGS
399
400 - Change to the directory containing the Tcl and Tk source trees and build:
401         make -C tcl${ver}/macosx
402         make -C tk${ver}/macosx
403
404 - Install Tcl and Tk onto the root volume (admin password required):
405         sudo make -C tcl${ver}/macosx install
406         sudo make -C tk${ver}/macosx  install
407 if you don't have an admin password, you can install into your home directory
408 instead by passing an INSTALL_ROOT argument to make:
409         make -C tcl${ver}/macosx install INSTALL_ROOT="${HOME}/"
410         make -C tk${ver}/macosx  install INSTALL_ROOT="${HOME}/"
411
412 - The default GNUmakefile targets will build _both_ debug and optimized versions
413 of the Tcl and Tk frameworks with the standard convention of naming the debug
414 library Tcl.framework/Tcl_debug resp. Tk.framework/Tk_debug.
415 This allows switching to the debug libraries at runtime by setting
416         export DYLD_IMAGE_SUFFIX=_debug
417 (c.f. man dyld for more details)
418
419 If you only want to build and install the debug or optimized build, use the
420 'develop' or 'deploy' target variants of the GNUmakefile, respectively.
421 For example, to build and install only the optimized versions:
422         make -C tcl${ver}/macosx deploy
423         make -C tk${ver}/macosx deploy
424         sudo make -C tcl${ver}/macosx install-deploy
425         sudo make -C tk${ver}/macosx  install-deploy
426
427 - The GNUmakefile can also build a version of Wish.app that has the Tcl and Tk
428 frameworks embedded in its application package. This allows for standalone
429 deployment of the application with no installation required, e.g. from read-only
430 media. To build & install in this manner, use the 'embedded' variants of
431 the GNUmakefile targets.
432 For example, to build a standalone 'Wish.app' in ./emb/Applications/Utilities:
433         make -C tcl${ver}/macosx embedded
434         make -C tk${ver}/macosx embedded
435         sudo make -C tcl${ver}/macosx install-embedded INSTALL_ROOT=`pwd`/emb/
436         sudo make -C tk${ver}/macosx  install-embedded INSTALL_ROOT=`pwd`/emb/
437 Notes:
438   * if you've already built standard TclTkAqua, building embedded does not
439   require any new compiling or linking, so you can skip the first two makes.
440   (making relinking unnecessary was added with 8.4.2)
441   * the embedded frameworks include only optimized builds and no documentation.
442   * the standalone Wish has the directory Wish.app/Contents/lib in its
443   auto_path. Thus you can place tcl extensions in this directory (i.e. embed
444   them in the app package) and load them with [package require].
445
446 - It is possible to build Tk against an installed Tcl.framework; but you will
447 still need a tcl sourcetree in the location specified in TCL_SRC_DIR in
448 Tcl.framework/tclConfig.sh. Also, linking with Tcl.framework has to work exactly
449 as indicated in TCL_LIB_SPEC in Tcl.framework/tclConfig.sh.
450 If you used non-default install locations for Tcl.framework, specify them as
451 make overrides to the tk/macosx GNUmakefile, e.g.
452         make -C tk${ver}/macosx \
453             TCL_FRAMEWORK_DIR=$HOME/Library/Frameworks TCLSH_DIR=$HOME/usr/bin
454         sudo make -C tk${ver}/macosx install \
455             TCL_FRAMEWORK_DIR=$HOME/Library/Frameworks TCLSH_DIR=$HOME/usr/bin
456 The Makefile variables TCL_FRAMEWORK_DIR and TCLSH_DIR were added with Tk 8.4.3.
457
458 - To build a Tcl.framework and Tk.framework for use as subframeworks in another
459 framework, use the install-embedded target and set SUBFRAMEWORK=1.  Set the
460 DYLIB_INSTALL_DIR variable to the path which should be the install_name path of
461 the shared library and set the DESTDIR variable to the pathname of a staging
462 directory where the frameworks will be written.  The Tcl framework must be
463 built first.
464 For example, running the commands:
465         make -C ../tcl8.6/macosx install-embedded SUBFRAMEWORK=1 DESTDIR=/tmp/tcltk \
466         DYLIB_INSTALL_DIR=/Library/Frameworks/Some.framework/Versions/X.Y/Frameworks/Tcl.framework
467         make -C macosx install-embedded SUBFRAMEWORK=1 DESTDIR=/tmp/tcltk \
468         DYLIB_INSTALL_DIR=/Library/Frameworks/Some.framework/Versions/X.Y/Frameworks/Tk.framework
469 will produce a Tcl.framework and a Tk.framework usable as subframeworks of
470 Some.framework.  The frameworks will be found in /tmp/tcltk/Frameworks/
471
472 5. Details regarding the macOS port of Tk.
473 -------------------------------------------
474
475 5.1 About the event loop
476 ~~~~~~~~~~~~~~~~~~~~~~~~
477
478 The main program in a typical OSX application looks like this (see
479 https://developer.apple.com/library/mac/documentation/Cocoa/\
480 Reference/ApplicationKit/Classes/NSApplication_Class)
481
482     void NSApplicationMain(int argc, char *argv[]) {
483         [NSApplication sharedApplication];
484         [NSBundle loadNibNamed:@"myMain" owner:NSApp];
485         [NSApp run];
486     }
487 Here NSApp is a standard global variable, initialized by the OS, which
488 points to an object in a subclass of NSApplication (called
489 TKApplication in the case of the macOS port of Tk).
490
491 The [NSApp run] method implements the event loop for a typical Mac
492 application.  There are three key steps in the run method.  First it
493 calls [NSApp finishLaunching], which creates the bouncing application
494 icon and does other mysterious things. Second it creates an
495 NSAutoreleasePool.  Third, it starts an event loop which drains the
496 NSAutoreleasePool every time the queue is empty, and replaces the
497 drained pool with a new one.  This third step is essential to
498 preventing memory leaks, since the internal methods of Appkit objects
499 all assume that an autorelease pool is in scope and will be drained
500 when the event processing cycle ends.
501
502 The macOS Tk application does not call the [NSApp run] method at
503 all.  Instead it uses the event loop built in to Tk.  So the
504 application must take care to replicate the important features of the
505 method ourselves.  The way that autorelease pools are handled is
506 discussed in 5.2 below.  Here we discuss the event handling itself.
507
508 The Tcl event loop simply consists of repeated calls to TclDoOneEvent.
509 Each call to TclDoOneEvent begins by collecting all pending events from
510 an "event source", converting them to Tcl events and adding them
511 to the Tcl event queue. For macOS, the event source is the NSApp
512 object, which maintains an event queue even though its run method
513 will never be called to process them.  The NSApp provides methods for
514 inspecting the queue and removing events from it as well as the
515 [NSApp sendevent] which sends an event to all of the application's
516 NSWindows which can then send it to subwindows, etc.
517
518 The event collection process consists of first calling a platform
519 specific SetupProc and then a platform specific CheckProc.  In
520 the macOS port, these are named TkMacOSXEventsSetupProc and
521 TkMacOSXEventsCheckProc.
522
523 It is important to understand that the Apple window manager does not
524 have the concept of an expose event.  Their replacement for an expose
525 event is to have the window manager call the [NSView drawRect] method
526 in any situation where an expose event for that NSView would be
527 generated in X11.  The [NSView drawRect] method is a no-op which is
528 expected to be overridden by any application.  In the case of Tcl, the
529 replacement [NSView drawRect] method creates a Tcl expose event
530 for each dirty rectangle of the NSView, and then adds the expose
531 event to the Tcl queue.
532
533
534 5.2 Autorelease pools
535 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
536
537 In order to carry out the job of managing autorelease pools, which
538 would normally be handled by the [NSApp run] method, a private
539 NSAutoreleasePool* property is added to the TkApplication subclass of
540 NSApplication. The TkpInit function calls [NSApp _setup] which
541 initializes this property by creating an NSAutoreleasePool prior to
542 calling [NSApp finishLaunching].  This mimics the behavior of the
543 [NSApp run] method, which calls [NSApp finishLaunching] just before
544 starting the event loop.
545
546 Since the CheckProc function gets called for every Tk event, it is an
547 appropriate place to drain the main NSAutoreleasePool and replace it
548 with a new pool.  This is done by calling the method [NSApp
549 _resetAutoreleasePool], where _resetAutoreleasePool is a method which
550 we define for the subclass.  Unfortunately, by itself this is not
551 sufficient for safe memory managememt because, as was made painfully
552 evident with the release of OS X 10.13, it is possible for calls to
553 TclDoOneEvent, and hence to CheckProc, to be nested.  Draining the
554 autorelease pool in a nested call leads to crashes as objects in use
555 by the outer call can get freed by the inner call and then reused later.
556 One particular situation where this happens is when a modal dialogue
557 gets posted by a Tk Application.  To address this, the NSApp object
558 also implements a semaphore to prevent draining the autorelease pool
559 in nested calls to CheckProc.
560
561 One additional minor caveat for developers is that there are several
562 steps of the Tk initialization which precede the call to TkpInit.
563 Notably, the font package is initialized first.  Since there is no
564 NSAutoreleasePool in scope prior to calling TkpInit, the functions
565 called in these preliminary stages need to create and drain their own
566 NSAutoreleasePools whenever they call methods of Appkit objects
567 (e.g. NSFont).
568
569 5.3 Clipping regions and "ghost windows"
570 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
571
572 Another unusual aspect of the macOS port is its use of clipping
573 regions.  It was part of Daniel Steffen's original design that the
574 TkWindowPrivate struct maintains three HIShapeRef regions, named
575 visRgn, aboveVisRgn and drawRgn.  These regions are used as clipping
576 masks whenever drawing into an NSView.  The visRgn is the bounding box
577 of the window with a rectangle removed for each subwindow and for each
578 sibling window at a higher stacking level.  The drawRgn is the
579 intersection of the visRgn with the clipping rectangle of the
580 window. (Normally, the clipping rectangle is the same as the bounding
581 rectangle, but drawing can be clipped to a smaller rectangle by
582 calling TkpClipDrawableToRect.) The aboveVisRgn is the intersection of
583 the window's bounding rectangle with the bounding rectangle of the
584 parent window.  Much of the code in tkMacOSXSubwindows.c is devoted to
585 rebuilding these clipping regions whenever something changes in the
586 layout of the windows.  This turns out to be a tricky thing to do and
587 it is extremely prone to errors which can be difficult to trace.
588
589 It is not entirely clear what the original reason for using these
590 clipping regions was.  But one benefit is that if they are correctly
591 maintained then it allows windows to be drawn in any order.  You do
592 not have to draw them in the order of the window hierarchy.  Each
593 window can draw its entire rectangle through its own mask and never
594 have to worry about drawing in the wrong place.  It is likely that
595 the need for using clipping regions arose because, as Apple explicitly
596 states in the documentation for [NSView subviews],
597
598     "The order of the subviews may be considered as being
599     back-to-front, but this does not imply invalidation and drawing
600     behavior."
601
602 In the early versions of the macOS port, buttons were implemented as
603 subviews of class TkButton.  This probably exacerbated the likelihood
604 that Tk windows would need to be drawn in arbitrary order.
605
606 The most obvious side effect caused by not maintaining the clipping
607 regions is the appearance of so-called "ghost windows".  A common
608 situation where these may arise is when a window containing buttons
609 is being scrolled.  A user may see two images of the same button on
610 the screen, one in the pre-scroll location and one in the post-scroll
611 location.
612
613 To see how these 'ghost windows' can arise, think about what happens if
614 the clipping regions are not maintained correctly.  A window might
615 have a rectangle missing from its clipping region because that
616 rectangle is the bounding rectangle for a subwindow, say a button.
617 The parent should not draw in the missing rectangle since doing so
618 would trash the button.  The button is responsible for drawing
619 there. Now imagine that the button gets moved, say by a scroll, but
620 the missing rectangle in the parent's clipping region does not get
621 moved correctly, or it gets moved later on, after the parent has
622 redrawn itself.  The parent would still not be allowed to draw in the
623 old rectangle, so the user would continue to see the image of the
624 button in its old location, as well as another image in the new
625 location.  This is a prototypical example of a "ghost window".
626 Anytime you see a "ghost window", you should suspect problems with the
627 updates to the clipping region visRgn.  It is natural to look for
628 timing issues, race conditions, or other "event loop problems".  But
629 in fact, the whole design of the code is to make those timing issues
630 irrelevant.  As long as the clipping regions are correctly maintained
631 the timing does not matter.  And if they are not correctly maintained
632 then you will see "ghost windows".
633
634 It is worth including a detailed description of one specific place
635 where the failure to correctly maintain clipping regions caused "ghost
636 window" artifacts that plagued the macOS port for years.  These
637 occurred when scrolling a Text widget which contained embedded
638 subwindows.  It involved some specific differences between the
639 low-level behavior of Apple's window manager versus those of the other
640 platforms, and the fix ultimately required changes in the generic Tk
641 implementation (documented in the comments in the DisplayText
642 function).
643
644 The Text widget attempts to improve perfomance when scrolling by
645 minimizing the number of text lines which need to be redisplayed.  It
646 does this by calling the platform-specific TkScrollWindow function
647 which uses a low-level routine to map one rectangle of the window to
648 another.  The TkScrollWindow function returns a damage region which is
649 then used by the Text widget's DisplayText function to determine which
650 text lines need to be redrawn.  On the unix and win platforms, this
651 damage region includes bounding rectangles for all embedded windows
652 inside the Text widget.  The way that this works is system dependent.
653 On unix, the low level scrolling is done by XCopyRegion, which
654 generates a GraphicsExpose event for each embedded window.  These
655 GraphicsExposed events are processsed within TkScrollWindow, using a
656 special handler which adds the bounding rectangle of each subwindow to
657 the damage region.  On the win platform the damage region is built by
658 the low level function ScrollWindowEx, and it also includes bounding
659 rectangles for all embedded windows.  This is possible because on X11
660 and Windows every Tk widget is also known to the window manager as a
661 window.  The situation is different on macOS.  The underlying object
662 for a top level window on macOS is the NSView.  However, Apple
663 explicitly warns in its documentation that performance degradation
664 occurs when an NSView has more than about 100 subviews.  A Text widget
665 with thousands of lines of text could easily contain more than 100
666 embedded windows.  In fact, while the original Cocoa port of Tk did
667 use the NSButton object, which is derived from NSView, as the basis
668 for its Tk Buttons, that was changed in order to improve performance.
669 Moreover, the low level routine used for scrolling on macOS, namely
670 [NSView scrollrect:by], does not provide any damage information.  So
671 TkScrollWindow needs to work differently on macOS.  Since it would be
672 inefficient to iterate through all embedded windows in a Text widget,
673 looking for those which meet the scrolling area, the damage region
674 constructed by TkScrollWindow contains only the difference between the
675 source and destination rectangles for the scrolling.  The embedded
676 windows are redrawn within the DisplayText function by some
677 conditional code which is only used for macOS.
678
679 6.0 Virtual events on macOS 10.14 and later
680 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
681
682 The 10.14 release added support for system appearance changes,
683 including a "Dark Mode" that renders all window frames and menus in
684 dark colors. Tk 8.6 provides three virtual events <<LightAqua>>,
685 <<DarkAqua>> and <<AppearanceChanged>>, to allow you to update your Tk
686 app's appearance when the system appearance changes.  These events are
687 generated in [NSView effectiveAppearanceChanged], which is called by
688 the Apple window manager when the General Preferences is changed
689 either by switching between Light Mode and Dark Mode or by changing
690 the Accent Color or Highlight Color.
691
692 The <<AppearanceChanged>> virtual event has a data string which can be
693 accessed with the %d substitution.  The format of the data string is
694 that it consists of 6 words:
695   "Appearance XXXX Accent YYYY Highlight ZZZZ"
696 For example, the following code will print the current appearance
697 name, accent color and highlight color when the <<AppearanceChanged>>
698 virtual event fires:
699
700 bind . <<AppearanceChanged>> {
701     array set data [split %d]
702     puts "  Appearance: $data(Appearance)"
703     puts "  Accent: $data(Accent)"
704     puts "  Highlight: $data(Highlight)\n"
705 }
706
707
708
709 7.0 Mac Services
710 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
711
712 With 8.6.10, Tk supports the Mac's NSServices API, documented at
713 https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/SysServices/introduction.html#//apple_ref/doc/uid/10000101-SW1
714 and in TIP 536 and Tk's man page. Tk presents a simple,
715 straightforward API to implement the Services functionality.
716
717 The Tk implementation of the NSServices API is intended for standalone
718 applications, such as one wrapped by the standalone version of Wish
719 and re-named into a different application.  In particular such an
720 application would specify its own unique CFBundleIdentifier in its
721 Info.plist file.  During development, however, if Wish itself is being
722 used as the receiver, it may be necessary to take some care to ensure
723 that the correct version of Wish.app is available as a receiver of
724 NSServices data.
725
726 When one macOS app uses NSServices to send data to another app that is
727 not running, LaunchServices will launch the receiver.  LaunchServices
728 assumes that the CFBundleIdentifier uniquely identifies an app among
729 all of the apps installed on a system.  But this may not be the case
730 for Wish.app if, for example, you have compiled Tk from source at some
731 time in the past.  In that case the Tk build directory will contain
732 its own copy of Wish.app that will be visible to LaunchServices.  It
733 may be necessary when testing your app to take some steps to ensure
734 that LaunchServices is launching the correct Wish.app.  Instructions
735 for doing this are provided below.
736
737 The command line tool which manages the LaunchServices database has
738 an amazingly unwieldy path name.  So, first, run this command:
739
740 alias lsregister='/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister'
741
742 Then you can reset the LaunchServices database like this:
743
744 $ lsregister -kill
745 $ lsregister -seed
746
747 To find out which versions of Wish.app have been located by
748 LaunchServices, run:
749
750 $ lsregister -dump | grep path | grep Wish
751
752 If more than one version of Wish is showing up in this list, eliminate
753 all of the unintended targets by running
754
755 lsregister -u /path/to/bad/Wish.app
756
757 Continue this until only the correct version of Wish shows up in the
758 list.