diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2018-12-25 19:55:50 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2018-12-25 19:55:50 (GMT) |
commit | ff51550ee89b473c63df78de6b2a413f21105687 (patch) | |
tree | bcdca927ed2a7b05c647b9a6bfdfd4a7ca5c730e /tk8.6/macosx/README | |
parent | 01cbf5b15ea760408c24288ccb5cf8e0af9aa299 (diff) | |
download | blt-ff51550ee89b473c63df78de6b2a413f21105687.zip blt-ff51550ee89b473c63df78de6b2a413f21105687.tar.gz blt-ff51550ee89b473c63df78de6b2a413f21105687.tar.bz2 |
update tcl/tk
Diffstat (limited to 'tk8.6/macosx/README')
-rw-r--r-- | tk8.6/macosx/README | 572 |
1 files changed, 0 insertions, 572 deletions
diff --git a/tk8.6/macosx/README b/tk8.6/macosx/README deleted file mode 100644 index c63b8ae..0000000 --- a/tk8.6/macosx/README +++ /dev/null @@ -1,572 +0,0 @@ -Tcl/Tk macOS README ----------------------- - -This is the README file for the macOS/Darwin version of Tcl/Tk. - -1. Where to go for support --------------------------- - -- The tcl-mac mailing list on sourceforge is the best place to ask questions -specific to Tcl & Tk on macOS: - http://lists.sourceforge.net/lists/listinfo/tcl-mac -(this page also has a link to searchable archives of the list, please check them -before asking on the list, many questions have already been answered). - -- For general Tcl/Tk questions, the newsgroup comp.lang.tcl is your best bet: - http://groups.google.com/group/comp.lang.tcl/ - -- The Tcl'ers Wiki also has many pages dealing with Tcl & Tk on macOS, see - http://wiki.tcl.tk/_/ref?N=3753 - http://wiki.tcl.tk/_/ref?N=8361 - -- Please report bugs with Tk on macOS to the tracker: - http://core.tcl.tk/tk/reportlist - -2. Using Tcl/Tk on macOS ---------------------------- - -- There are two versions of Tk available on macOS: TkAqua using the native -aqua widgets and look&feel, and TkX11 using the traditional unix X11 wigets. -TkX11 requires an X11 server to be installed, such as Apple's X11 (which is -available as an optional or default install on recent macOS). -TkAqua and TkX11 can be distinguished at runtime via [tk windowingsystem]. - -- At a minimum, macOS 10.3 is required to run Tcl and TkX11. -TkAqua requires macOS 10.6 or later. - -- Unless weak-linking is used, Tcl/Tk built on macOS 10.x will not run on -10.y with y < x; on the other hand Tcl/Tk built on 10.y will always run on 10.x -with y <= x (but without any of the fixes and optimizations that would be -available in a binary built on 10.x). -Weak-linking is available on OS X 10.2 or later, it additionally allows Tcl/Tk -built on 10.x to run on any 10.y with x > y >= z (for a chosen z >= 2). - -- Wish checks the Resources/Scripts directory in its application bundle for a -file called AppMain.tcl, if found it is used as the startup script and the -Scripts folder is added to the auto_path. This can be used to emulate the old -OS9 TclTk droplets. - -- If standard input is a special file of zero length (e.g. /dev/null), Wish -brings up the Tk console window at startup. This is the case when double -clicking Wish in the Finder (or using 'open Wish.app' from the Terminal). - -- Tcl extensions can be installed in any of: - $HOME/Library/Tcl /Library/Tcl /System/Library/Tcl - $HOME/Library/Frameworks /Library/Frameworks /System/Library/Frameworks - (searched in that order). -Given a potential package directory $pkg, Tcl on OSX checks for the file -$pkg/Resources/Scripts/pkgIndex.tcl as well as the usual $pkg/pkgIndex.tcl. -This allows building extensions as frameworks with all script files contained in -the Resources/Scripts directory of the framework. - -- [load]able binary extensions can linked as either ordinary shared libraries -(.dylib) or as MachO bundles (since 8.4.10/8.5a3); bundles have the advantage -that they are [load]ed more efficiently from a tcl VFS (no temporary copy to the -native filesystem required). - -- The 'deploy' target of macosx/GNUmakefile installs the html manpages into the -standard documentation location in the Tcl/Tk frameworks: - Tcl.framework/Resources/Documentation/Reference/Tcl - Tk.framework/Resources/Documentation/Reference/Tk -No nroff manpages are installed by default by the GNUmakefile. - -- The Tcl and Tk frameworks can be installed in any of the system's standard -framework directories: - $HOME/Library/Frameworks /Library/Frameworks /System/Library/Frameworks - -- ${prefix}/bin/wish8.x is a script that calls a copy of 'Wish' contained in - Tk.framework/Resources - -- if 'Wish' is started from the Finder or via 'open', $argv may contain a -"-psn_XXXX" argument. This is the process serial number, you may need to filter -it out for cross platform compatibility of your scripts. - -- the env array is different when Wish is started from the Finder (i.e. via -LaunchServices) than when it (or tclsh) is invoked from the Terminal, in -particular PATH may not be what you expect. (Wish started by LaunchServices -inherits loginwindow's environment variables, which are essentially those set in -$HOME/.MacOSX/environment.plist, and are unrelated to those set in your shell). - -- TkAqua drawing is antialiased by default, but (outline) linewidth can be used -to control whether a line/shape is drawn antialiased. The antialiasing threshold -is 0 by default (i.e. antialias everything), it can be changed by setting - set tk::mac::CGAntialiasLimit <limit> -in your script before drawing, in which case lines (or shapes with outlines) -thinner than <limit> pixels will not be antialiased. - -- Text antialiasing by default uses the standard OS antialising settings. -Setting the global variable '::tk::mac::antialiasedtext' allows to control text -antialiasing from Tcl: a value of 1 enables AA, 0 disables AA and -1 restores -the default behaviour of respecting the OS settings. - -- Scrollbars: There are two scrollbar variants in Aqua, normal & small. The -normal scrollbar has a small dimension of 15, the small variant 11. -Access to the small variant was added in Tk 8.4.2. - -- The default metrics of native buttons, radiobuttons, checkboxes and -menubuttons in the Cocoa-based Tk 8.5.7 and later preserve compatibility with -the older Carbon-based implementation, you can turn off the compatibility -metrics to get more native-looking spacing by setting: - set tk::mac::useCompatibilityMetrics 0 - -- TkAqua provides access to native OS X images via the Tk native bitmap facility -(including any image file readable by NSImage). A native bitmap name is -interpreted as follows (in order): - - predefined builtin 32x32 icon name (stop, caution, document, etc) - - name defined by [tk::mac::iconBitmap] - - NSImage named image name - - NSImage url string - - 4-char OSType of IconServices icon -the syntax of [tk::mac::iconBitmap] is as follows: - tk::mac::iconBitmap name width height -kind value -where -kind is one of - -file icon of file at given path - -fileType icon of given file type - -osType icon of given 4-char OSType file type - -systemType icon for given IconServices 4-char OSType - -namedImage named NSImage for given name - -imageFile image at given path -This support was added with the Cocoa-based Tk 8.5.7. - -- TkAqua cursor names are interpred as follows (in order): - - standard or platform-specific Tk cursor name (c.f. cursors.n) - - @path to any image file readable by NSImage - - NSImage named image name -Support for the latter two was added with the Cocoa-based Tk 8.5.7. - -- The standard Tk dialog commands [tk_getOpenFile], [tk_chooseDirectory], -[tk_getSaveFile] and [tk_messageBox] all take an additional optional -command -parameter on TkAqua. If it is present, the given command prefix is evaluated at -the global level when the dialog closes, with the dialog command's result -appended (the dialog command itself returning an emtpy result). If the -parent -option is also present, the dialog is configured as a modeless (window-modal) -sheet attached to the parent window and the dialog command returns immediately. -Support for -command was added with the Cocoa-based Tk 8.5.7. - -- The TkAqua-specific [tk::mac::standardAboutPanel] command brings the standard -Cocoa about panel to the front, with all its information filled in from your -application bundle files (i.e. standard about panel with no options specified). -See Apple Technote TN2179 and the AppKit documentation for -[NSApplication -orderFrontStandardAboutPanelWithOptions:] for details on the Info.plist keys and -app bundle files used by the about panel. -This support was added with the Cocoa-based Tk 8.5.7. - -- TkAqua has three special menu names that give access to the standard -Application, Window and Help menus, see menu.n for details. -By default, the platform-specific standard Help menu item "YourApp Help" peforms -the default Cocoa action of showing the Help Book configured in the -application's Info.plist (or displaying an alert if no Help Book is set). This -action can be customized by defining a procedure named [tk::mac::ShowHelp], if -present, this procedure is invoked instead by the standard Help menu item. -Support for the Window menu and [tk::mac::ShowHelp] was added with the -Cocoa-based Tk 8.5.7. - -- The TkAqua-specific command [tk::unsupported::MacWindowStyle style] is used to -get and set macOS-specific toplevel window class and attributes. Note that -the window class and many attributes have to be set before the window is first -mapped for the change to have any effect. -The command has the following syntax: - tk::unsupported::MacWindowStyle style window ?class? ?attributes? -The 2 argument form returns a list of the current class and attributes for the -given window. The 3 argument form sets the class for the given window using the -default attributes for that class. The 4 argument form sets the class and the -list of attributes for the given window. -Window class names: - document, modal, floating, utility, toolbar, simple, help, overlay -Window attribute names: - standardDocument, standardFloating, resizable, fullZoom, horizontalZoom, - verticalZoom, closeBox, collapseBox, toolbarButton, sideTitlebar, - noTitleBar, unifiedTitleAndToolbar, metal, hud, noShadow, doesNotCycle, - noActivates, hideOnSuspend, inWindowMenu, ignoreClicks, doesNotHide, - canJoinAllSpaces, moveToActiveSpace, nonActivating - -Note that not all attributes are valid for all window classes. -Support for the 3 argument form was added with the Cocoa-based Tk 8.5.7, at the -same time support for some legacy Carbon-specific classes and attributes was -removed (they are still accepted by the command but no longer have any effect). - -If you want to use Remote Debugging with Xcode, you need to set the -environment variable XCNOSTDIN to 1 in the Executable editor for Wish. That will -cause us to force closing stdin & stdout. Otherwise, given how Xcode launches -Wish remotely, they will be left open and then Wish & gdb will fight for stdin. - - -3. Building Tcl/Tk on macOS ------------------------------- - -- At least macOS 10.3 is required to build Tcl and TkX11, and macOS 10.6 -is required to build TkAqua. The XCode application provides everything -needed to build Tk, but it is not necessary to install the full XCode. -It suffices to install the Command Line Tools package, which can be done -by running the command: -xcode-selecct --install - -- Tcl/Tk are most easily built as macOS frameworks via GNUmakefile in -tcl/macosx and tk/macosx (see below for details), but can also be built with the -standard unix configure and make buildsystem in tcl/unix resp. tk/unix as on any -other unix platform (indeed, the GNUmakefiles are just wrappers around the unix -buildsystem). -The macOS specific configure flags are --enable-aqua, --enable-framework and ---disable-corefoundation (which disables CF and notably reverts to the standard -select based notifier). Note that --enable-aqua is incompatible with ---disable-corefoundation (for both Tcl and Tk configure). - -- It was once possible to build with the Xcode IDE via the projects in -tk/macosx, but this has not been tested recently. Take care to use the -project matching your DevTools and OS version: - Tk.xcode: for Xcode 3.1 on 10.5 - Tk.xcodeproj: for Xcode 3.2 on 10.6 -These have the following targets: - Tk: calls through to tk/macosx/GNUMakefile, - requires a corresponding build of the Tcl - target of tcl/macosx/Tcl.xcode. - tktest: static build of TkAqua tktest for debugging. - tktest-X11: static build of TkX11 tktest for debugging. -The following build configurations are available: - Debug: debug build for the active architecture, - with Fix & Continue enabled. - Debug clang: use clang compiler. - Debug llvm-gcc: use llvm-gcc compiler. - Debug gcc40: use gcc 4.0 compiler. - DebugNoGC: disable Objective-C garbage collection. - DebugNoFixAndContinue: disable Fix & Continue. - DebugUnthreaded: disable threading. - DebugNoCF: disable corefoundation (X11 only). - DebugNoCFUnthreaded: disable corefoundation an threading. - DebugMemCompile: enable memory and bytecode debugging. - DebugLeaks: define PURIFY. - DebugGCov: enable generation of gcov data files. - Debug64bit: configure with --enable-64bit (requires - building on a 64bit capable processor). - Release: release build for the active architecture. - ReleaseUniversal: 32/64-bit universal build. - ReleaseUniversal clang: use clang compiler. - ReleaseUniversal llvm-gcc: use llvm-gcc compiler. - ReleaseUniversal gcc40: use gcc 4.0 compiler. - ReleaseUniversal10.5SDK: build against the 10.5 SDK (with 10.5 - deployment target). - Note that the non-SDK configurations have their deployment target set to - 10.5 (Tk.xcode) resp. 10.6 (Tk.xcodeproj). -The Xcode projects refer to the toplevel tcl and tk source directories via the -the TCL_SRCROOT and TK_SRCROOT user build settings, by default these are set to -the project-relative paths '../../tcl' and '../../tk', if your source -directories are named differently, e.g. '../../tcl8.6' and '../../tk8.6', you -need to manually change the TCL_SRCROOT and TK_SRCROOT settings by editing your -${USER}.pbxuser file (located inside the Tk.xcodeproj bundle directory) with a -text editor. - -- To build universal binaries outside of the Xcode IDE, set CFLAGS as follows: - export CFLAGS="-arch i386 -arch x86_64 -arch ppc" -This requires macOS 10.4 and Xcode 2.4 (or Xcode 2.2 if -arch x86_64 is -omitted, but _not_ Xcode 2.1) and will work on any architecture (on PowerPC -Tiger you need to add "-isysroot /Developer/SDKs/MacOSX10.4u.sdk"). -Note that configure requires CFLAGS to contain a least one architecture that can -be run on the build machine (i.e. ppc on G3/G4, ppc or ppc64 on G5, ppc or i386 -on Core and ppc, i386 or x86_64 on Core2/Xeon). -Universal builds of Tcl TEA extensions are also possible with CFLAGS set as -above, they will be [load]able by universal as well as thin binaries of Tcl. - -- To enable weak-linking, set the MACOSX_DEPLOYMENT_TARGET environment variable -to the minimal OS version the binaries should be able to run on, e.g: - export MACOSX_DEPLOYMENT_TARGET=10.6 -This requires at least gcc 3.1; with gcc 4 or later, set/add to CFLAGS instead: - export CFLAGS="-mmacosx-version-min=10.6" -Support for weak-linking was added with 8.4.14/8.5a5. - -Detailed Instructions for building with macosx/GNUmakefile ----------------------------------------------------------- - -- Unpack the Tcl and Tk source release archives and place the tcl and tk source -trees in a common parent directory. -[ If you don't want have the two source trees in one directory, you'll need to ] -[ create the following symbolic link for the build to work as setup by default ] -[ ln -fs /path_to_tcl/build /path_to_tk/build ] -[ (where /path_to_{tcl,tk} is the directory containing the tcl resp. tk tree) ] -[ or you can pass an argument of BUILD_DIR=/somewhere to the tcl and tk make. ] - -- The following instructions assume the Tcl and Tk source trees are named -"tcl${ver}" and "tk${ver}" (where ${ver} is a shell variable containing the -Tcl/Tk version number, e.g. '8.6'). -Setup this shell variable as follows: - ver="8.6" -If you are building from CVS, omit this step (CVS source tree names usually do -not contain a version number). - -- Setup environment variables as desired, e.g. for a universal build on 10.5: - CFLAGS="-arch i386 -arch x86_64 -arch ppc -mmacosx-version-min=10.5" - export CFLAGS - -- Change to the directory containing the Tcl and Tk source trees and build: - make -C tcl${ver}/macosx - make -C tk${ver}/macosx - -- Install Tcl and Tk onto the root volume (admin password required): - sudo make -C tcl${ver}/macosx install - sudo make -C tk${ver}/macosx install -if you don't have an admin password, you can install into your home directory -instead by passing an INSTALL_ROOT argument to make: - make -C tcl${ver}/macosx install INSTALL_ROOT="${HOME}/" - make -C tk${ver}/macosx install INSTALL_ROOT="${HOME}/" - -- The default GNUmakefile targets will build _both_ debug and optimized versions -of the Tcl and Tk frameworks with the standard convention of naming the debug -library Tcl.framework/Tcl_debug resp. Tk.framework/Tk_debug. -This allows switching to the debug libraries at runtime by setting - export DYLD_IMAGE_SUFFIX=_debug -(c.f. man dyld for more details) - -If you only want to build and install the debug or optimized build, use the -'develop' or 'deploy' target variants of the GNUmakefile, respectively. -For example, to build and install only the optimized versions: - make -C tcl${ver}/macosx deploy - make -C tk${ver}/macosx deploy - sudo make -C tcl${ver}/macosx install-deploy - sudo make -C tk${ver}/macosx install-deploy - -- The GNUmakefile can also build a version of Wish.app that has the Tcl and Tk -frameworks embedded in its application package. This allows for standalone -deployment of the application with no installation required, e.g. from read-only -media. To build & install in this manner, use the 'embedded' variants of -the GNUmakefile targets. -For example, to build a standalone 'Wish.app' in ./emb/Applications/Utilities: - make -C tcl${ver}/macosx embedded - make -C tk${ver}/macosx embedded - sudo make -C tcl${ver}/macosx install-embedded INSTALL_ROOT=`pwd`/emb/ - sudo make -C tk${ver}/macosx install-embedded INSTALL_ROOT=`pwd`/emb/ -Notes: - * if you've already built standard TclTkAqua, building embedded does not - require any new compiling or linking, so you can skip the first two makes. - (making relinking unnecessary was added with 8.4.2) - * the embedded frameworks include only optimized builds and no documentation. - * the standalone Wish has the directory Wish.app/Contents/lib in its - auto_path. Thus you can place tcl extensions in this directory (i.e. embed - them in the app package) and load them with [package require]. - -- It is possible to build Tk against an installed Tcl.framework; but you will -still need a tcl sourcetree in the location specified in TCL_SRC_DIR in -Tcl.framework/tclConfig.sh. Also, linking with Tcl.framework has to work exactly -as indicated in TCL_LIB_SPEC in Tcl.framework/tclConfig.sh. -If you used non-default install locations for Tcl.framework, specify them as -make overrides to the tk/macosx GNUmakefile, e.g. - make -C tk${ver}/macosx \ - TCL_FRAMEWORK_DIR=$HOME/Library/Frameworks TCLSH_DIR=$HOME/usr/bin - sudo make -C tk${ver}/macosx install \ - TCL_FRAMEWORK_DIR=$HOME/Library/Frameworks TCLSH_DIR=$HOME/usr/bin -The Makefile variables TCL_FRAMEWORK_DIR and TCLSH_DIR were added with Tk 8.4.3. - -4. Details regarding the macOS port of Tk. -------------------------------------------- - -4.1 About the event loop -~~~~~~~~~~~~~~~~~~~~~~~~ - -The main program in a typical OSX application looks like this (see -https://developer.apple.com/library/mac/documentation/Cocoa/\ -Reference/ApplicationKit/Classes/NSApplication_Class) - - void NSApplicationMain(int argc, char *argv[]) { - [NSApplication sharedApplication]; - [NSBundle loadNibNamed:@"myMain" owner:NSApp]; - [NSApp run]; - } -Here NSApp is a standard global variable, initialized by the OS, which -points to an object in a subclass of NSApplication (called -TKApplication in the case of the macOS port of Tk). - -The [NSApp run] method implements the event loop for a typical Mac -application. There are three key steps in the run method. First it -calls [NSApp finishLaunching], which creates the bouncing application -icon and does other mysterious things. Second it creates an -NSAutoreleasePool. Third, it starts an event loop which drains the -NSAutoreleasePool every time the queue is empty, and replaces the -drained pool with a new one. This third step is essential to -preventing memory leaks, since the internal methods of Appkit objects -all assume that an autorelease pool is in scope and will be drained -when the event processing cycle ends. - -The macOS Tk application does not call the [NSApp run] method at -all. Instead it uses the event loop built in to Tk. So the -application must take care to replicate the important features of the -method ourselves. The way that autorelease pools are handled is -discussed in 4.2 below. Here we discuss the event handling itself. - -The Tcl event loop simply consists of repeated calls to TclDoOneEvent. -Each call to TclDoOneEvent begins by collecting all pending events from -an "event source", converting them to Tcl events and adding them -to the Tcl event queue. For macOS, the event source is the NSApp -object, which maintains an event queue even though its run method -will never be called to process them. The NSApp provides methods for -inspecting the queue and removing events from it as well as the -[NSApp sendevent] which sends an event to all of the application's -NSWindows which can then send it to subwindows, etc. - -The event collection process consists of first calling a platform -specific SetupProc and then a platform specific CheckProc. In -the macOS port, these are named TkMacOSXEventsSetupProc and -TkMacOSXEventsCheckProc. - -It is important to understand that the Apple window manager does not -have the concept of an expose event. Their replacement for an expose -event is to have the window manager call the [NSView drawRect] method -in any situation where an expose event for that NSView would be -generated in X11. The [NSView drawRect] method is a no-op which is -expected to be overridden by any application. In the case of Tcl, the -replacement [NSView drawRect] method creates a Tcl expose event -for each dirty rectangle of the NSView, and then adds the expose -event to the Tcl queue. - - -4.2 Autorelease pools -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In order to carry out the job of managing autorelease pools, which -would normally be handled by the [NSApp run] method, a private -NSAUtoreleasePool* property is added to the TkApplication subclass of -NSApplication. The TkpInit function calls [NSApp _setup] which -initializes this property by creating an NSAutoreleasePool prior to -calling [NSApp finishLaunching]. This mimics the behavior of the -[NSApp run] method, which calls [NSApp finishLaunching] just before -starting the event loop. - -Since the CheckProc function gets called for every Tk event, it is an -appropriate place to drain the main NSAutoreleasePool and replace it -with a new pool. This is done by calling the method [NSApp -_resetAutoreleasePool], where _resetAutoreleasePool is a method which -we define for the subclass. Unfortunately, by itself this is not -sufficient for safe memory managememt because, as was made painfully -evident with the release of OS X 10.13, it is possible for calls to -TclDoOneEvent, and hence to CheckProc, to be nested. Draining the -autorelease pool in a nested call leads to crashes as objects in use -by the outer call can get freed by the inner call and then reused later. -One particular situation where this happens is when a modal dialogue -gets posted by a Tk Application. To address this, the NSApp object -also implements a semaphore to prevent draining the autorelease pool -in nested calls to CheckProc. - -One additional minor caveat for developers is that there are several -steps of the Tk initialization which precede the call to TkpInit. -Notably, the font package is initialized first. Since there is no -NSAUtoreleasePool in scope prior to calling TkpInit, the functions -called in these preliminary stages need to create and drain their own -NSAutoreleasePools whenever they call methods of Appkit objects -(e.g. NSFont). - -4.3 Clipping regions and "ghost windows" -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Another unusual aspect of the macOS port is its use of clipping -regions. It was part of Daniel Steffen's original design that the -TkWindowPrivate struct maintains three HIShapeRef regions, named -visRgn, aboveVisRgn and drawRgn. These regions are used as clipping -masks whenever drawing into an NSView. The visRgn is the bounding box -of the window with a rectangle removed for each subwindow and for each -sibling window at a higher stacking level. The drawRgn is the -intersection of the visRgn with the clipping rectangle of the -window. (Normally, the clipping rectangle is the same as the bounding -rectangle, but drawing can be clipped to a smaller rectangle by -calling TkpClipDrawableToRect.) The aboveVisRgn is the intersection of -the window's bounding rectangle with the bounding rectangle of the -parent window. Much of the code in tkMacOSXSubindows.c is devoted to -rebuilding these clipping regions whenever something changes in the -layout of the windows. This turns out to be a tricky thing to do and -it is extremely prone to errors which can be difficult to trace. - -It is not entirely clear what the original reason for using these -clipping regions was. But one benefit is that if they are correctly -maintained then it allows windows to be drawn in any order. You do -not have to draw them in the order of the window hierarchy. Each -window can draw its entire rectangle through its own mask and never -have to worry about drawing in the wrong place. It is likely that -the need for using clipping regions arose because, as Apple explicitly -states in the documentation for [NSView subviews], - - "The order of the subviews may be considered as being - back-to-front, but this does not imply invalidation and drawing - behavior." - -In the early versions of the macOS port, buttons were implemented as -subviews of class TkButton. This probably exacerbated the likelihood -that Tk windows would need to be drawn in arbitrary order. - -The most obvious side effect caused by not maintaining the clipping -regions is the appearance of so-called "ghost windows". A common -situation where these may arise is when a window containing buttons -is being scrolled. A user may see two images of the same button on -the screen, one in the pre-scroll location and one in the post-scroll -location. - -To see how these 'ghost windows' can arise, think about what happens if -the clipping regions are not maintained correctly. A window might -have a rectangle missing from its clipping region because that -rectangle is the bounding rectangle for a subwindow, say a button. -The parent should not draw in the missing rectangle since doing so -would trash the button. The button is responsible for drawing -there. Now imagine that the button gets moved, say by a scroll, but -the missing rectangle in the parent's clipping region does not get -moved correctly, or it gets moved later on, after the parent has -redrawn itself. The parent would still not be allowed to draw in the -old rectangle, so the user would continue to see the image of the -button in its old location, as well as another image in the new -location. This is a prototypical example of a "ghost window". -Anytime you see a "ghost window", you should suspect problems with the -updates to the clipping region visRgn. It is natural to look for -timing issues, race conditions, or other "event loop problems". But -in fact, the whole design of the code is to make those timing issues -irrelevant. As long as the clipping regions are correctly maintained -the timing does not matter. And if they are not correctly maintained -then you will see "ghost windows". - -It is worth including a detailed description of one specific place -where the failure to correctly maintain clipping regions caused "ghost -window" artifacts that plagued the macOS port for years. These -occurred when scrolling a Text widget which contained embedded -subwindows. It involved some specific differences between the -low-level behavior of Apple's window manager versus those of the other -platforms, and the fix ultimately required changes in the generic Tk -implementation (documented in the comments in the DisplayText -function). - -The Text widget attempts to improve perfomance when scrolling by -minimizing the number of text lines which need to be redisplayed. It -does this by calling the platform-specific TkScrollWindow function -which uses a low-level routine to map one rectangle of the window to -another. The TkScrollWindow function returns a damage region which is -then used by the Text widget's DisplayText function to determine which -text lines need to be redrawn. On the unix and win platforms, this -damage region includes bounding rectangles for all embedded windows -inside the Text widget. The way that this works is system dependent. -On unix, the low level scrolling is done by XCopyRegion, which -generates a GraphicsExpose event for each embedded window. These -GraphicsExposed events are processsed within TkScrollWindow, using a -special handler which adds the bounding rectangle of each subwindow to -the damage region. On the win platform the damage region is built by -the low level function ScrollWindowEx, and it also includes bounding -rectangles for all embedded windows. This is possible because on X11 -and Windows every Tk widget is also known to the window manager as a -window. The situation is different on macOS. The underlying object -for a top level window on macOS is the NSView. However, Apple -explicitly warns in its documentation that performance degradation -occurs when an NSView has more than about 100 subviews. A Text widget -with thousands of lines of text could easily contain more than 100 -embedded windows. In fact, while the original Cocoa port of Tk did -use the NSButton object, which is derived from NSView, as the basis -for its Tk Buttons, that was changed in order to improve performance. -Moreover, the low level routine used for scrolling on macOS, namely -[NSView scrollrect:by], does not provide any damage information. So -TkScrollWindow needs to work differently on macOS. Since it would be -inefficient to iterate through all embedded windows in a Text widget, -looking for those which meet the scrolling area, the damage region -constructed by TkScrollWindow contains only the difference between the -source and destination rectangles for the scrolling. The embedded -windows are redrawn within the DisplayText function by some -conditional code which is only used for macOS. - -5.0 Virtual events on 10.14 -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -10.14 supports system appearance changes, and has added a "Dark Mode" -that casts all window frames and menus as black. Tk 8.6.9 has added two -virtual events, <<LightAqua>> and <<DarkAqua>>, to allow you to update -your Tk app's appearance when the system appearance changes. Just bind -your appearance-updating code to these virtual events and you will see -it triggered when the system appearance toggles between dark and light. |