Import Tk 8.6.10

This commit is contained in:
Steve Dower
2020-09-24 22:55:34 +01:00
parent 5ba5cbc9af
commit 42c69189d9
365 changed files with 24323 additions and 12832 deletions

View File

@@ -225,22 +225,6 @@ ifeq (${EMBEDDED_BUILD},1)
@rm -f "${INSTALL_ROOT}${BINDIR}/${WISH}" && \
rmdir -p "${INSTALL_ROOT}${BINDIR}" 2>&- || true
else
# redo prebinding (when not building for Mac OS X 10.4 or later only)
@if [ "`echo "$${MACOSX_DEPLOYMENT_TARGET}" | \
awk -F '10\\.' '{print int($$2)}'`" -lt 4 -a "`echo "$${CFLAGS}" | \
awk -F '-mmacosx-version-min=10\\.' '{print int($$2)}'`" -lt 4 ]; \
then cd ${INSTALL_ROOT}/; \
if [ ! -d usr/lib ]; then mkdir -p usr && ln -fs /usr/lib usr/ && RM_USRLIB=1; fi; \
if [ -n "${TK_X11}" -a ! -d usr/X11R6 ]; then mkdir -p usr && ln -fs /usr/X11R6 usr/ && RM_USRX11=1; fi; \
if [ ! -d System ]; then ln -fs /System . && RM_SYSTEM=1; fi; \
if [ ! -d "./${LIBDIR}/Tcl.framework" ]; then ln -fs "${TCL_FRAMEWORK_DIR}/Tcl.framework" "./${LIBDIR}"; RM_TCL=1; fi; \
redo_prebinding -r . "./${TK_FMWK_DIR}/${PRODUCT_NAME}"; \
if [ -z "${TK_X11}" ]; then redo_prebinding -r . "./${TK_FMWK_DIR}/Resources/Wish.app/Contents/MacOS/Wish"; \
else redo_prebinding -r . "./${BINDIR}/${WISH}"; fi; \
if [ -n "$${RM_USRLIB:-}" ]; then rm -f usr/lib; rmdir -p usr 2>&-; fi; \
if [ -n "$${RM_USRX11:-}" ]; then rm -f usr/X11R6; rmdir -p usr 2>&-; fi; \
if [ -n "$${RM_SYSTEM:-}" ]; then rm -f System; fi; \
if [ -n "$${RM_TCL:-}" ]; then rm -f "./${LIBDIR}/Tcl.framework"; fi; fi
# install wish symbolic link
@ln -fs ${WISH} "${INSTALL_ROOT}${BINDIR}/${wish}"
endif

View File

@@ -16,19 +16,17 @@ before asking on the list, many questions have already been answered).
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
https://wiki.tcl-lang.org/page/MacOS
- Please report bugs with Tk on macOS to the tracker:
http://core.tcl.tk/tk/reportlist
https://core.tcl-lang.org/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).
aqua widgets and look&feel, and TkX11 using the traditional unix X11 widgets.
TkX11 requires an X11 server to be installed, such as XQuartz (available from www.xquartz.org).
TkAqua and TkX11 can be distinguished at runtime via [tk windowingsystem].
- At a minimum, macOS 10.3 is required to run Tcl and TkX11.
@@ -51,19 +49,14 @@ 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
$HOME/Library/Tcl /Library/Tcl
$HOME/Library/Frameworks /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
@@ -72,7 +65,7 @@ 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
$HOME/Library/Frameworks /Library/Frameworks
- ${prefix}/bin/wish8.x is a script that calls a copy of 'Wish' contained in
Tk.framework/Resources
@@ -87,28 +80,6 @@ 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):
@@ -152,14 +123,13 @@ 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.
Application, Window and Help menus, see menu.n for details. By default, the
platform-specific standard Help menu item "YourApp Help" performs 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
@@ -180,26 +150,168 @@ Window attribute names:
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).
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
- Another command available in the tk::unsupported::MacWindowStyle namespace is:
tk::unsupported::MacWindowStyle tabbingid window ?newId?
which can be used to get or set the tabbingIdentifier for the NSWindow
associated with a Tk Window. See section 3 for details.
- The command:
tk::unsupported::MacWindowStyle appearance window ?newAppearance?
is available when Tk is built and run on macOS 10.14 (Mojave) or later. In
that case the Ttk widgets all support the "Dark Mode" appearance which was
introduced in 10.14. The command accepts the following values for the optional
newAppearance option: "aqua", "darkaqua", or "auto". If the appearance is set
to aqua or darkaqua then the window will be displayed with the corresponding
appearance independent of any preferences settings. If it is set to "auto"
the appearance will be determined by the preferences. This command can be
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.
- To determine the current appearance of a window in macOS 10.14 (Mojave) and
higher, one can use the command:
tk::unsupported::MacWindowStyle isdark window?
The boolean return value is true if the window is currently displayed with the
dark appearance.
- 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. FullScreen, Split View and Tabbed Windows
--------------------------------------------
3. Building Tcl/Tk on macOS
Since the release of OSX 10.6 (Snow Leopard) a steadily expanding sequence of
high level window operations have been added to Apple's window manager. These
operations are launched by user actions which are handled directly by the
window manager; they are not initiated by the application. In some, but not
all cases, the application is notified before and after the operations are
carried out.
In OSX releases up to and including 10.6 there were three buttons with
stoplight colors located on the left side of a window's title bar. The
function of the green button was to "zoom" or "maximize" the window, i.e. to
expand the window so that it fills the entire screen, while preserving the
appearance of the window including its title bar. The release of OSX 10.7
(Lion) introduced the "FullScreen" window which not only filled the screen but
also hid the window's title bar and the menu bar which normally appears at the
top of the screen. These hidden objects would only become visible when the
mouse hovered near the top of the screen. FullScreen mode was initiated by
pressing a button showing two outward pointing arrows located on the right side
of the title bar; it was terminated by pressing a similar button with inward
pointing arrows on the right hand side of the menu bar. In OSX 10.10
(Yosemite) the FullScreen button was removed. The green button was repurposed
to cause a window to become a FullScreen window. To zoom a window the user had
to hold down the option key while pressing the green button. The release of
OSX 10.11 added a third function to the green button: to create two half-screen
windows with hidden title bars and a hidden menu bar, called Split View
windows. If the green button is held down for one second its window expands to
fill half of the screen. It can be moved to one side or the other with the
mouse. The opposite side shows thumbnail images of other windows. Selecting
one of the thumbnails expands its window to fill that half of the screen. The
divider between the two windows can be moved to adjust the percentage of the
screen occupied by each of the two tiles. In OSX 10.12 (Sierra) Tabbed windows
were introduced. These allow an application with multiple windows to display
its windows as tabs within a single window frame. Clicking on a tab brings its
window into view. Tabs can be rearranged by dragging. Dragging a tab to the
desktop turns it into a separate window. Items in the Window menu can be used
to cycle through the tabs, move tabbed windows to separate windows, or merge a
set of separate windows as tabs in the same window frame.
Tk now fully supports all of these high level window operations on any system
where the operation exists. The FullScreen and Split View windows are handled
automatically with no action required on the part of the programmer. Tabbed
windows, on the other hand, require some attention from the programmer.
Because many of the operations with tabs are handled through the application's
Window menu, it is essential that an application provide a Windows menu to
avoid presenting a confusing interface to the user. This cannot be ignored, in
part because the systemwide Dock Preferences offers an option to always attempt
to open application windows as tabs. An application which does not provide a
Window menu will necessarily present a confusing interface to any user who has
selected this option.
A further complication is that it is not neccessarily appropriate for all of an
application's windows to be grouped together as tabs in the same frame. In
fact, the Apple guidelines insist that windows which are grouped together as
tabs should be similar to each other. The mechanism provided for arranging
this was to assign to each NSwindow a tabbingIdentifier, and to require that
all windows grouped together as tabs in the same window frame must have the
same tabbingIdentifier. A tabbingIdentifier is implemented as an arbitrary
string, and a system-generated default tabbingIdentifier is provided to all new
windows.
Tk provides a means for getting and setting the tabbingIdentifier of
the NSWindow underlying a Tk Window. This is handled by the command
tk::unsupported::MacWindowStyle tabbingid window ?newId?
(This command generates an error if used on OSX 10.11 or earlier, since the
tabbingIdentifier does not exist on those systems.) The command returns the
tabbingIdentifier which had been assigned to the window prior to execution of
the command. If the optional newId argument is omitted, the window's
tabbingIdentifier is not changed. Otherwise it is set to the string specified
by the argument.
Since NSWindows can only be grouped together as tabs if they all have the same
tabbingIdentifier, one can prevent a window from becoming a tab by giving it a
unique tabbingIdentifier. This is independent of any preferences setting. To
ensure that we maintain consistency, changing the tabbingIdentifier of a window
which is already displayed as a tab will also cause it to become a separate
window.
4. Ttk, Dark Mode and semantic colors
---------------------------------------
With the release of OSX 10.14 (Mojave), Apple introduced the DarkAqua
appearance. Part of the implementation of the Dark Mode was to make
some of the named NSColors have dynamic values. Apple calls these
"semantic colors" because the name does not specify a specific color,
but rather refers to the context in which the color should be used.
Tk now provides the following semantic colors as system colors:
systemTextColor, systemTextBackgroundColor, systemSelectedTextColor,
systemSelectedTextBackgroundColor, systemControlTextColor,
systemDisabledControlTextColor, systemLabelColor, and
systemControlAccentColor. All of these except the last two were
present in OSX 10.0 (and those two are simulated in systems where they
do not exist). The change in 10.14 was that the RGB color value of
these colors became dynamic, meaning that the color value can change
when the application appearance changes. In particular, when a user
selects Dark Mode in the system preferences these colors change
appearance. For example systemTextColor is dark in Aqua and light in
DarkAqua. One additional color, systemSelectedTabTextColor, does not
exist in macOS but is used by Tk to match the different colors used
for Notebook tab text in different OS versions.
The default background and foreground colors of most of the Tk widgets
have been set to semantic colors, which means that the widgets will change
appearance, and remain usable, when Dark Mode is selected in the system
preferences. However, to get a close match to the native Dark Mode style it
is recommended to use Ttk widgets when possible.
Apple's tab view and GroupBox objects delimit their content by
displaying it within a rounded rectangle with a background color that
contrasts with the background of the containing object. This means
that the background color of a Ttk widget depends on how deeply it is
nested inside of other widgets that use contrasting backgrounds. To
support this, there are 8 contrasting system colors named
systemWindowBackgroundColor, and systemWindowBackgroundColor1 - 7.
The systemWindowBackgroundColor is the standard background for a
dialog window and the others match the contrasting background colors
used in ttk::notebooks and ttk::labelframes which are nested to the
corresponding depth.
5. 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.
- 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.
It suffices to install the Command Line Tools package, which can be done
by running the command:
xcode-selecct --install
xcode-select --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
@@ -255,17 +367,6 @@ 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
@@ -354,10 +455,10 @@ make overrides to the tk/macosx GNUmakefile, e.g.
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.
5. Details regarding the macOS port of Tk.
-------------------------------------------
4.1 About the event loop
5.1 About the event loop
~~~~~~~~~~~~~~~~~~~~~~~~
The main program in a typical OSX application looks like this (see
@@ -388,7 +489,7 @@ 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.
discussed in 5.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
@@ -416,12 +517,12 @@ for each dirty rectangle of the NSView, and then adds the expose
event to the Tcl queue.
4.2 Autorelease pools
5.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
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
@@ -446,12 +547,12 @@ 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
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"
5.3 Clipping regions and "ghost windows"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Another unusual aspect of the macOS port is its use of clipping
@@ -466,7 +567,7 @@ 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
parent window. Much of the code in tkMacOSXSubwindows.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.
@@ -561,7 +662,7 @@ 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
6.0 Virtual events on 10.14
~~~~~~~~~~~~~~~~~~~~~~~~~~~
10.14 supports system appearance changes, and has added a "Dark Mode"
@@ -570,3 +671,54 @@ 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.
7.0 Mac Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~
With 8.6.10, Tk supports the Mac's NSServices API, documented at
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/SysServices/introduction.html#//apple_ref/doc/uid/10000101-SW1
and in TIP 536 and Tk's man page. Tk presents a simple,
straightforward API to implement the Services functionality.
The Tk implementation of the NSServices API is intended for standalone
applications, such as one wrapped by the standalone version of Wish
and re-named into a different application. In particular such an
application would specify its own unique CFBundleIdentifier in its
Info.plist file. During development, however, if Wish itself is being
used as the receiver, it may be necessary to take some care to ensure
that the correct version of Wish.app is available as a receiver of
NSServices data.
When one macOS app uses NSServices to send data to another app that is
not running, LaunchServices will launch the receiver. LaunchServices
assumes that the CFBundleIdentifier uniquely identifies an app among
all of the apps installed on a system. But this may not be the case
for Wish.app if, for example, you have compiled Tk from source at some
time in the past. In that case the Tk build directory will contain
its own copy of Wish.app that will be visible to LaunchServices. It
may be necessary when testing your app to take some steps to ensure
that LaunchServices is launching the correct Wish.app. Instructions
for doing this are provided below.
The command line tool which manages the LaunchServices database has
an amazingly unwieldy path name. So, first, run this command:
alias lsregister='/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister'
Then you can reset the LaunchServices database like this:
$ lsregister -kill
$ lsregister -seed
To find out which versions of Wish.app have been located by
LaunchServices, run:
$ lsregister -dump | grep path | grep Wish
If more than one version of Wish is showing up in this list, eliminate
all of the unintended targets by running
lsregister -u /path/to/bad/Wish.app
Continue this until only the correct version of Wish shows up in the
list.

View File

@@ -8,75 +8,101 @@
this file, and for a DISCLAIMER OF ALL WARRANTIES.
-->
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>tcl</string>
<string>TCL</string>
<string>*</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/x-tcl</string>
<string>text/plain</string>
</array>
<key>CFBundleTypeName</key>
<string>NSStringPboardType</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>TEXT</string>
<string>****</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<string>tcl</string>
<string>TCL</string>
<string>*</string>
</array>
<key>CFBundleExecutable</key>
<string>Wish</string>
<key>CFBundleGetInfoString</key>
<string>Wish Shell @TK_VERSION@@TK_PATCH_LEVEL@,
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 &amp; Ian Reid</string>
<key>CFBundleIconFile</key>
<string>Wish.icns</string>
<key>CFBundleIdentifier</key>
<string>com.tcltk.wish</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLocalizations</key>
<key>CFBundleTypeMIMETypes</key>
<array>
@CFBUNDLELOCALIZATIONS@
<string>application/x-tcl</string>
<string>text/plain</string>
</array>
<key>CFBundleName</key>
<key>CFBundleTypeName</key>
<string>NSStringPboardType</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>TEXT</string>
<string>****</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLSchemes</key>
<array>
<string>foo</string>
</array>
<key>CFBundleURLName</key>
<string>Get Foo</string>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>Wish</string>
<key>CFBundleGetInfoString</key>
<string>Wish Shell @TK_VERSION@@TK_PATCH_LEVEL@,
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 &amp; Ian Reid</string>
<key>CFBundleIconFile</key>
<string>Wish.icns</string>
<key>CFBundleIdentifier</key>
<string>com.tcltk.wish</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLocalizations</key>
<array>
@CFBUNDLELOCALIZATIONS@
</array>
<key>CFBundleName</key>
<string>Wish</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>@TK_VERSION@@TK_PATCH_LEVEL@</string>
<key>CFBundleSignature</key>
<string>WiSH</string>
<key>CFBundleVersion</key>
<string>@TK_VERSION@@TK_PATCH_LEVEL@</string>
<key>LSMinimumSystemVersion</key>
<string>10.6.0</string>
<key>LSRequiresCarbon</key>
<true/>
<key>NSAppleScriptEnabled</key>
<true/>
<key>OSAScriptingDefinition</key>
<string>Wish.sdef</string>
<key>NSHighResolutionCapable</key>
<string>True</string>
<key>NSServices</key>
<array>
<dict>
<key>NSMessage</key>
<string>provideService</string>
<key>NSPortName</key>
<string>Wish</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>@TK_VERSION@@TK_PATCH_LEVEL@</string>
<key>CFBundleSignature</key>
<string>WiSH</string>
<key>CFBundleVersion</key>
<string>@TK_VERSION@@TK_PATCH_LEVEL@</string>
<key>LSMinimumSystemVersion</key>
<string>10.6.0</string>
<key>LSRequiresCarbon</key>
<true/>
<key>NSAppleScriptEnabled</key>
<true/>
<key>OSAScriptingDefinition</key>
<string>Wish.sdef</string>
<key>NSHighResolutionCapable</key>
<string>True</string>
</dict>
<key>NSSendTypes</key>
<array>
<string>NSStringPboardType</string>
<string>NSPasteboardTypeString</string>
</array>
</dict>
</array>
</dict>
</plist>

View File

@@ -33,5 +33,14 @@
<type type="text"/>
</result>
</command>
<command name="open location" code="GURLGURL"
description="Open a URL.">
<direct-parameter description="URL" type="text">
<type type="text"/>
</direct-parameter>
<result description="Result">
<type type="text"/>
</result>
</command>
</suite>
</dictionary>

19
macosx/configure vendored
View File

@@ -2287,7 +2287,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
TK_VERSION=8.6
TK_MAJOR_VERSION=8
TK_MINOR_VERSION=6
TK_PATCH_LEVEL=".9"
TK_PATCH_LEVEL=".10"
VERSION=${TK_VERSION}
LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv"
@@ -2362,7 +2362,6 @@ $as_echo "$as_me: WARNING: --with-tcl argument should refer to directory contain
for i in `ls -d ~/Library/Frameworks 2>/dev/null` \
`ls -d /Library/Frameworks 2>/dev/null` \
`ls -d /Network/Library/Frameworks 2>/dev/null` \
`ls -d /System/Library/Frameworks 2>/dev/null` \
; do
if test -f "$i/Tcl.framework/tclConfig.sh" ; then
ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`"
@@ -2379,6 +2378,7 @@ $as_echo "$as_me: WARNING: --with-tcl argument should refer to directory contain
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib/tcl8.6 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
`ls -d /usr/local/lib/tcl8.6 2>/dev/null` \
@@ -4527,6 +4527,9 @@ $as_echo "$as_me: WARNING: can't find uname command" >&2;}
if test "`uname -s`" = "AIX" ; then
tcl_cv_sys_version=AIX-`uname -v`.`uname -r`
fi
if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then
tcl_cv_sys_version=NetBSD-Debian
fi
fi
fi
@@ -5596,12 +5599,6 @@ fi
SHLIB_SUFFIX=".dylib"
DL_OBJS="tclLoadDyld.o"
DL_LIBS=""
# Don't use -prebind when building for Mac OS X 10.4 or later only:
if test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int($2)}'`" -lt 4 -a \
"`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int($2)}'`" -lt 4; then :
LDFLAGS="$LDFLAGS -prebind"
fi
LDFLAGS="$LDFLAGS -headerpad_max_install_names"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -search_paths_first flag" >&5
$as_echo_n "checking if ld accepts -search_paths_first flag... " >&6; }
@@ -8123,8 +8120,8 @@ $as_echo "$enable_xft" >&6; }
XFT_LIBS=`xft-config --libs 2>/dev/null` || found_xft="no"
if test "$found_xft" = "no" ; then
found_xft=yes
XFT_CFLAGS=`pkg-config --cflags xft 2>/dev/null` || found_xft="no"
XFT_LIBS=`pkg-config --libs xft 2>/dev/null` || found_xft="no"
XFT_CFLAGS=`pkg-config --cflags xft fontconfig 2>/dev/null` || found_xft="no"
XFT_LIBS=`pkg-config --libs xft fontconfig 2>/dev/null` || found_xft="no"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $found_xft" >&5
$as_echo "$found_xft" >&6; }
@@ -8614,7 +8611,7 @@ if test "${SHARED_BUILD}" = "1" -a "${SHLIB_SUFFIX}" != ""; then
TCL_STUB_FLAGS="-DUSE_TCL_STUBS"
fi
TK_LIBRARY='$(prefix)/lib/tk$(VERSION)'
test -z "$TK_LIBRARY" && TK_LIBRARY='$(prefix)/lib/tk$(VERSION)'
PRIVATE_INCLUDE_DIR='$(includedir)'
HTML_DIR='$(DISTDIR)/html'
TK_PKG_DIR='tk$(VERSION)'

View File

@@ -49,6 +49,9 @@ static BuiltInIcon builtInIcons[] = {
#define builtInIconSize 32
#define OSTYPE_TO_UTI(x) (NSString *)UTTypeCreatePreferredIdentifierForTag( \
kUTTagClassOSType, UTCreateStringForOSType(x), nil)
static Tcl_HashTable iconBitmapTable = {};
typedef struct {
int kind, width, height;
@@ -107,14 +110,15 @@ TkpDefineNativeBitmaps(void)
}
}
}
/*
*----------------------------------------------------------------------
*
* GetBitmapForIcon --
* PixmapFromImage --
*
* Results:
* Bitmap for the given IconRef.
* Returns a Pixmap with an NSImage drawn into it.
*
* Side effects:
* None.
@@ -123,9 +127,9 @@ TkpDefineNativeBitmaps(void)
*/
static Pixmap
GetBitmapForIcon(
PixmapFromImage(
Display *display,
IconRef icon,
NSImage* image,
CGSize size)
{
TkMacOSXDrawingContext dc;
@@ -134,18 +138,22 @@ GetBitmapForIcon(
pixmap = Tk_GetPixmap(display, None, size.width, size.height, 0);
if (TkMacOSXSetupDrawingContext(pixmap, NULL, 1, &dc)) {
if (dc.context) {
const CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1,
.tx = 0, .ty = size.height };
const CGRect r = { .origin = { .x = 0, .y = 0 }, .size = size };
CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1,
.tx = 0, .ty = size.height};
CGContextConcatCTM(dc.context, t);
PlotIconRefInContext(dc.context, &r, kAlignAbsoluteCenter,
kTransformNone, NULL, kPlotIconRefNormalFlags, icon);
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext
graphicsContextWithGraphicsPort:dc.context
flipped:NO]];
[image drawAtPoint:NSZeroPoint fromRect:NSZeroRect
operation:NSCompositeCopy fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
}
TkMacOSXRestoreDrawingContext(&dc);
}
return pixmap;
}
/*
*----------------------------------------------------------------------
@@ -168,22 +176,14 @@ TkpCreateNativeBitmap(
Display *display,
const void *source) /* Info about the icon to build. */
{
Pixmap pixmap;
IconRef icon;
OSErr err;
err = ChkErr(GetIconRef, kOnSystemDisk, kSystemIconsCreator,
PTR2UINT(source), &icon);
if (err == noErr) {
pixmap = GetBitmapForIcon(display, icon, CGSizeMake(builtInIconSize,
builtInIconSize));
ReleaseIconRef(icon);
} else {
pixmap = Tk_GetPixmap(display, None, builtInIconSize,
builtInIconSize, 0);
}
NSString *iconUTI = OSTYPE_TO_UTI(PTR2UINT(source));
NSImage *iconImage = [[NSWorkspace sharedWorkspace]
iconForFileType: iconUTI];
CGSize size = CGSizeMake(builtInIconSize, builtInIconSize);
Pixmap pixmap = PixmapFromImage(display, iconImage, NSSizeToCGSize(size));
return pixmap;
}
/*
*----------------------------------------------------------------------
@@ -210,7 +210,7 @@ OSTypeFromString(const char *s, OSType *t) {
Tcl_UtfToExternalDString(encoding, s, -1, &ds);
if (Tcl_DStringLength(&ds) <= 4) {
char string[4] = {};
memcpy(string, Tcl_DStringValue(&ds), (size_t) Tcl_DStringLength(&ds));
memcpy(string, Tcl_DStringValue(&ds), Tcl_DStringLength(&ds));
*t = (OSType) string[0] << 24 | (OSType) string[1] << 16 |
(OSType) string[2] << 8 | (OSType) string[3];
result = TCL_OK;
@@ -219,6 +219,7 @@ OSTypeFromString(const char *s, OSType *t) {
Tcl_FreeEncoding(encoding);
return result;
}
/*
*----------------------------------------------------------------------
@@ -309,50 +310,17 @@ TkpGetNativeAppBitmap(
}
}
if (image) {
TkMacOSXDrawingContext dc;
int depth = 0;
#ifdef MAC_OSX_TK_TODO
for (NSImageRep *r in [image representations]) {
NSInteger bitsPerSample = [r bitsPerSample];
if (bitsPerSample && bitsPerSample > depth) {
depth = bitsPerSample;
};
}
if (depth == 1) {
/* TODO: convert BW NSImage to CGImageMask */
}
#endif
pixmap = Tk_GetPixmap(display, None, size.width, size.height, depth);
*width = size.width;
*height = size.height;
if (TkMacOSXSetupDrawingContext(pixmap, NULL, 1, &dc)) {
if (dc.context) {
CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1,
.tx = 0, .ty = size.height};
CGContextConcatCTM(dc.context, t);
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext
graphicsContextWithGraphicsPort:dc.context flipped:NO]];
[image drawAtPoint:NSZeroPoint fromRect:NSZeroRect
operation:NSCompositeCopy fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
}
TkMacOSXRestoreDrawingContext(&dc);
}
pixmap = PixmapFromImage(display, image, NSSizeToCGSize(size));
} else if (name) {
OSType iconType;
if (OSTypeFromString(name, &iconType) == TCL_OK) {
IconRef icon;
OSErr err = ChkErr(GetIconRef, kOnSystemDisk, kSystemIconsCreator,
iconType, &icon);
if (err == noErr) {
pixmap = GetBitmapForIcon(display, icon, NSSizeToCGSize(size));
*width = size.width;
*height = size.height;
ReleaseIconRef(icon);
}
NSString *iconUTI = OSTYPE_TO_UTI(iconType);
printf("Found image for UTI %s\n", iconUTI.UTF8String);
NSImage *iconImage = [[NSWorkspace sharedWorkspace]
iconForFileType: iconUTI];
pixmap = PixmapFromImage(display, iconImage, NSSizeToCGSize(size));
}
}
return pixmap;

File diff suppressed because it is too large Load Diff

View File

@@ -35,10 +35,7 @@ static Tk_Window clipboardOwner = NULL;
targetPtr->type == dispPtr->utf8Atom) {
for (TkClipboardBuffer *cbPtr = targetPtr->firstBufferPtr;
cbPtr; cbPtr = cbPtr->nextPtr) {
NSString *s = [[NSString alloc] initWithBytesNoCopy:
cbPtr->buffer length:cbPtr->length
encoding:NSUTF8StringEncoding freeWhenDone:NO];
NSString *s = TclUniToNSString(cbPtr->buffer, cbPtr->length);
[string appendString:s];
[s release];
}
@@ -123,8 +120,9 @@ TkSelGetSelection(
{
int result = TCL_ERROR;
TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
int haveExternalClip =
([[NSPasteboard generalPasteboard] changeCount] != changeCount);
int haveExternalClip = ([[NSPasteboard generalPasteboard] changeCount] != changeCount);
if (dispPtr && (haveExternalClip || dispPtr->clipboardActive)
&& selection == dispPtr->clipboardAtom
&& (target == XA_STRING || target == dispPtr->utf8Atom)) {
@@ -136,7 +134,22 @@ TkSelGetSelection(
if (type) {
string = [pb stringForType:type];
}
result = proc(clientData, interp, string ? [string UTF8String] : "");
if (string) {
/*
* Encode the string using the encoding which is used in Tcl
* when TCL_UTF_MAX = 3. This replaces each UTF-16 surrogate with
* a 3-byte sequence generated using the UTF-8 algorithm. (Even
* though UTF-8 does not allow encoding surrogates, the algorithm
* does produce a 3-byte sequence.)
*/
char *bytes = NSStringToTclUni(string, NULL);
result = proc(clientData, interp, bytes);
if (bytes) {
ckfree(bytes);
}
}
} else {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s selection doesn't exist or form \"%s\" not defined",
@@ -177,6 +190,7 @@ XSetSelectionOwner(
clipboardOwner = owner ? Tk_IdToWindow(display, owner) : NULL;
if (!dispPtr->clipboardActive) {
NSPasteboard *pb = [NSPasteboard generalPasteboard];
changeCount = [pb declareTypes:[NSArray array] owner:NSApp];
}
}
@@ -188,8 +202,8 @@ XSetSelectionOwner(
*
* TkMacOSXSelDeadWindow --
*
* This function is invoked just before a TkWindow is deleted. It
* performs selection-related cleanup.
* This function is invoked just before a TkWindow is deleted. It performs
* selection-related cleanup.
*
* Results:
* None.

View File

@@ -17,11 +17,32 @@
#include "tkMacOSXPrivate.h"
#include "tkColor.h"
/*
* The colorType specifies how the color value should be interpreted. For the
* unique rgbColor entry, the RGB values are generated from the pixel value of
* an XColor. The ttkBackground and semantic types are dynamic, meaning
* that they change when dark mode is enabled on OSX 10.13 and later.
*/
enum colorType {
clearColor, /* There should be only one of these. */
rgbColor, /* There should be only one of these. */
appearance, /* There should be only one of these. */
HIBrush, /* The value is a HITheme brush color table index. */
HIText, /* The value is a HITheme text color table index. */
HIBackground, /* The value is a HITheme background color table index. */
ttkBackground, /* The value can be used as a parameter.*/
semantic, /* The value can be used as a parameter.*/
};
/*
*/
struct SystemColorMapEntry {
const char *name;
ThemeBrush brush;
ThemeTextColor textColor;
ThemeBackgroundKind background;
enum colorType type;
long value;
}; /* unsigned char pixelCode; */
/*
@@ -32,157 +53,178 @@ struct SystemColorMapEntry {
#define MIN_PIXELCODE 30
static const struct SystemColorMapEntry systemColorMap[] = {
{ "Transparent", 0, 0, 0 }, /* 30: TRANSPARENT_PIXEL */
{ "Highlight", kThemeBrushPrimaryHighlightColor, 0, 0 }, /* 31: HIGHLIGHT_PIXEL */
{ "HighlightSecondary", kThemeBrushSecondaryHighlightColor, 0, 0 }, /* 32: HIGHLIGHT_SECONDARY_PIXEL */
{ "HighlightText", kThemeBrushBlack, 0, 0 }, /* 33: HIGHLIGHT_TEXT_PIXEL */
{ "HighlightAlternate", kThemeBrushAlternatePrimaryHighlightColor, 0, 0 }, /* 34: HIGHLIGHT_ALTERNATE_PIXEL */
{ "ButtonText", 0, kThemeTextColorPushButtonActive, 0 }, /* 35: CONTROL_TEXT_PIXEL */
{ "PrimaryHighlightColor", kThemeBrushPrimaryHighlightColor, 0, 0 }, /* 36 */
{ "ButtonFace", kThemeBrushButtonFaceActive, 0, 0 }, /* 37: CONTROL_BODY_PIXEL */
{ "SecondaryHighlightColor", kThemeBrushSecondaryHighlightColor, 0, 0 }, /* 38 */
{ "ButtonFrame", kThemeBrushButtonFrameActive, 0, 0 }, /* 39: CONTROL_FRAME_PIXEL */
{ "AlternatePrimaryHighlightColor", kThemeBrushAlternatePrimaryHighlightColor, 0, 0 }, /* 40 */
{ "WindowBody", kThemeBrushDocumentWindowBackground, 0, 0 }, /* 41: WINDOW_BODY_PIXEL */
{ "SheetBackground", kThemeBrushSheetBackground, 0, 0 }, /* 42 */
{ "MenuActive", kThemeBrushMenuBackgroundSelected, 0, 0 }, /* 43: MENU_ACTIVE_PIXEL */
{ "Black", kThemeBrushBlack, 0, 0 }, /* 44 */
{ "MenuActiveText", 0, kThemeTextColorMenuItemSelected, 0 }, /* 45: MENU_ACTIVE_TEXT_PIXEL */
{ "White", kThemeBrushWhite, 0, 0 }, /* 46 */
{ "Menu", kThemeBrushMenuBackground, 0, 0 }, /* 47: MENU_BACKGROUND_PIXEL */
{ "DialogBackgroundActive", kThemeBrushDialogBackgroundActive, 0, 0 }, /* 48 */
{ "MenuDisabled", 0, kThemeTextColorMenuItemDisabled, 0 }, /* 49: MENU_DISABLED_PIXEL */
{ "DialogBackgroundInactive", kThemeBrushDialogBackgroundInactive, 0, 0 }, /* 50 */
{ "MenuText", 0, kThemeTextColorMenuItemActive, 0 }, /* 51: MENU_TEXT_PIXEL */
{ "AppearanceColor", 0, 0, 0 }, /* 52: APPEARANCE_PIXEL */
{ "AlertBackgroundActive", kThemeBrushAlertBackgroundActive, 0, 0 }, /* 53 */
{ "AlertBackgroundInactive", kThemeBrushAlertBackgroundInactive, 0, 0 }, /* 54 */
{ "ModelessDialogBackgroundActive", kThemeBrushModelessDialogBackgroundActive, 0, 0 }, /* 55 */
{ "ModelessDialogBackgroundInactive", kThemeBrushModelessDialogBackgroundInactive, 0, 0 }, /* 56 */
{ "UtilityWindowBackgroundActive", kThemeBrushUtilityWindowBackgroundActive, 0, 0 }, /* 57 */
{ "UtilityWindowBackgroundInactive", kThemeBrushUtilityWindowBackgroundInactive, 0, 0 }, /* 58 */
{ "ListViewSortColumnBackground", kThemeBrushListViewSortColumnBackground, 0, 0 }, /* 59 */
{ "ListViewBackground", kThemeBrushListViewBackground, 0, 0 }, /* 60 */
{ "IconLabelBackground", kThemeBrushIconLabelBackground, 0, 0 }, /* 61 */
{ "ListViewSeparator", kThemeBrushListViewSeparator, 0, 0 }, /* 62 */
{ "ChasingArrows", kThemeBrushChasingArrows, 0, 0 }, /* 63 */
{ "DragHilite", kThemeBrushDragHilite, 0, 0 }, /* 64 */
{ "DocumentWindowBackground", kThemeBrushDocumentWindowBackground, 0, 0 }, /* 65 */
{ "FinderWindowBackground", kThemeBrushFinderWindowBackground, 0, 0 }, /* 66 */
{ "ScrollBarDelimiterActive", kThemeBrushScrollBarDelimiterActive, 0, 0 }, /* 67 */
{ "ScrollBarDelimiterInactive", kThemeBrushScrollBarDelimiterInactive, 0, 0 }, /* 68 */
{ "FocusHighlight", kThemeBrushFocusHighlight, 0, 0 }, /* 69 */
{ "PopupArrowActive", kThemeBrushPopupArrowActive, 0, 0 }, /* 70 */
{ "PopupArrowPressed", kThemeBrushPopupArrowPressed, 0, 0 }, /* 71 */
{ "PopupArrowInactive", kThemeBrushPopupArrowInactive, 0, 0 }, /* 72 */
{ "AppleGuideCoachmark", kThemeBrushAppleGuideCoachmark, 0, 0 }, /* 73 */
{ "IconLabelBackgroundSelected", kThemeBrushIconLabelBackgroundSelected, 0, 0 }, /* 74 */
{ "StaticAreaFill", kThemeBrushStaticAreaFill, 0, 0 }, /* 75 */
{ "ActiveAreaFill", kThemeBrushActiveAreaFill, 0, 0 }, /* 76 */
{ "ButtonFrameActive", kThemeBrushButtonFrameActive, 0, 0 }, /* 77 */
{ "ButtonFrameInactive", kThemeBrushButtonFrameInactive, 0, 0 }, /* 78 */
{ "ButtonFaceActive", kThemeBrushButtonFaceActive, 0, 0 }, /* 79 */
{ "ButtonFaceInactive", kThemeBrushButtonFaceInactive, 0, 0 }, /* 80 */
{ "ButtonFacePressed", kThemeBrushButtonFacePressed, 0, 0 }, /* 81 */
{ "ButtonActiveDarkShadow", kThemeBrushButtonActiveDarkShadow, 0, 0 }, /* 82 */
{ "ButtonActiveDarkHighlight", kThemeBrushButtonActiveDarkHighlight, 0, 0 }, /* 83 */
{ "ButtonActiveLightShadow", kThemeBrushButtonActiveLightShadow, 0, 0 }, /* 84 */
{ "ButtonActiveLightHighlight", kThemeBrushButtonActiveLightHighlight, 0, 0 }, /* 85 */
{ "ButtonInactiveDarkShadow", kThemeBrushButtonInactiveDarkShadow, 0, 0 }, /* 86 */
{ "ButtonInactiveDarkHighlight", kThemeBrushButtonInactiveDarkHighlight, 0, 0 }, /* 87 */
{ "ButtonInactiveLightShadow", kThemeBrushButtonInactiveLightShadow, 0, 0 }, /* 88 */
{ "ButtonInactiveLightHighlight", kThemeBrushButtonInactiveLightHighlight, 0, 0 }, /* 89 */
{ "ButtonPressedDarkShadow", kThemeBrushButtonPressedDarkShadow, 0, 0 }, /* 90 */
{ "ButtonPressedDarkHighlight", kThemeBrushButtonPressedDarkHighlight, 0, 0 }, /* 91 */
{ "ButtonPressedLightShadow", kThemeBrushButtonPressedLightShadow, 0, 0 }, /* 92 */
{ "ButtonPressedLightHighlight", kThemeBrushButtonPressedLightHighlight, 0, 0 }, /* 93 */
{ "BevelActiveLight", kThemeBrushBevelActiveLight, 0, 0 }, /* 94 */
{ "BevelActiveDark", kThemeBrushBevelActiveDark, 0, 0 }, /* 95 */
{ "BevelInactiveLight", kThemeBrushBevelInactiveLight, 0, 0 }, /* 96 */
{ "BevelInactiveDark", kThemeBrushBevelInactiveDark, 0, 0 }, /* 97 */
{ "NotificationWindowBackground", kThemeBrushNotificationWindowBackground, 0, 0 }, /* 98 */
{ "MovableModalBackground", kThemeBrushMovableModalBackground, 0, 0 }, /* 99 */
{ "SheetBackgroundOpaque", kThemeBrushSheetBackgroundOpaque, 0, 0 }, /* 100 */
{ "DrawerBackground", kThemeBrushDrawerBackground, 0, 0 }, /* 101 */
{ "ToolbarBackground", kThemeBrushToolbarBackground, 0, 0 }, /* 102 */
{ "SheetBackgroundTransparent", kThemeBrushSheetBackgroundTransparent, 0, 0 }, /* 103 */
{ "MenuBackground", kThemeBrushMenuBackground, 0, 0 }, /* 104 */
{ "Pixel", 0, 0, 0 }, /* 105: PIXEL_MAGIC */
{ "MenuBackgroundSelected", kThemeBrushMenuBackgroundSelected, 0, 0 }, /* 106 */
{ "ListViewOddRowBackground", kThemeBrushListViewOddRowBackground, 0, 0 }, /* 107 */
{ "ListViewEvenRowBackground", kThemeBrushListViewEvenRowBackground, 0, 0 }, /* 108 */
{ "ListViewColumnDivider", kThemeBrushListViewColumnDivider, 0, 0 }, /* 109 */
{ "BlackText", 0, kThemeTextColorBlack, 0 }, /* 110 */
{ "DialogActiveText", 0, kThemeTextColorDialogActive, 0 }, /* 111 */
{ "DialogInactiveText", 0, kThemeTextColorDialogInactive, 0 }, /* 112 */
{ "AlertActiveText", 0, kThemeTextColorAlertActive, 0 }, /* 113 */
{ "AlertInactiveText", 0, kThemeTextColorAlertInactive, 0 }, /* 114 */
{ "ModelessDialogActiveText", 0, kThemeTextColorModelessDialogActive, 0 }, /* 115 */
{ "ModelessDialogInactiveText", 0, kThemeTextColorModelessDialogInactive, 0 }, /* 116 */
{ "WindowHeaderActiveText", 0, kThemeTextColorWindowHeaderActive, 0 }, /* 117 */
{ "WindowHeaderInactiveText", 0, kThemeTextColorWindowHeaderInactive, 0 }, /* 118 */
{ "PlacardActiveText", 0, kThemeTextColorPlacardActive, 0 }, /* 119 */
{ "PlacardInactiveText", 0, kThemeTextColorPlacardInactive, 0 }, /* 120 */
{ "PlacardPressedText", 0, kThemeTextColorPlacardPressed, 0 }, /* 121 */
{ "PushButtonActiveText", 0, kThemeTextColorPushButtonActive, 0 }, /* 122 */
{ "PushButtonInactiveText", 0, kThemeTextColorPushButtonInactive, 0 }, /* 123 */
{ "PushButtonPressedText", 0, kThemeTextColorPushButtonPressed, 0 }, /* 124 */
{ "BevelButtonActiveText", 0, kThemeTextColorBevelButtonActive, 0 }, /* 125 */
{ "BevelButtonInactiveText", 0, kThemeTextColorBevelButtonInactive, 0 }, /* 126 */
{ "BevelButtonPressedText", 0, kThemeTextColorBevelButtonPressed, 0 }, /* 127 */
{ "PopupButtonActiveText", 0, kThemeTextColorPopupButtonActive, 0 }, /* 128 */
{ "PopupButtonInactiveText", 0, kThemeTextColorPopupButtonInactive, 0 }, /* 129 */
{ "PopupButtonPressedText", 0, kThemeTextColorPopupButtonPressed, 0 }, /* 130 */
{ "IconLabelText", 0, kThemeTextColorIconLabel, 0 }, /* 131 */
{ "ListViewText", 0, kThemeTextColorListView, 0 }, /* 132 */
{ "DocumentWindowTitleActiveText", 0, kThemeTextColorDocumentWindowTitleActive, 0 }, /* 133 */
{ "DocumentWindowTitleInactiveText", 0, kThemeTextColorDocumentWindowTitleInactive, 0 }, /* 134 */
{ "MovableModalWindowTitleActiveText", 0, kThemeTextColorMovableModalWindowTitleActive, 0 }, /* 135 */
{ "MovableModalWindowTitleInactiveText",0, kThemeTextColorMovableModalWindowTitleInactive, 0 }, /* 136 */
{ "UtilityWindowTitleActiveText", 0, kThemeTextColorUtilityWindowTitleActive, 0 }, /* 137 */
{ "UtilityWindowTitleInactiveText", 0, kThemeTextColorUtilityWindowTitleInactive, 0 }, /* 138 */
{ "PopupWindowTitleActiveText", 0, kThemeTextColorPopupWindowTitleActive, 0 }, /* 139 */
{ "PopupWindowTitleInactiveText", 0, kThemeTextColorPopupWindowTitleInactive, 0 }, /* 140 */
{ "RootMenuActiveText", 0, kThemeTextColorRootMenuActive, 0 }, /* 141 */
{ "RootMenuSelectedText", 0, kThemeTextColorRootMenuSelected, 0 }, /* 142 */
{ "RootMenuDisabledText", 0, kThemeTextColorRootMenuDisabled, 0 }, /* 143 */
{ "MenuItemActiveText", 0, kThemeTextColorMenuItemActive, 0 }, /* 144 */
{ "MenuItemSelectedText", 0, kThemeTextColorMenuItemSelected, 0 }, /* 145 */
{ "MenuItemDisabledText", 0, kThemeTextColorMenuItemDisabled, 0 }, /* 146 */
{ "PopupLabelActiveText", 0, kThemeTextColorPopupLabelActive, 0 }, /* 147 */
{ "PopupLabelInactiveText", 0, kThemeTextColorPopupLabelInactive, 0 }, /* 148 */
{ "TabFrontActiveText", 0, kThemeTextColorTabFrontActive, 0 }, /* 149 */
{ "TabNonFrontActiveText", 0, kThemeTextColorTabNonFrontActive, 0 }, /* 150 */
{ "TabNonFrontPressedText", 0, kThemeTextColorTabNonFrontPressed, 0 }, /* 151 */
{ "TabFrontInactiveText", 0, kThemeTextColorTabFrontInactive, 0 }, /* 152 */
{ "TabNonFrontInactiveText", 0, kThemeTextColorTabNonFrontInactive, 0 }, /* 153 */
{ "IconLabelSelectedText", 0, kThemeTextColorIconLabelSelected, 0 }, /* 154 */
{ "BevelButtonStickyActiveText", 0, kThemeTextColorBevelButtonStickyActive, 0 }, /* 155 */
{ "BevelButtonStickyInactiveText", 0, kThemeTextColorBevelButtonStickyInactive, 0 }, /* 156 */
{ "NotificationText", 0, kThemeTextColorNotification, 0 }, /* 157 */
{ "SystemDetailText", 0, kThemeTextColorSystemDetail, 0 }, /* 158 */
{ "WhiteText", 0, kThemeTextColorWhite, 0 }, /* 159 */
{ "TabPaneBackground", 0, 0, kThemeBackgroundTabPane }, /* 160 */
{ "PlacardBackground", 0, 0, kThemeBackgroundPlacard }, /* 161 */
{ "WindowHeaderBackground", 0, 0, kThemeBackgroundWindowHeader }, /* 162 */
{ "ListViewWindowHeaderBackground", 0, 0, kThemeBackgroundListViewWindowHeader }, /* 163 */
{ "SecondaryGroupBoxBackground", 0, 0, kThemeBackgroundSecondaryGroupBox }, /* 164 */
{ "MetalBackground", 0, 0, kThemeBackgroundMetal }, /* 165 */
{ NULL, 0, 0, 0 }
{ "Transparent", clearColor, 0 }, /* 30: TRANSPARENT_PIXEL */
{ "Highlight", HIBrush, kThemeBrushPrimaryHighlightColor }, /* 31 */
{ "HighlightSecondary", HIBrush, kThemeBrushSecondaryHighlightColor }, /* 32 */
{ "HighlightText", HIBrush, kThemeBrushBlack }, /* 33 */
{ "HighlightAlternate", HIBrush, kThemeBrushAlternatePrimaryHighlightColor }, /* 34 */
{ "ButtonText", HIText, kThemeTextColorPushButtonActive }, /* 35 */
{ "PrimaryHighlightColor", HIBrush, kThemeBrushPrimaryHighlightColor }, /* 36 */
{ "ButtonFace", HIBrush, kThemeBrushButtonFaceActive }, /* 37 */
{ "SecondaryHighlightColor", HIBrush, kThemeBrushSecondaryHighlightColor }, /* 38 */
{ "ButtonFrame", HIBrush, kThemeBrushButtonFrameActive }, /* 39 */
{ "AlternatePrimaryHighlightColor", HIBrush, kThemeBrushAlternatePrimaryHighlightColor }, /* 40 */
{ "WindowBody", HIBrush, kThemeBrushDocumentWindowBackground }, /* 41 */
{ "SheetBackground", HIBrush, kThemeBrushSheetBackground }, /* 42 */
{ "MenuActive", HIBrush, kThemeBrushMenuBackgroundSelected }, /* 43 */
{ "Black", HIBrush, kThemeBrushBlack }, /* 44 */
{ "MenuActiveText", HIText, kThemeTextColorMenuItemSelected }, /* 45 */
{ "White", HIBrush, kThemeBrushWhite }, /* 46 */
{ "Menu", HIBrush, kThemeBrushMenuBackground }, /* 47 */
{ "DialogBackgroundActive", HIBrush, kThemeBrushDialogBackgroundActive }, /* 48 */
{ "MenuDisabled", HIText, kThemeTextColorMenuItemDisabled }, /* 49 */
{ "DialogBackgroundInactive", HIBrush, kThemeBrushDialogBackgroundInactive }, /* 50 */
{ "MenuText", HIText, kThemeTextColorMenuItemActive }, /* 51 */
{ "AppearanceColor", appearance, 0 }, /* 52: APPEARANCE_PIXEL */
{ "AlertBackgroundActive", HIBrush, kThemeBrushAlertBackgroundActive }, /* 53 */
{ "AlertBackgroundInactive", HIBrush, kThemeBrushAlertBackgroundInactive }, /* 54 */
{ "ModelessDialogBackgroundActive", HIBrush, kThemeBrushModelessDialogBackgroundActive }, /* 55 */
{ "ModelessDialogBackgroundInactive", HIBrush, kThemeBrushModelessDialogBackgroundInactive }, /* 56 */
{ "UtilityWindowBackgroundActive", HIBrush, kThemeBrushUtilityWindowBackgroundActive }, /* 57 */
{ "UtilityWindowBackgroundInactive", HIBrush, kThemeBrushUtilityWindowBackgroundInactive }, /* 58 */
{ "ListViewSortColumnBackground", HIBrush, kThemeBrushListViewSortColumnBackground }, /* 59 */
{ "ListViewBackground", HIBrush, kThemeBrushListViewBackground }, /* 60 */
{ "IconLabelBackground", HIBrush, kThemeBrushIconLabelBackground }, /* 61 */
{ "ListViewSeparator", HIBrush, kThemeBrushListViewSeparator }, /* 62 */
{ "ChasingArrows", HIBrush, kThemeBrushChasingArrows }, /* 63 */
{ "DragHilite", HIBrush, kThemeBrushDragHilite }, /* 64 */
{ "DocumentWindowBackground", HIBrush, kThemeBrushDocumentWindowBackground }, /* 65 */
{ "FinderWindowBackground", HIBrush, kThemeBrushFinderWindowBackground }, /* 66 */
{ "ScrollBarDelimiterActive", HIBrush, kThemeBrushScrollBarDelimiterActive }, /* 67 */
{ "ScrollBarDelimiterInactive", HIBrush, kThemeBrushScrollBarDelimiterInactive }, /* 68 */
{ "FocusHighlight", HIBrush, kThemeBrushFocusHighlight }, /* 69 */
{ "PopupArrowActive", HIBrush, kThemeBrushPopupArrowActive }, /* 70 */
{ "PopupArrowPressed", HIBrush, kThemeBrushPopupArrowPressed }, /* 71 */
{ "PopupArrowInactive", HIBrush, kThemeBrushPopupArrowInactive }, /* 72 */
{ "AppleGuideCoachmark", HIBrush, kThemeBrushAppleGuideCoachmark }, /* 73 */
{ "IconLabelBackgroundSelected", HIBrush, kThemeBrushIconLabelBackgroundSelected }, /* 74 */
{ "StaticAreaFill", HIBrush, kThemeBrushStaticAreaFill }, /* 75 */
{ "ActiveAreaFill", HIBrush, kThemeBrushActiveAreaFill }, /* 76 */
{ "ButtonFrameActive", HIBrush, kThemeBrushButtonFrameActive }, /* 77 */
{ "ButtonFrameInactive", HIBrush, kThemeBrushButtonFrameInactive }, /* 78 */
{ "ButtonFaceActive", HIBrush, kThemeBrushButtonFaceActive }, /* 79 */
{ "ButtonFaceInactive", HIBrush, kThemeBrushButtonFaceInactive }, /* 80 */
{ "ButtonFacePressed", HIBrush, kThemeBrushButtonFacePressed }, /* 81 */
{ "ButtonActiveDarkShadow", HIBrush, kThemeBrushButtonActiveDarkShadow }, /* 82 */
{ "ButtonActiveDarkHighlight", HIBrush, kThemeBrushButtonActiveDarkHighlight }, /* 83 */
{ "ButtonActiveLightShadow", HIBrush, kThemeBrushButtonActiveLightShadow }, /* 84 */
{ "ButtonActiveLightHighlight", HIBrush, kThemeBrushButtonActiveLightHighlight }, /* 85 */
{ "ButtonInactiveDarkShadow", HIBrush, kThemeBrushButtonInactiveDarkShadow }, /* 86 */
{ "ButtonInactiveDarkHighlight", HIBrush, kThemeBrushButtonInactiveDarkHighlight }, /* 87 */
{ "ButtonInactiveLightShadow", HIBrush, kThemeBrushButtonInactiveLightShadow }, /* 88 */
{ "ButtonInactiveLightHighlight", HIBrush, kThemeBrushButtonInactiveLightHighlight }, /* 89 */
{ "ButtonPressedDarkShadow", HIBrush, kThemeBrushButtonPressedDarkShadow }, /* 90 */
{ "ButtonPressedDarkHighlight", HIBrush, kThemeBrushButtonPressedDarkHighlight }, /* 91 */
{ "ButtonPressedLightShadow", HIBrush, kThemeBrushButtonPressedLightShadow }, /* 92 */
{ "ButtonPressedLightHighlight", HIBrush, kThemeBrushButtonPressedLightHighlight }, /* 93 */
{ "BevelActiveLight", HIBrush, kThemeBrushBevelActiveLight }, /* 94 */
{ "BevelActiveDark", HIBrush, kThemeBrushBevelActiveDark }, /* 95 */
{ "BevelInactiveLight", HIBrush, kThemeBrushBevelInactiveLight }, /* 96 */
{ "BevelInactiveDark", HIBrush, kThemeBrushBevelInactiveDark }, /* 97 */
{ "NotificationWindowBackground", HIBrush, kThemeBrushNotificationWindowBackground }, /* 98 */
{ "MovableModalBackground", HIBrush, kThemeBrushMovableModalBackground }, /* 99 */
{ "SheetBackgroundOpaque", HIBrush, kThemeBrushSheetBackgroundOpaque }, /* 100 */
{ "DrawerBackground", HIBrush, kThemeBrushDrawerBackground }, /* 101 */
{ "ToolbarBackground", HIBrush, kThemeBrushToolbarBackground }, /* 102 */
{ "SheetBackgroundTransparent", HIBrush, kThemeBrushSheetBackgroundTransparent }, /* 103 */
{ "MenuBackground", HIBrush, kThemeBrushMenuBackground }, /* 104 */
{ "Pixel", rgbColor, 0 }, /* 105: PIXEL_MAGIC */
{ "MenuBackgroundSelected", HIBrush, kThemeBrushMenuBackgroundSelected }, /* 106 */
{ "ListViewOddRowBackground", HIBrush, kThemeBrushListViewOddRowBackground }, /* 107 */
{ "ListViewEvenRowBackground", HIBrush, kThemeBrushListViewEvenRowBackground }, /* 108 */
{ "ListViewColumnDivider", HIBrush, kThemeBrushListViewColumnDivider }, /* 109 */
{ "BlackText", HIText, kThemeTextColorBlack }, /* 110 */
{ "DialogActiveText", HIText, kThemeTextColorDialogActive }, /* 111 */
{ "DialogInactiveText", HIText, kThemeTextColorDialogInactive }, /* 112 */
{ "AlertActiveText", HIText, kThemeTextColorAlertActive }, /* 113 */
{ "AlertInactiveText", HIText, kThemeTextColorAlertInactive }, /* 114 */
{ "ModelessDialogActiveText", HIText, kThemeTextColorModelessDialogActive }, /* 115 */
{ "ModelessDialogInactiveText", HIText, kThemeTextColorModelessDialogInactive }, /* 116 */
{ "WindowHeaderActiveText", HIText, kThemeTextColorWindowHeaderActive }, /* 117 */
{ "WindowHeaderInactiveText", HIText, kThemeTextColorWindowHeaderInactive }, /* 118 */
{ "PlacardActiveText", HIText, kThemeTextColorPlacardActive }, /* 119 */
{ "PlacardInactiveText", HIText, kThemeTextColorPlacardInactive }, /* 120 */
{ "PlacardPressedText", HIText, kThemeTextColorPlacardPressed }, /* 121 */
{ "PushButtonActiveText", HIText, kThemeTextColorPushButtonActive }, /* 122 */
{ "PushButtonInactiveText", HIText, kThemeTextColorPushButtonInactive }, /* 123 */
{ "PushButtonPressedText", HIText, kThemeTextColorPushButtonPressed }, /* 124 */
{ "BevelButtonActiveText", HIText, kThemeTextColorBevelButtonActive }, /* 125 */
{ "BevelButtonInactiveText", HIText, kThemeTextColorBevelButtonInactive }, /* 126 */
{ "BevelButtonPressedText", HIText, kThemeTextColorBevelButtonPressed }, /* 127 */
{ "PopupButtonActiveText", HIText, kThemeTextColorPopupButtonActive }, /* 128 */
{ "PopupButtonInactiveText", HIText, kThemeTextColorPopupButtonInactive }, /* 129 */
{ "PopupButtonPressedText", HIText, kThemeTextColorPopupButtonPressed }, /* 130 */
{ "IconLabelText", HIText, kThemeTextColorIconLabel }, /* 131 */
{ "ListViewText", HIText, kThemeTextColorListView }, /* 132 */
{ "DocumentWindowTitleActiveText", HIText, kThemeTextColorDocumentWindowTitleActive }, /* 133 */
{ "DocumentWindowTitleInactiveText", HIText, kThemeTextColorDocumentWindowTitleInactive }, /* 134 */
{ "MovableModalWindowTitleActiveText", HIText, kThemeTextColorMovableModalWindowTitleActive }, /* 135 */
{ "MovableModalWindowTitleInactiveText",HIText, kThemeTextColorMovableModalWindowTitleInactive }, /* 136 */
{ "UtilityWindowTitleActiveText", HIText, kThemeTextColorUtilityWindowTitleActive }, /* 137 */
{ "UtilityWindowTitleInactiveText", HIText, kThemeTextColorUtilityWindowTitleInactive }, /* 138 */
{ "PopupWindowTitleActiveText", HIText, kThemeTextColorPopupWindowTitleActive }, /* 139 */
{ "PopupWindowTitleInactiveText", HIText, kThemeTextColorPopupWindowTitleInactive }, /* 140 */
{ "RootMenuActiveText", HIText, kThemeTextColorRootMenuActive }, /* 141 */
{ "RootMenuSelectedText", HIText, kThemeTextColorRootMenuSelected }, /* 142 */
{ "RootMenuDisabledText", HIText, kThemeTextColorRootMenuDisabled }, /* 143 */
{ "MenuItemActiveText", HIText, kThemeTextColorMenuItemActive }, /* 144 */
{ "MenuItemSelectedText", HIText, kThemeTextColorMenuItemSelected }, /* 145 */
{ "MenuItemDisabledText", HIText, kThemeTextColorMenuItemDisabled }, /* 146 */
{ "PopupLabelActiveText", HIText, kThemeTextColorPopupLabelActive }, /* 147 */
{ "PopupLabelInactiveText", HIText, kThemeTextColorPopupLabelInactive }, /* 148 */
{ "TabFrontActiveText", HIText, kThemeTextColorTabFrontActive }, /* 149 */
{ "TabNonFrontActiveText", HIText, kThemeTextColorTabNonFrontActive }, /* 150 */
{ "TabNonFrontPressedText", HIText, kThemeTextColorTabNonFrontPressed }, /* 151 */
{ "TabFrontInactiveText", HIText, kThemeTextColorTabFrontInactive }, /* 152 */
{ "TabNonFrontInactiveText", HIText, kThemeTextColorTabNonFrontInactive }, /* 153 */
{ "IconLabelSelectedText", HIText, kThemeTextColorIconLabelSelected }, /* 154 */
{ "BevelButtonStickyActiveText", HIText, kThemeTextColorBevelButtonStickyActive }, /* 155 */
{ "BevelButtonStickyInactiveText", HIText, kThemeTextColorBevelButtonStickyInactive }, /* 156 */
{ "NotificationText", HIText, kThemeTextColorNotification }, /* 157 */
{ "SystemDetailText", HIText, kThemeTextColorSystemDetail }, /* 158 */
{ "WhiteText", HIText, kThemeTextColorWhite }, /* 159 */
{ "TabPaneBackground", HIBackground, kThemeBackgroundTabPane }, /* 160 */
{ "PlacardBackground", HIBackground, kThemeBackgroundPlacard }, /* 161 */
{ "WindowHeaderBackground", HIBackground, kThemeBackgroundWindowHeader }, /* 162 */
{ "ListViewWindowHeaderBackground", HIBackground, kThemeBackgroundListViewWindowHeader }, /* 163 */
{ "SecondaryGroupBoxBackground", HIBackground, kThemeBackgroundSecondaryGroupBox }, /* 164 */
{ "MetalBackground", HIBackground, kThemeBackgroundMetal }, /* 165 */
/*
* Colors based on "semantic" NSColors.
*/
{ "WindowBackgroundColor", ttkBackground, 0 }, /* 166 */
{ "WindowBackgroundColor1", ttkBackground, 1 }, /* 167 */
{ "WindowBackgroundColor2", ttkBackground, 2 }, /* 168 */
{ "WindowBackgroundColor3", ttkBackground, 3 }, /* 169 */
{ "WindowBackgroundColor4", ttkBackground, 4 }, /* 170 */
{ "WindowBackgroundColor5", ttkBackground, 5 }, /* 171 */
{ "WindowBackgroundColor6", ttkBackground, 6 }, /* 172 */
{ "WindowBackgroundColor7", ttkBackground, 7 }, /* 173 */
{ "TextColor", semantic, 0 }, /* 174 */
{ "SelectedTextColor", semantic, 1 }, /* 175 */
{ "LabelColor", semantic, 2 }, /* 176 */
{ "ControlTextColor", semantic, 3 }, /* 177 */
{ "DisabledControlTextColor", semantic, 4 }, /* 178 */
{ "SelectedTabTextColor", semantic, 5 }, /* 179 */
{ "TextBackgroundColor", semantic, 6 }, /* 180 */
{ "SelectedTextBackgroundColor", semantic, 7 }, /* 181 */
{ "ControlAccentColor", semantic, 8 }, /* 182 */
{ NULL, 0, 0 }
};
#define MAX_PIXELCODE 165
#define FIRST_SEMANTIC_COLOR 166
#define MAX_PIXELCODE 182
/*
*----------------------------------------------------------------------
*
* GetThemeFromPixelCode --
* GetEntryFromPixelCode --
*
* When given a pixel code corresponding to a theme system color,
* set one of brush, textColor or background to the corresponding
* Appearance Mgr theme constant.
* Extract a SystemColorMapEntry from the table.
*
* Results:
* Returns false if not a real pixel, true otherwise.
* Returns false if the code is out of bounds.
*
* Side effects:
* None.
@@ -190,36 +232,28 @@ static const struct SystemColorMapEntry systemColorMap[] = {
*----------------------------------------------------------------------
*/
static int
GetThemeFromPixelCode(
static bool
GetEntryFromPixelCode(
unsigned char code,
ThemeBrush *brush,
ThemeTextColor *textColor,
ThemeBackgroundKind *background)
struct SystemColorMapEntry *entry)
{
if (code >= MIN_PIXELCODE && code <= MAX_PIXELCODE) {
*brush = systemColorMap[code - MIN_PIXELCODE].brush;
*textColor = systemColorMap[code - MIN_PIXELCODE].textColor;
*background = systemColorMap[code - MIN_PIXELCODE].background;
} else {
*brush = 0;
*textColor = 0;
*background = 0;
}
if (!*brush && !*textColor && !*background && code != PIXEL_MAGIC &&
code != TRANSPARENT_PIXEL) {
return false;
} else {
*entry = systemColorMap[code - MIN_PIXELCODE];
return true;
} else {
return false;
}
}
/*
*----------------------------------------------------------------------
*
* GetThemeColor --
* SetCGColorComponents --
*
* Get RGB color for a given system color or pixel value.
* Set the components of a CGColorRef from an XColor pixel value and a
* system color map entry. The pixel value is only used in the case where
* the color is of type rgbColor. In that case the normalized XColor RGB
* values are copied into the CGColorRef.
*
* Results:
* OSStatus
@@ -230,60 +264,217 @@ GetThemeFromPixelCode(
*----------------------------------------------------------------------
*/
static NSColorSpace* deviceRGB = NULL;
static CGFloat blueAccentRGBA[4] = {0, 122.0 / 255, 1.0, 1.0};
static CGFloat windowBackground[4] =
{236.0 / 255, 236.0 / 255, 236.0 / 255, 1.0};
static OSStatus
GetThemeColor(
SetCGColorComponents(
struct SystemColorMapEntry entry,
unsigned long pixel,
ThemeBrush brush,
ThemeTextColor textColor,
ThemeBackgroundKind background,
CGColorRef *c)
{
OSStatus err = noErr;
NSColor *bgColor, *color = nil;
CGFloat rgba[4] = {0, 0, 0, 1};
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101400
NSInteger colorVariant;
static CGFloat graphiteAccentRGBA[4] =
{152.0 / 255, 152.0 / 255, 152.0 / 255, 1.0};
#endif
if (brush) {
err = ChkErr(HIThemeBrushCreateCGColor, brush, c);
/*} else if (textColor) {
err = ChkErr(GetThemeTextColor, textColor, 32, true, c);*/
} else {
CGFloat rgba[4] = {0, 0, 0, 1};
switch ((pixel >> 24) & 0xff) {
case PIXEL_MAGIC: {
unsigned short red, green, blue;
red = (pixel >> 16) & 0xff;
green = (pixel >> 8) & 0xff;
blue = (pixel ) & 0xff;
red |= red << 8;
green |= green << 8;
blue |= blue << 8;
rgba[0] = red / 65535.0;
rgba[1] = green / 65535.0;
rgba[2] = blue / 65535.0;
break;
}
case TRANSPARENT_PIXEL:
rgba[3] = 0.0;
break;
}
static CGColorSpaceRef deviceRGBSpace = NULL;
if (!deviceRGBSpace) {
deviceRGBSpace = CGColorSpaceCreateDeviceRGB();
}
*c = CGColorCreate(deviceRGBSpace, rgba );
if (!deviceRGB) {
deviceRGB = [NSColorSpace deviceRGBColorSpace];
}
/*
* This function is called before our autorelease pool is set up,
* so it needs its own pool.
*/
NSAutoreleasePool *pool = [NSAutoreleasePool new];
switch (entry.type) {
case HIBrush:
err = ChkErr(HIThemeBrushCreateCGColor, entry.value, c);
return err;
case rgbColor:
rgba[0] = ((pixel >> 16) & 0xff) / 255.0;
rgba[1] = ((pixel >> 8) & 0xff) / 255.0;
rgba[2] = ((pixel ) & 0xff) / 255.0;
break;
case ttkBackground:
/*
* Prior to OSX 10.14, getComponents returns black when applied to
* windowBackGroundColor.
*/
if ([NSApp macMinorVersion] < 14) {
for (int i=0; i<3; i++) {
rgba[i] = windowBackground[i];
}
} else {
bgColor = [[NSColor windowBackgroundColor] colorUsingColorSpace:
deviceRGB];
[bgColor getComponents: rgba];
}
if (rgba[0] + rgba[1] + rgba[2] < 1.5) {
for (int i=0; i<3; i++) {
rgba[i] += entry.value*8.0 / 255.0;
}
} else {
for (int i=0; i<3; i++) {
rgba[i] -= entry.value*8.0 / 255.0;
}
}
break;
case semantic:
switch (entry.value) {
case 0:
color = [[NSColor textColor] colorUsingColorSpace: deviceRGB];
break;
case 1:
color = [[NSColor selectedTextColor] colorUsingColorSpace: deviceRGB];
break;
case 2:
if ([NSApp macMinorVersion] > 9) {
#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
color = [[NSColor labelColor] colorUsingColorSpace: deviceRGB];
#endif
} else {
color = [[NSColor textColor] colorUsingColorSpace: deviceRGB];
}
break;
case 3:
color = [[NSColor controlTextColor] colorUsingColorSpace:
deviceRGB];
break;
case 4:
color = [[NSColor disabledControlTextColor] colorUsingColorSpace:
deviceRGB];
break;
case 5:
if ([NSApp macMinorVersion] > 6) {
color = [[NSColor whiteColor] colorUsingColorSpace:
deviceRGB];
} else {
color = [[NSColor blackColor] colorUsingColorSpace:
deviceRGB];
}
break;
case 6:
color = [[NSColor textBackgroundColor] colorUsingColorSpace:
deviceRGB];
break;
case 7:
color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpace:
deviceRGB];
break;
case 8:
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
if (@available(macOS 10.14, *)) {
color = [[NSColor controlAccentColor] colorUsingColorSpace:
deviceRGB];
} else {
color = [NSColor colorWithColorSpace: deviceRGB
components: blueAccentRGBA
count: 4];
}
#else
colorVariant = [[NSUserDefaults standardUserDefaults]
integerForKey:@"AppleAquaColorVariant"];
if (colorVariant == 6) {
color = [NSColor colorWithColorSpace: deviceRGB
components: graphiteAccentRGBA
count: 4];
} else {
color = [NSColor colorWithColorSpace: deviceRGB
components: blueAccentRGBA
count: 4];
}
#endif
break;
default:
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
if ([NSApp macMinorVersion] >= 10) {
color = [[NSColor labelColor] colorUsingColorSpace:
deviceRGB];
break;
}
#endif
color = [[NSColor textColor] colorUsingColorSpace: deviceRGB];
break;
}
[color getComponents: rgba];
break;
case clearColor:
rgba[3] = 0.0;
break;
/*
* There are no HITheme functions which convert Text or background colors
* to CGColors. (GetThemeTextColor has been removed, and it was never
* possible with backgrounds.) If we get one of these we return black.
*/
case HIText:
case HIBackground:
default:
break;
}
*c = CGColorCreate(deviceRGB.CGColorSpace, rgba);
[pool drain];
return err;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXInDarkMode --
*
* Tests whether the given window's NSView has a DarkAqua Appearance.
*
* Results:
* Returns true if the NSView is in DarkMode, false if not.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE Bool
TkMacOSXInDarkMode(Tk_Window tkwin)
{
int result = false;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
if ([NSApp macMinorVersion] >= 14) {
static NSAppearanceName darkAqua = @"NSAppearanceNameDarkAqua";
TkWindow *winPtr = (TkWindow*) tkwin;
NSView *view = TkMacOSXDrawableView(winPtr->privatePtr);
result = (view &&
[view.effectiveAppearance.name isEqualToString:darkAqua]);
}
#endif
return result;
}
/*
*----------------------------------------------------------------------
*
* TkSetMacColor --
*
* Creates a CGColorRef from a X style pixel value.
* Sets the components of a CGColorRef from an XColor pixel value.
* The high order byte of the pixel value is used as an index into
* the system color table, and then SetCGColorComponents is called
* with the table entry and the pixel value.
*
* Results:
* Returns false if not a real pixel, true otherwise.
* Returns false if the high order byte is not a valid index, true
* otherwise.
*
* Side effects:
* The variable macColor is set to a new CGColorRef, the caller is
@@ -299,14 +490,10 @@ TkSetMacColor(
{
CGColorRef *color = (CGColorRef*)macColor;
OSStatus err = -1;
ThemeBrush brush;
ThemeTextColor textColor;
ThemeBackgroundKind background;
struct SystemColorMapEntry entry;
if (GetThemeFromPixelCode((pixel >> 24) & 0xff, &brush, &textColor,
&background)) {
err = ChkErr(GetThemeColor, pixel, brush, textColor, background,
color);
if (GetEntryFromPixelCode((pixel >> 24) & 0xff, &entry)) {
err = ChkErr(SetCGColorComponents, entry, pixel, color);
}
return (err == noErr);
}
@@ -321,7 +508,7 @@ TkSetMacColor(
* Results:
* None resp. retained CGColorRef for CopyCachedColor()
*
* Side effects:
* Side effects:M
* None.
*
*----------------------------------------------------------------------
@@ -450,6 +637,7 @@ TkMacOSXGetNSColor(
if (cgColor) {
NSColorSpace *colorSpace = [[NSColorSpace alloc]
initWithCGColorSpace:CGColorGetColorSpace(cgColor)];
nsColor = [NSColor colorWithColorSpace:colorSpace
components:CGColorGetComponents(cgColor)
count:CGColorGetNumberOfComponents(cgColor)];
@@ -484,48 +672,56 @@ TkMacOSXSetColorInContext(
unsigned long pixel,
CGContextRef context)
{
OSStatus err = -1;
CGColorRef cgColor = CopyCachedColor(gc, pixel);
ThemeBrush brush;
ThemeTextColor textColor;
ThemeBackgroundKind background;
OSStatus err = noErr;
CGColorRef cgColor = nil;
struct SystemColorMapEntry entry;
CGRect rect;
int code = (pixel >> 24) & 0xff;
HIThemeBackgroundDrawInfo info = {0, kThemeStateActive, 0};;
static CGColorSpaceRef deviceRGBSpace = NULL;
if (!cgColor && GetThemeFromPixelCode((pixel >> 24) & 0xff, &brush,
&textColor, &background)) {
if (brush) {
err = ChkErr(HIThemeSetFill, brush, NULL, context,
if (!deviceRGBSpace) {
deviceRGBSpace = CGColorSpaceCreateDeviceRGB();
}
if (code < FIRST_SEMANTIC_COLOR) {
cgColor = CopyCachedColor(gc, pixel);
}
if (!cgColor && GetEntryFromPixelCode(code, &entry)) {
switch (entry.type) {
case HIBrush:
err = ChkErr(HIThemeSetFill, entry.value, NULL, context,
kHIThemeOrientationNormal);
if (err == noErr) {
err = ChkErr(HIThemeSetStroke, brush, NULL, context,
err = ChkErr(HIThemeSetStroke, entry.value, NULL, context,
kHIThemeOrientationNormal);
}
} else if (textColor) {
err = ChkErr(HIThemeSetTextFill, textColor, NULL, context,
break;
case HIText:
err = ChkErr(HIThemeSetTextFill, entry.value, NULL, context,
kHIThemeOrientationNormal);
} else if (background) {
CGRect rect = CGContextGetClipBoundingBox(context);
HIThemeBackgroundDrawInfo info = { 0, kThemeStateActive,
background };
break;
case HIBackground:
info.kind = entry.value;
rect = CGContextGetClipBoundingBox(context);
err = ChkErr(HIThemeApplyBackground, &rect, &info,
context, kHIThemeOrientationNormal);
break;
default:
err = ChkErr(SetCGColorComponents, entry, pixel, &cgColor);
if (err == noErr) {
SetCachedColor(gc, pixel, cgColor);
}
break;
}
if (err == noErr) {
return;
}
err = ChkErr(GetThemeColor, pixel, brush, textColor, background,
&cgColor);
if (err == noErr) {
SetCachedColor(gc, pixel, cgColor);
}
} else if (!cgColor) {
TkMacOSXDbgMsg("Ignored unknown pixel value 0x%lx", pixel);
}
if (cgColor) {
CGContextSetFillColorWithColor(context, cgColor);
CGContextSetStrokeColorWithColor(context, cgColor);
CGColorRelease(cgColor);
}
if (err != noErr) {
TkMacOSXDbgMsg("Ignored unknown pixel value 0x%lx", pixel);
}
}
/*
@@ -549,7 +745,7 @@ TkMacOSXSetColorInContext(
TkColor *
TkpGetColor(
Tk_Window tkwin, /* Window in which color will be used. */
Tk_Uid name) /* Name of color to allocated (in form
Tk_Uid name) /* Name of color to be allocated (in form
* suitable for passing to XParseColor). */
{
Display *display = tkwin != None ? Tk_Display(tkwin) : NULL;
@@ -561,22 +757,21 @@ TkpGetColor(
* Check to see if this is a system color. Otherwise, XParseColor
* will do all the work.
*/
if (strncasecmp(name, "system", 6) == 0) {
Tcl_Obj *strPtr = Tcl_NewStringObj(name+6, -1);
int idx, result;
result = Tcl_GetIndexFromObjStruct(NULL, strPtr, systemColorMap,
sizeof(struct SystemColorMapEntry), NULL, TCL_EXACT, &idx);
sizeof(struct SystemColorMapEntry), NULL, TCL_EXACT, &idx);
Tcl_DecrRefCount(strPtr);
if (result == TCL_OK) {
OSStatus err;
CGColorRef c;
unsigned char pixelCode = idx + MIN_PIXELCODE;
ThemeBrush brush = systemColorMap[idx].brush;
ThemeTextColor textColor = systemColorMap[idx].textColor;
ThemeBackgroundKind background = systemColorMap[idx].background;
struct SystemColorMapEntry entry = systemColorMap[idx];
err = ChkErr(GetThemeColor, 0, brush, textColor, background, &c);
err = ChkErr(SetCGColorComponents, entry, 0, &c);
if (err == noErr) {
const size_t n = CGColorGetNumberOfComponents(c);
const CGFloat *rgba = CGColorGetComponents(c);
@@ -591,12 +786,12 @@ TkpGetColor(
color.red = color.green = color.blue = rgba[0] * 65535.0;
break;
default:
Tcl_Panic("CGColor with %d components", (int) n);
Tcl_Panic("CGColor with %d components", (int) n);
}
color.pixel = ((((((pixelCode << 8)
| ((color.red >> 8) & 0xff)) << 8)
| ((color.green >> 8) & 0xff)) << 8)
| ((color.blue >> 8) & 0xff));
| ((color.red >> 8) & 0xff)) << 8)
| ((color.green >> 8) & 0xff)) << 8)
| ((color.blue >> 8) & 0xff));
CGColorRelease(c);
goto validXColor;
}

View File

@@ -79,22 +79,8 @@
#define NSInformationalAlertStyle NSAlertStyleInformational
#define NSCriticalAlertStyle NSAlertStyleCritical
#define NSCenterTextAlignment NSTextAlignmentCenter
#define NSDeviceIndependentModifierFlagsMask NSEventModifierFlagDeviceIndependentFlagsMask
#define NSCommandKeyMask NSEventModifierFlagCommand
#define NSShiftKeyMask NSEventModifierFlagShift
#define NSAlphaShiftKeyMask NSEventModifierFlagCapsLock
#define NSAlternateKeyMask NSEventModifierFlagOption
#define NSControlKeyMask NSEventModifierFlagControl
#define NSNumericPadKeyMask NSEventModifierFlagNumericPad
#define NSFunctionKeyMask NSEventModifierFlagFunction
#define NSKeyUp NSEventTypeKeyUp
#define NSKeyDown NSEventTypeKeyDown
#define NSFlagsChanged NSEventTypeFlagsChanged
#define NSAlphaShiftKeyMask NSEventModifierFlagCapsLock
#define NSShiftKeyMask NSEventModifierFlagShift
#define NSAnyEventMask NSEventMaskAny
#define NSApplicationDefinedMask NSEventMaskApplicationDefined
#define NSTexturedBackgroundWindowMask NSWindowStyleMaskTexturedBackground
#define NSUtilityWindowMask NSWindowStyleMaskUtilityWindow
#define NSNonactivatingPanelMask NSWindowStyleMaskNonactivatingPanel
#define NSDocModalWindowMask NSWindowStyleMaskDocModalWindow

View File

@@ -185,7 +185,7 @@ static const struct CursorName cursorNames[] = {
* Declarations of static variables used in this file.
*/
static TkMacOSXCursor * gCurrentCursor = NULL;
static TkMacOSXCursor *gCurrentCursor = NULL;
/* A pointer to the current cursor. */
static int gResizeOverride = false;
/* A boolean indicating whether we should use
@@ -194,7 +194,7 @@ static int gTkOwnsCursor = true;/* A boolean indicating whether Tk owns the
* cursor. If not (for instance, in the case
* where a Tk window is embedded in another
* app's window, and the cursor is out of the
* tk window, we will not attempt to adjust
* Tk window, we will not attempt to adjust
* the cursor. */
/*
@@ -278,6 +278,7 @@ FindCursorByName(
kCGColorSpaceGenericGray);
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL,
bitmap, pix*pix/8, NULL);
if (provider) {
img = CGImageCreate(pix, pix, 1, 1, pix/8, colorspace,
kCGBitmapByteOrderDefault, provider, decodeWB, 0,
@@ -299,14 +300,21 @@ FindCursorByName(
initWithCGImage:maskedImg];
CFRelease(maskedImg);
}
if (mask) { CFRelease(mask); }
if (img) { CFRelease(img); }
if (colorspace) { CFRelease(colorspace); }
if (mask) {
CFRelease(mask);
}
if (img) {
CFRelease(img);
}
if (colorspace) {
CFRelease(colorspace);
}
if (bitmapImageRep) {
image = [[NSImage alloc] initWithSize:NSMakeSize(pix, pix)];
[image addRepresentation:bitmapImageRep];
[bitmapImageRep release];
}
uint16_t *hotSpotData = (uint16_t*)(bitmap + 2*pix*pix/8);
hotSpot.y = CFSwapInt16BigToHost(*hotSpotData++);
hotSpot.x = CFSwapInt16BigToHost(*hotSpotData);

View File

@@ -23,7 +23,9 @@
/*
* The definitions below provide symbolic names for the default colors.
* NORMAL_BG - Normal background color.
* NORMAL_FG - Normal foreground color.
* ACTIVE_BG - Background color when widget is active.
* ACTIVE_FG - Foreground color when widget is active.
* SELECT_BG - Background color for selected text.
* SELECT_FG - Foreground color for selected text.
* TROUGH - Background color for troughs in scales and scrollbars.
@@ -33,12 +35,14 @@
#define BLACK "Black"
#define WHITE "White"
#define NORMAL_BG "systemWindowBody"
#define ACTIVE_BG "systemButtonFacePressed"
#define ACTIVE_FG "systemPushButtonPressedText"
#define SELECT_BG "systemHighlight"
#define SELECT_FG None
#define INACTIVE_SELECT_BG "systemHighlightSecondary"
#define NORMAL_BG "systemWindowBackgroundColor"
#define TEXT_BG "systemTextBackgroundColor"
#define NORMAL_FG "systemTextColor"
#define ACTIVE_BG "systemWindowBackgroundColor"
#define ACTIVE_FG "systemTextColor"
#define SELECT_BG "systemSelectedTextBackgroundColor"
#define SELECT_FG "systemSelectedTextColor"
#define INACTIVE_SELECT_BG "systemSelectedTextBackgroundColor"
#define TROUGH "#c3c3c3"
#define INDICATOR "#b03060"
#define DISABLED "#a3a3a3"
@@ -50,11 +54,10 @@
#define DEF_BUTTON_ANCHOR "center"
#define DEF_BUTTON_ACTIVE_BG_COLOR ACTIVE_BG
#define DEF_BUTTON_ACTIVE_BG_MONO BLACK
#define DEF_BUTTON_ACTIVE_FG_COLOR ACTIVE_FG
#define DEF_CHKRAD_ACTIVE_FG_COLOR DEF_BUTTON_ACTIVE_FG_COLOR
#define DEF_BUTTON_ACTIVE_FG_COLOR WHITE
#define DEF_CHKRAD_ACTIVE_FG_COLOR ACTIVE_FG
#define DEF_BUTTON_ACTIVE_FG_MONO WHITE
/* #define DEF_BUTTON_BG_COLOR "systemButtonFace"*/
#define DEF_BUTTON_BG_COLOR WHITE
#define DEF_BUTTON_BG_COLOR NORMAL_BG
#define DEF_BUTTON_BG_MONO WHITE
#define DEF_BUTTON_BITMAP ""
#define DEF_BUTTON_BORDER_WIDTH "2"
@@ -64,7 +67,7 @@
#define DEF_BUTTON_DEFAULT "disabled"
#define DEF_BUTTON_DISABLED_FG_COLOR DISABLED
#define DEF_BUTTON_DISABLED_FG_MONO ""
#define DEF_BUTTON_FG "systemButtonText"
#define DEF_BUTTON_FG NORMAL_FG
#define DEF_CHKRAD_FG DEF_BUTTON_FG
#define DEF_BUTTON_FONT "TkDefaultFont"
#define DEF_BUTTON_HEIGHT "0"
@@ -78,7 +81,7 @@
//#else
#define DEF_BUTTON_HIGHLIGHT_WIDTH "1"
//#endif
#define DEF_BUTTON_IMAGE ((char *) NULL)
#define DEF_BUTTON_IMAGE NULL
#define DEF_BUTTON_INDICATOR "1"
#define DEF_BUTTON_JUSTIFY "center"
#define DEF_BUTTON_OFF_VALUE "0"
@@ -105,10 +108,10 @@
#define DEF_BUTTON_REPEAT_INTERVAL "0"
#define DEF_BUTTON_SELECT_COLOR INDICATOR
#define DEF_BUTTON_SELECT_MONO BLACK
#define DEF_BUTTON_SELECT_IMAGE ((char *) NULL)
#define DEF_BUTTON_SELECT_IMAGE NULL
#define DEF_BUTTON_STATE "normal"
#define DEF_LABEL_TAKE_FOCUS "0"
#define DEF_BUTTON_TAKE_FOCUS ((char *) NULL)
#define DEF_BUTTON_TAKE_FOCUS NULL
#define DEF_BUTTON_TEXT ""
#define DEF_BUTTON_TEXT_VARIABLE ""
#define DEF_BUTTON_UNDERLINE "-1"
@@ -146,7 +149,7 @@
#define DEF_CANVAS_SELECT_BD_MONO "0"
#define DEF_CANVAS_SELECT_FG_COLOR SELECT_FG
#define DEF_CANVAS_SELECT_FG_MONO WHITE
#define DEF_CANVAS_TAKE_FOCUS ((char *) NULL)
#define DEF_CANVAS_TAKE_FOCUS NULL
#define DEF_CANVAS_WIDTH "10c"
#define DEF_CANVAS_X_SCROLL_CMD ""
#define DEF_CANVAS_X_SCROLL_INCREMENT "0"
@@ -169,7 +172,7 @@
#define MAC_OSX_ENTRY_RELIEF TK_RELIEF_SUNKEN
#define MAC_OSX_ENTRY_SELECT_RELIEF TK_RELIEF_FLAT
#define DEF_ENTRY_BG_COLOR NORMAL_BG
#define DEF_ENTRY_BG_COLOR TEXT_BG
#define DEF_ENTRY_BG_MONO WHITE
#define DEF_ENTRY_BORDER_WIDTH "2"
#define DEF_ENTRY_CURSOR "xterm"
@@ -178,23 +181,20 @@
#define DEF_ENTRY_DISABLED_FG DISABLED
#define DEF_ENTRY_EXPORT_SELECTION "1"
#define DEF_ENTRY_FONT "TkTextFont"
#define DEF_ENTRY_FG BLACK
#define DEF_ENTRY_FG NORMAL_FG
#define DEF_ENTRY_HIGHLIGHT_BG NORMAL_BG
#define DEF_ENTRY_HIGHLIGHT BLACK
/* #define DEF_ENTRY_HIGHLIGHT_WIDTH "3" */
#define DEF_ENTRY_HIGHLIGHT_WIDTH "3"
#define DEF_ENTRY_INSERT_BG BLACK
#define DEF_ENTRY_INSERT_BG NORMAL_FG
#define DEF_ENTRY_INSERT_BD_COLOR "0"
#define DEF_ENTRY_INSERT_BD_MONO "0"
#define DEF_ENTRY_INSERT_OFF_TIME "300"
#define DEF_ENTRY_INSERT_ON_TIME "600"
/* #define DEF_ENTRY_INSERT_WIDTH "2" */
#define DEF_ENTRY_INSERT_WIDTH "1"
#define DEF_ENTRY_JUSTIFY "left"
#define DEF_ENTRY_READONLY_BG_COLOR NORMAL_BG
#define DEF_ENTRY_READONLY_BG_MONO WHITE
#define DEF_ENTRY_RELIEF "sunken"
/* #define DEF_ENTRY_RELIEF "solid" */
#define DEF_ENTRY_SCROLL_COMMAND ""
#define DEF_ENTRY_SELECT_COLOR SELECT_BG
#define DEF_ENTRY_SELECT_MONO BLACK
@@ -202,9 +202,9 @@
#define DEF_ENTRY_SELECT_BD_MONO "0"
#define DEF_ENTRY_SELECT_FG_COLOR SELECT_FG
#define DEF_ENTRY_SELECT_FG_MONO WHITE
#define DEF_ENTRY_SHOW ((char *) NULL)
#define DEF_ENTRY_SHOW NULL
#define DEF_ENTRY_STATE "normal"
#define DEF_ENTRY_TAKE_FOCUS ((char *) NULL)
#define DEF_ENTRY_TAKE_FOCUS NULL
#define DEF_ENTRY_TEXT_VARIABLE ""
#define DEF_ENTRY_WIDTH "20"
@@ -237,7 +237,7 @@
#define DEF_LABELFRAME_BORDER_WIDTH "2"
#define DEF_LABELFRAME_CLASS "Labelframe"
#define DEF_LABELFRAME_RELIEF "groove"
#define DEF_LABELFRAME_FG "systemButtonText"
#define DEF_LABELFRAME_FG NORMAL_FG
#define DEF_LABELFRAME_FONT "TkDefaultFont"
#define DEF_LABELFRAME_TEXT ""
#define DEF_LABELFRAME_LABELANCHOR "nw"
@@ -247,14 +247,14 @@
*/
#define DEF_LISTBOX_ACTIVE_STYLE "dotbox"
#define DEF_LISTBOX_BG_COLOR WHITE
#define DEF_LISTBOX_BG_COLOR TEXT_BG
#define DEF_LISTBOX_BG_MONO WHITE
#define DEF_LISTBOX_BORDER_WIDTH "1"
#define DEF_LISTBOX_CURSOR ""
#define DEF_LISTBOX_DISABLED_FG DISABLED
#define DEF_LISTBOX_EXPORT_SELECTION "1"
#define DEF_LISTBOX_FONT "TkTextFont"
#define DEF_LISTBOX_FG BLACK
#define DEF_LISTBOX_FG NORMAL_FG
#define DEF_LISTBOX_HEIGHT "10"
#define DEF_LISTBOX_HIGHLIGHT_BG NORMAL_BG
#define DEF_LISTBOX_HIGHLIGHT BLACK
@@ -271,36 +271,36 @@
#define DEF_LISTBOX_SELECT_MODE "browse"
#define DEF_LISTBOX_SET_GRID "0"
#define DEF_LISTBOX_STATE "normal"
#define DEF_LISTBOX_TAKE_FOCUS ((char *) NULL)
#define DEF_LISTBOX_TAKE_FOCUS NULL
#define DEF_LISTBOX_WIDTH "20"
/*
* Defaults for individual entries of menus:
*/
#define DEF_MENU_ENTRY_ACTIVE_BG ((char *) NULL)
#define DEF_MENU_ENTRY_ACTIVE_FG ((char *) NULL)
#define DEF_MENU_ENTRY_ACCELERATOR ((char *) NULL)
#define DEF_MENU_ENTRY_BG ((char *) NULL)
#define DEF_MENU_ENTRY_BITMAP None
#define DEF_MENU_ENTRY_ACTIVE_BG NULL
#define DEF_MENU_ENTRY_ACTIVE_FG NULL
#define DEF_MENU_ENTRY_ACCELERATOR NULL
#define DEF_MENU_ENTRY_BG NULL
#define DEF_MENU_ENTRY_BITMAP NULL
#define DEF_MENU_ENTRY_COLUMN_BREAK "0"
#define DEF_MENU_ENTRY_COMMAND ((char *) NULL)
#define DEF_MENU_ENTRY_COMMAND NULL
#define DEF_MENU_ENTRY_COMPOUND "none"
#define DEF_MENU_ENTRY_FG ((char *) NULL)
#define DEF_MENU_ENTRY_FONT ((char *) NULL)
#define DEF_MENU_ENTRY_FG NULL
#define DEF_MENU_ENTRY_FONT NULL
#define DEF_MENU_ENTRY_HIDE_MARGIN "0"
#define DEF_MENU_ENTRY_IMAGE ((char *) NULL)
#define DEF_MENU_ENTRY_IMAGE NULL
#define DEF_MENU_ENTRY_INDICATOR "1"
#define DEF_MENU_ENTRY_LABEL ((char *) NULL)
#define DEF_MENU_ENTRY_MENU ((char *) NULL)
#define DEF_MENU_ENTRY_LABEL NULL
#define DEF_MENU_ENTRY_MENU NULL
#define DEF_MENU_ENTRY_OFF_VALUE "0"
#define DEF_MENU_ENTRY_ON_VALUE "1"
#define DEF_MENU_ENTRY_SELECT_IMAGE ((char *) NULL)
#define DEF_MENU_ENTRY_SELECT_IMAGE NULL
#define DEF_MENU_ENTRY_STATE "normal"
#define DEF_MENU_ENTRY_VALUE ((char *) NULL)
#define DEF_MENU_ENTRY_CHECK_VARIABLE ((char *) NULL)
#define DEF_MENU_ENTRY_VALUE NULL
#define DEF_MENU_ENTRY_CHECK_VARIABLE NULL
#define DEF_MENU_ENTRY_RADIO_VARIABLE "selectedButton"
#define DEF_MENU_ENTRY_SELECT ((char *) NULL)
#define DEF_MENU_ENTRY_SELECT NULL
#define DEF_MENU_ENTRY_UNDERLINE "-1"
/*
@@ -326,7 +326,7 @@
#define DEF_MENU_SELECT_MONO BLACK
#define DEF_MENU_TAKE_FOCUS "0"
#define DEF_MENU_TEAROFF "0"
#define DEF_MENU_TEAROFF_CMD ((char *) NULL)
#define DEF_MENU_TEAROFF_CMD NULL
#define DEF_MENU_TITLE ""
#define DEF_MENU_TYPE "normal"
@@ -334,32 +334,32 @@
* Defaults for menubuttons:
*/
#define DEF_MENUBUTTON_ANCHOR "center"
#define DEF_MENUBUTTON_ANCHOR "w"
#define DEF_MENUBUTTON_ACTIVE_BG_COLOR ACTIVE_BG
#define DEF_MENUBUTTON_ACTIVE_BG_MONO BLACK
#define DEF_MENUBUTTON_ACTIVE_BG_MONO WHITE
#define DEF_MENUBUTTON_ACTIVE_FG_COLOR ACTIVE_FG
#define DEF_MENUBUTTON_ACTIVE_FG_MONO WHITE
#define DEF_MENUBUTTON_ACTIVE_FG_MONO BLACK
#define DEF_MENUBUTTON_BG_COLOR NORMAL_BG
#define DEF_MENUBUTTON_BG_MONO WHITE
#define DEF_MENUBUTTON_BITMAP ""
#define DEF_MENUBUTTON_BORDER_WIDTH "2"
#define DEF_MENUBUTTON_BORDER_WIDTH "0"
#define DEF_MENUBUTTON_CURSOR ""
#define DEF_MENUBUTTON_DIRECTION "below"
#define DEF_MENUBUTTON_DISABLED_FG_COLOR DISABLED
#define DEF_MENUBUTTON_DISABLED_FG_MONO ""
#define DEF_MENUBUTTON_FONT "TkDefaultFont"
#define DEF_MENUBUTTON_FG BLACK
#define DEF_MENUBUTTON_FG NORMAL_FG
#define DEF_MENUBUTTON_HEIGHT "0"
#define DEF_MENUBUTTON_HIGHLIGHT_BG_COLOR DEF_MENUBUTTON_BG_COLOR
#define DEF_MENUBUTTON_HIGHLIGHT_BG_MONO DEF_MENUBUTTON_BG_MONO
#define DEF_MENUBUTTON_HIGHLIGHT BLACK
#define DEF_MENUBUTTON_HIGHLIGHT_WIDTH "0"
#define DEF_MENUBUTTON_IMAGE ((char *) NULL)
#define DEF_MENUBUTTON_IMAGE NULL
#define DEF_MENUBUTTON_INDICATOR "1"
#define DEF_MENUBUTTON_JUSTIFY "left"
#define DEF_MENUBUTTON_MENU ""
#define DEF_MENUBUTTON_PADX "4"
#define DEF_MENUBUTTON_PADY "3"
#define DEF_MENUBUTTON_PADX "0"
#define DEF_MENUBUTTON_PADY "0"
#define DEF_MENUBUTTON_RELIEF "flat"
#define DEF_MENUBUTTON_STATE "normal"
#define DEF_MENUBUTTON_TAKE_FOCUS "0"
@@ -379,7 +379,7 @@
#define DEF_MESSAGE_BG_MONO WHITE
#define DEF_MESSAGE_BORDER_WIDTH "1"
#define DEF_MESSAGE_CURSOR ""
#define DEF_MESSAGE_FG BLACK
#define DEF_MESSAGE_FG NORMAL_FG
#define DEF_MESSAGE_FONT "TkDefaultFont"
#define DEF_MESSAGE_HIGHLIGHT_BG NORMAL_BG
#define DEF_MESSAGE_HIGHLIGHT BLACK
@@ -443,7 +443,7 @@
#define DEF_SCALE_CURSOR ""
#define DEF_SCALE_DIGITS "0"
#define DEF_SCALE_FONT "TkDefaultFont"
#define DEF_SCALE_FG_COLOR BLACK
#define DEF_SCALE_FG_COLOR NORMAL_FG
#define DEF_SCALE_FG_MONO BLACK
#define DEF_SCALE_FROM "0"
#define DEF_SCALE_HIGHLIGHT_BG_COLOR DEF_SCALE_BG_COLOR
@@ -463,7 +463,7 @@
#define DEF_SCALE_SLIDER_LENGTH "30"
#define DEF_SCALE_SLIDER_RELIEF "raised"
#define DEF_SCALE_STATE "normal"
#define DEF_SCALE_TAKE_FOCUS ((char *) NULL)
#define DEF_SCALE_TAKE_FOCUS NULL
#define DEF_SCALE_TICK_INTERVAL "0"
#define DEF_SCALE_TO "100"
#define DEF_SCALE_VARIABLE ""
@@ -490,7 +490,7 @@
#define DEF_SCROLLBAR_RELIEF "flat"
#define DEF_SCROLLBAR_REPEAT_DELAY "300"
#define DEF_SCROLLBAR_REPEAT_INTERVAL "100"
#define DEF_SCROLLBAR_TAKE_FOCUS ((char *) NULL)
#define DEF_SCROLLBAR_TAKE_FOCUS NULL
#define DEF_SCROLLBAR_TROUGH_COLOR TROUGH
#define DEF_SCROLLBAR_TROUGH_MONO WHITE
#define DEF_SCROLLBAR_WIDTH "15"
@@ -500,19 +500,19 @@
*/
#define DEF_TEXT_AUTO_SEPARATORS "1"
#define DEF_TEXT_BG_COLOR NORMAL_BG
#define DEF_TEXT_BG_COLOR TEXT_BG
#define DEF_TEXT_BG_MONO WHITE
#define DEF_TEXT_BLOCK_CURSOR "0"
#define DEF_TEXT_BORDER_WIDTH "0"
#define DEF_TEXT_CURSOR "xterm"
#define DEF_TEXT_FG BLACK
#define DEF_TEXT_FG NORMAL_FG
#define DEF_TEXT_EXPORT_SELECTION "1"
#define DEF_TEXT_FONT "TkFixedFont"
#define DEF_TEXT_HEIGHT "24"
#define DEF_TEXT_HIGHLIGHT_BG NORMAL_BG
#define DEF_TEXT_HIGHLIGHT BLACK
#define DEF_TEXT_HIGHLIGHT_WIDTH "3"
#define DEF_TEXT_INSERT_BG BLACK
#define DEF_TEXT_INSERT_BG NORMAL_FG
#define DEF_TEXT_INSERT_BD_COLOR "0"
#define DEF_TEXT_INSERT_BD_MONO "0"
#define DEF_TEXT_INSERT_OFF_TIME "300"
@@ -538,7 +538,7 @@
#define DEF_TEXT_STATE "normal"
#define DEF_TEXT_TABS ""
#define DEF_TEXT_TABSTYLE "tabular"
#define DEF_TEXT_TAKE_FOCUS ((char *) NULL)
#define DEF_TEXT_TAKE_FOCUS NULL
#define DEF_TEXT_UNDO "0"
#define DEF_TEXT_WIDTH "80"
#define DEF_TEXT_WRAP "char"
@@ -551,6 +551,14 @@
#define DEF_CANVTEXT_FONT "TkDefaultFont"
/*
* Defaults for canvas items
* (arcs, bitmaps, lines, polygons, rectangles, and ovals):
*/
#define DEF_CANVBMAP_FG NORMAL_FG
#define DEF_CANVITEM_OUTLINE NORMAL_FG
/*
* Defaults for toplevels (most of the defaults for frames also apply
* to toplevels):

View File

@@ -22,31 +22,39 @@
#else
#define modalOK NSModalResponseOK
#define modalCancel NSModalResponseCancel
#endif
#endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1090
#define modalOther -1
#define modalError -2
/*Vars for filtering in "open file" and "save file" dialogs.*/
/*
* Vars for filtering in "open file" and "save file" dialogs.
*/
typedef struct {
bool doFileTypes; // show the accessory view which displays the filter menu
bool preselectFilter; // a filter was selected by the typevariable
bool userHasSelectedFilter; // The user has changed the filter in the accessory view
NSMutableArray *fileTypeNames; // array of names, e.g. "Text document"
NSMutableArray *fileTypeExtensions; // array of allowed extensions per name, e.g. "txt", "doc"
NSMutableArray *fileTypeLabels; // displayed string, e.g. "Text document (.txt, .doc)"
NSMutableArray *fileTypeAllowsAll; // boolean if the all pattern (*.*) is included
NSMutableArray *allowedExtensions; // set of all allowed extensions
bool allowedExtensionsAllowAll; // set of all allowed extensions includes *.*
NSUInteger fileTypeIndex; // index of currently selected filter
bool doFileTypes; /* Show the accessory view which
* displays the filter menu */
bool preselectFilter; /* A filter was selected by the
* typevariable. */
bool userHasSelectedFilter; /* The user has changed the filter in
* the accessory view. */
NSMutableArray *fileTypeNames; /* Array of names, e.g. "Text
* document". */
NSMutableArray *fileTypeExtensions; /* Array of allowed extensions per
* name, e.g. "txt", "doc". */
NSMutableArray *fileTypeLabels; /* Displayed string, e.g. "Text
* document (.txt, .doc)". */
NSMutableArray *fileTypeAllowsAll; /* Boolean if the all pattern (*.*) is
* included. */
NSMutableArray *allowedExtensions; /* Set of all allowed extensions. */
bool allowedExtensionsAllowAll; /* Set of all allowed extensions
* includes *.* */
NSUInteger fileTypeIndex; /* Index of currently selected
* filter. */
} filepanelFilterInfo;
filepanelFilterInfo filterInfo;
NSOpenPanel *openpanel;
NSSavePanel *savepanel;
static filepanelFilterInfo filterInfo;
static NSOpenPanel *openpanel;
static NSSavePanel *savepanel;
static const char *const colorOptionStrings[] = {
"-initialcolor", "-parent", "-title", NULL
@@ -166,10 +174,15 @@ static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = {
};
/*
* Construct a file URL from directory and filename. Either may
* be nil. If both are nil, returns nil.
* Construct a file URL from directory and filename. Either may be nil. If both
* are nil, returns nil.
*/
static NSURL *getFileURL(NSString *directory, NSString *filename) {
static NSURL *
getFileURL(
NSString *directory,
NSString *filename)
{
NSURL *url = nil;
if (directory) {
url = [NSURL fileURLWithPath:directory isDirectory:YES];
@@ -182,12 +195,20 @@ static NSURL *getFileURL(NSString *directory, NSString *filename) {
#pragma mark TKApplication(TKDialog)
@interface NSColorPanel(TKDialog)
- (void) _setUseModalAppearance: (BOOL) flag;
@end
@implementation TKApplication(TKDialog)
- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url {
return YES;
}
- (void)panel:(id)sender didChangeToDirectoryURL:(NSURL *)url {
}
- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError {
*outError = nil;
return YES;
}
- (void) tkFilePanelDidEnd: (NSSavePanel *) panel
returnCode: (NSInteger) returnCode contextInfo: (void *) contextInfo
{
@@ -233,7 +254,6 @@ static NSURL *getFileURL(NSString *directory, NSString *filename) {
}
}
- (void) tkAlertDidEnd: (NSAlert *) alert returnCode: (NSInteger) returnCode
contextInfo: (void *) contextInfo
{
@@ -276,12 +296,18 @@ static NSURL *getFileURL(NSString *directory, NSString *filename) {
if ([[filterInfo.fileTypeAllowsAll objectAtIndex:filterInfo.fileTypeIndex] boolValue]) {
[openpanel setAllowsOtherFileTypes:YES];
/* setAllowsOtherFileTypes might have no effect; it's inherited from the
* NSSavePanel, where it has the effect that it does not append an extension
* Setting the allowed file types to nil allows selecting any file */
/*
* setAllowsOtherFileTypes might have no effect; it's inherited from
* the NSSavePanel, where it has the effect that it does not append an
* extension. Setting the allowed file types to nil allows selecting
* any file.
*/
[openpanel setAllowedFileTypes:nil];
} else {
NSMutableArray *allowedtypes = [filterInfo.fileTypeExtensions objectAtIndex:filterInfo.fileTypeIndex];
NSMutableArray *allowedtypes =
[filterInfo.fileTypeExtensions objectAtIndex:filterInfo.fileTypeIndex];
[openpanel setAllowedFileTypes:allowedtypes];
[openpanel setAllowsOtherFileTypes:NO];
}
@@ -297,7 +323,8 @@ static NSURL *getFileURL(NSString *directory, NSString *filename) {
[savepanel setAllowsOtherFileTypes:YES];
[savepanel setAllowedFileTypes:nil];
} else {
NSMutableArray *allowedtypes = [filterInfo.fileTypeExtensions objectAtIndex:filterInfo.fileTypeIndex];
NSMutableArray *allowedtypes =
[filterInfo.fileTypeExtensions objectAtIndex:filterInfo.fileTypeIndex];
[savepanel setAllowedFileTypes:allowedtypes];
[savepanel setAllowsOtherFileTypes:NO];
}
@@ -309,6 +336,30 @@ static NSURL *getFileURL(NSString *directory, NSString *filename) {
#pragma mark -
static NSInteger showOpenSavePanel(
NSSavePanel *panel,
NSWindow *parent,
FilePanelCallbackInfo *callbackInfo)
{
NSInteger modalReturnCode;
if (parent && ![parent attachedSheet] && [NSApp macMinorVersion] < 15) {
[panel beginSheetModalForWindow:parent
completionHandler:^(NSInteger returnCode) {
[NSApp tkFilePanelDidEnd:panel
returnCode:returnCode
contextInfo:callbackInfo ];
}];
modalReturnCode = callbackInfo->cmdObj ? modalOther :
[NSApp runModalForWindow:panel];
} else {
modalReturnCode = [panel runModal];
[NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode
contextInfo:callbackInfo];
}
return modalReturnCode;
}
/*
*----------------------------------------------------------------------
*
@@ -388,6 +439,7 @@ Tk_ChooseColorObjCmd(
[colorPanel _setUseModalAppearance:YES];
if (title) {
NSString *s = [[NSString alloc] initWithUTF8String:title];
[colorPanel setTitle:s];
[s release];
}
@@ -419,9 +471,17 @@ end:
return result;
}
/* dissect the -filetype nested lists and store the information
* in the filterInfo structure */
int parseFileFilters(Tcl_Interp *interp, Tcl_Obj *fileTypesPtr, Tcl_Obj *typeVariablePtr) {
/*
* Dissect the -filetype nested lists and store the information in the
* filterInfo structure.
*/
static int
parseFileFilters(
Tcl_Interp *interp,
Tcl_Obj *fileTypesPtr,
Tcl_Obj *typeVariablePtr)
{
if (!fileTypesPtr) {
filterInfo.doFileTypes = false;
@@ -429,6 +489,7 @@ int parseFileFilters(Tcl_Interp *interp, Tcl_Obj *fileTypesPtr, Tcl_Obj *typeVar
}
FileFilterList fl;
TkInitFileFilters(&fl);
if (TkGetFileFilters(interp, &fl, fileTypesPtr, 0) != TCL_OK) {
TkFreeFileFilters(&fl);
@@ -449,11 +510,12 @@ int parseFileFilters(Tcl_Interp *interp, Tcl_Obj *fileTypesPtr, Tcl_Obj *typeVar
if (filterInfo.doFileTypes) {
for (FileFilter *filterPtr = fl.filters; filterPtr;
filterPtr = filterPtr->next) {
NSString * name = [[NSString alloc] initWithUTF8String: filterPtr -> name];
NSString *name = [[NSString alloc] initWithUTF8String: filterPtr->name];
[filterInfo.fileTypeNames addObject:name];
[name release];
NSMutableArray * clauseextensions = [NSMutableArray array];
NSMutableArray * displayextensions = [NSMutableArray array];
NSMutableArray *clauseextensions = [NSMutableArray array];
NSMutableArray *displayextensions = [NSMutableArray array];
bool allowsAll = NO;
for (FileFilterClause *clausePtr = filterPtr->clauses; clausePtr;
@@ -464,7 +526,7 @@ int parseFileFilters(Tcl_Interp *interp, Tcl_Obj *fileTypesPtr, Tcl_Obj *typeVar
const char *str = globPtr->pattern;
while (*str && (*str == '*' || *str == '.')) {
str++;
}
}
if (*str) {
NSString *extension = [[NSString alloc] initWithUTF8String:str];
if (![filterInfo.allowedExtensions containsObject:extension]) {
@@ -476,7 +538,10 @@ int parseFileFilters(Tcl_Interp *interp, Tcl_Obj *fileTypesPtr, Tcl_Obj *typeVar
[extension release];
} else {
// it is the all pattern (*, .* or *.*)
/*
* It is the all pattern (*, .* or *.*)
*/
allowsAll = YES;
filterInfo.allowedExtensionsAllowAll = YES;
[displayextensions addObject:@"*"];
@@ -486,27 +551,39 @@ int parseFileFilters(Tcl_Interp *interp, Tcl_Obj *fileTypesPtr, Tcl_Obj *typeVar
[filterInfo.fileTypeExtensions addObject:clauseextensions];
[filterInfo.fileTypeAllowsAll addObject:[NSNumber numberWithBool:allowsAll]];
NSMutableString * label = [[NSMutableString alloc] initWithString:name];
NSMutableString *label = [[NSMutableString alloc] initWithString:name];
[label appendString:@" ("];
[label appendString:[displayextensions componentsJoinedByString:@", "]];
[label appendString:@")"];
[filterInfo.fileTypeLabels addObject:label];
[label release];
}
/* Check if the typevariable exists and matches one of the names */
/*
* Check if the typevariable exists and matches one of the names.
*/
filterInfo.preselectFilter = false;
filterInfo.userHasSelectedFilter = false;
if (typeVariablePtr) {
/* extract the variable content as a NSString */
Tcl_Obj *selectedFileTypeObj = Tcl_ObjGetVar2(interp, typeVariablePtr, NULL, TCL_GLOBAL_ONLY);
/*
* Extract the variable content as a NSString.
*/
Tcl_Obj *selectedFileTypeObj = Tcl_ObjGetVar2(interp,
typeVariablePtr, NULL, TCL_GLOBAL_ONLY);
/*
* Check that the typevariable exists.
*/
/* check that the typevariable exists */
if (selectedFileTypeObj != NULL) {
const char *selectedFileType = Tcl_GetString(selectedFileTypeObj);
NSString *selectedFileTypeStr = [[NSString alloc] initWithUTF8String:selectedFileType];
NSUInteger index = [filterInfo.fileTypeNames indexOfObject:selectedFileTypeStr];
const char *selectedFileType =
Tcl_GetString(selectedFileTypeObj);
NSString *selectedFileTypeStr =
[[NSString alloc] initWithUTF8String:selectedFileType];
NSUInteger index =
[filterInfo.fileTypeNames indexOfObject:selectedFileTypeStr];
if (index != NSNotFound) {
filterInfo.fileTypeIndex = index;
@@ -521,17 +598,24 @@ int parseFileFilters(Tcl_Interp *interp, Tcl_Obj *fileTypesPtr, Tcl_Obj *typeVar
return TCL_OK;
}
bool filterCompatible(NSString *extension, int filterIndex) {
NSMutableArray *allowedExtensions = [filterInfo.fileTypeExtensions objectAtIndex: filterIndex];
static bool
filterCompatible(
NSString *extension,
int filterIndex)
{
NSMutableArray *allowedExtensions =
[filterInfo.fileTypeExtensions objectAtIndex: filterIndex];
/*
* If this contains the all pattern, accept any extension.
*/
/* If this contains the all pattern, accept any extension */
if ([[filterInfo.fileTypeAllowsAll objectAtIndex:filterIndex] boolValue]) {
return true;
}
return [allowedExtensions containsObject: extension];
}
/*
*----------------------------------------------------------------------
@@ -570,6 +654,8 @@ Tk_GetOpenFileObjCmd(
NSInteger modalReturnCode = modalError;
BOOL parentIsKey = NO;
[openpanel setDelegate:NSApp];
for (i = 1; i < objc; i += 2) {
if (Tcl_GetIndexFromObjStruct(interp, objv[i], openOptionStrings,
sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
@@ -631,22 +717,24 @@ Tk_GetOpenFileObjCmd(
break;
}
}
if (title) {
[openpanel setTitle:title];
/* From OSX 10.11, the title string is silently ignored in the open panel.
* Prepend the title to the message in this case
* NOTE should be conditional on OSX version, but
* -mmacosx-version-min does not revert this behaviour*/
/*
* From OSX 10.11, the title string is silently ignored in the open
* panel. Prepend the title to the message in this case.
*/
if (message) {
NSString *fullmessage = [[NSString alloc] initWithFormat:@"%@\n%@",title,message];
[message release];
[title release];
message = fullmessage;
} else {
message = title;
if ([NSApp macMinorVersion] > 10) {
if (message) {
NSString *fullmessage =
[[NSString alloc] initWithFormat:@"%@\n%@", title, message];
[message release];
[title release];
message = fullmessage;
} else {
message = title;
}
}
}
@@ -662,117 +750,124 @@ Tk_GetOpenFileObjCmd(
}
if (filterInfo.doFileTypes) {
NSView *accessoryView = [[NSView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 300, 32.0)];
NSTextField *label = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 60, 22)];
NSTextField *label = [[NSTextField alloc]
initWithFrame:NSMakeRect(0, 0, 60, 22)];
NSPopUpButton *popupButton = [[NSPopUpButton alloc]
initWithFrame:NSMakeRect(50.0, 2, 240, 22.0) pullsDown:NO];
NSView *accessoryView = [[NSView alloc]
initWithFrame:NSMakeRect(0.0, 0.0, 300, 32.0)];
[label setEditable:NO];
[label setStringValue:@"Filter:"];
[label setBordered:NO];
[label setBezeled:NO];
[label setDrawsBackground:NO];
NSPopUpButton *popupButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(50.0, 2, 240, 22.0) pullsDown:NO];
[popupButton addItemsWithTitles:filterInfo.fileTypeLabels];
[popupButton setAction:@selector(selectFormat:)];
[accessoryView addSubview:label];
[accessoryView addSubview:popupButton];
if (filterInfo.preselectFilter) {
/* A specific filter was selected from the typevariable. Select it and
* open the accessory view */
/*
* A specific filter was selected from the typevariable. Select it
* and open the accessory view.
*/
[popupButton selectItemAtIndex:filterInfo.fileTypeIndex];
/* on OSX > 10.11, the optons are not visible by default. Ergo allow all file types
/*
* On OSX > 10.11, the options are not visible by default. Ergo
* allow all file types
[openpanel setAllowedFileTypes:filterInfo.fileTypeExtensions[filterInfo.fileTypeIndex]];
*/
[openpanel setAllowedFileTypes:filterInfo.allowedExtensions];
} else {
[openpanel setAllowedFileTypes:filterInfo.allowedExtensions];
}
if (filterInfo.allowedExtensionsAllowAll) {
[openpanel setAllowsOtherFileTypes:YES];
} else {
[openpanel setAllowsOtherFileTypes:NO];
}
[openpanel setAccessoryView:accessoryView];
} else {
/* No filters are given. Allow picking all files */
/*
* No filters are given. Allow picking all files.
*/
[openpanel setAllowsOtherFileTypes:YES];
}
if (cmdObj) {
callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo));
if (Tcl_IsShared(cmdObj)) {
cmdObj = Tcl_DuplicateObj(cmdObj);
}
Tcl_IncrRefCount(cmdObj);
}
callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo));
callbackInfo->cmdObj = cmdObj;
callbackInfo->interp = interp;
callbackInfo->multiple = multiple;
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
if (haveParentOption && parent && ![parent attachedSheet]) {
parentIsKey = [parent isKeyWindow];
if (directory || filename ) {
NSURL * fileURL = getFileURL(directory, filename);
[openpanel setDirectoryURL:fileURL];
}
if (directory || filename) {
NSURL *fileURL = getFileURL(directory, filename);
[openpanel beginSheetModalForWindow:parent
completionHandler:^(NSInteger returnCode)
{ [NSApp tkFilePanelDidEnd:openpanel
returnCode:returnCode
contextInfo:callbackInfo ]; } ];
modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:openpanel];
} else {
if (directory || filename ) {
NSURL * fileURL = getFileURL(directory, filename);
[openpanel setDirectoryURL:fileURL];
}
modalReturnCode = [openpanel runModal];
[NSApp tkFilePanelDidEnd:openpanel returnCode:modalReturnCode
contextInfo:callbackInfo];
[openpanel setDirectoryURL:fileURL];
}
if (haveParentOption) {
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
parentIsKey = parent && [parent isKeyWindow];
} else {
parent = nil;
parentIsKey = False;
}
modalReturnCode = showOpenSavePanel(openpanel, parent, callbackInfo);
result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR;
if (parentIsKey) {
[parent makeKeyWindow];
}
if ((typeVariablePtr && (modalReturnCode == NSOKButton)) &&
filterInfo.doFileTypes) {
if ((typeVariablePtr && (modalReturnCode == NSOKButton))
&& filterInfo.doFileTypes) {
/*
* The -typevariable must be set to the selected file type, if the dialog was not cancelled
* The -typevariable must be set to the selected file type, if the
* dialog was not cancelled.
*/
NSUInteger selectedFilterIndex = filterInfo.fileTypeIndex;
NSString *selectedFilter = NULL;
if (filterInfo.userHasSelectedFilter) {
selectedFilterIndex = filterInfo.fileTypeIndex;
selectedFilter = [filterInfo.fileTypeNames objectAtIndex:selectedFilterIndex];
} else {
/* Difficult case: the user has not touched the filter settings, but we must
* return something in the typevariable. First check if the preselected type is compatible
* with the selected file, otherwise choose the first compatible type from the list,
* finally fall back to the empty string */
/*
* Difficult case: the user has not touched the filter settings,
* but we must return something in the typevariable. First check if
* the preselected type is compatible with the selected file,
* otherwise choose the first compatible type from the list,
* finally fall back to the empty string.
*/
NSURL *selectedFile;
NSString *extension;
if (multiple) {
// Use the first file in the case of multiple selection
// Anyway it is not overly useful here
/*
* Use the first file in the case of multiple selection.
* Anyway it is not overly useful here.
*/
selectedFile = [[openpanel URLs] objectAtIndex:0];
} else {
selectedFile = [openpanel URL];
}
NSString *extension = [selectedFile pathExtension];
extension = [selectedFile pathExtension];
if (filterInfo.preselectFilter &&
filterCompatible(extension, filterInfo.fileTypeIndex)) {
filterCompatible(extension, filterInfo.fileTypeIndex)) {
selectedFilterIndex = filterInfo.fileTypeIndex; // The preselection from the typevariable
selectedFilter = [filterInfo.fileTypeNames objectAtIndex:selectedFilterIndex];
} else {
// scan the list
NSUInteger i;
for (i = 0; i < [filterInfo.fileTypeNames count]; i++) {
if (filterCompatible(extension, i)) {
selectedFilterIndex = i;
@@ -784,19 +879,15 @@ Tk_GetOpenFileObjCmd(
} else {
selectedFilter = @"";
}
}
}
Tcl_ObjSetVar2(interp, typeVariablePtr, NULL,
Tcl_NewStringObj([selectedFilter UTF8String], -1), TCL_GLOBAL_ONLY);
Tcl_NewStringObj([selectedFilter UTF8String], -1),
TCL_GLOBAL_ONLY);
}
end:
end:
return result;
}
/*
*----------------------------------------------------------------------
@@ -811,6 +902,7 @@ Tk_GetOpenFileObjCmd(
*
* Side effects:
* See user documentation.
*
*----------------------------------------------------------------------
*/
@@ -832,10 +924,12 @@ Tk_GetSaveFileObjCmd(
NSString *directory = nil, *filename = nil, *defaultType = nil;
NSString *message = nil, *title = nil;
NSWindow *parent;
savepanel = [NSSavePanel savePanel];
savepanel = [NSSavePanel savePanel];
NSInteger modalReturnCode = modalError;
BOOL parentIsKey = NO;
[savepanel setDelegate:NSApp];
for (i = 1; i < objc; i += 2) {
if (Tcl_GetIndexFromObjStruct(interp, objv[i], saveOptionStrings,
sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
@@ -910,13 +1004,17 @@ Tk_GetSaveFileObjCmd(
if (title) {
[savepanel setTitle:title];
/* From OSX 10.11, the title string is silently ignored, if the save panel is a sheet.
* Prepend the title to the message in this case
* NOTE should be conditional on OSX version, but
* -mmacosx-version-min does not revert this behaviour*/
/*
* From OSX 10.11, the title string is silently ignored, if the save
* panel is a sheet. Prepend the title to the message in this case.
* NOTE: should be conditional on OSX version, but -mmacosx-version-min
* does not revert this behaviour.
*/
if (haveParentOption) {
if (message) {
NSString *fullmessage = [[NSString alloc] initWithFormat:@"%@\n%@",title,message];
NSString *fullmessage =
[[NSString alloc] initWithFormat:@"%@\n%@",title,message];
[message release];
[title release];
message = fullmessage;
@@ -936,15 +1034,20 @@ Tk_GetSaveFileObjCmd(
}
if (filterInfo.doFileTypes) {
NSView *accessoryView = [[NSView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 300, 32.0)];
NSTextField *label = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 60, 22)];
NSView *accessoryView = [[NSView alloc]
initWithFrame:NSMakeRect(0.0, 0.0, 300, 32.0)];
NSTextField *label = [[NSTextField alloc]
initWithFrame:NSMakeRect(0, 0, 60, 22)];
[label setEditable:NO];
[label setStringValue:NSLocalizedString(@"Format:", nil)];
[label setBordered:NO];
[label setBezeled:NO];
[label setDrawsBackground:NO];
NSPopUpButton *popupButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(50.0, 2, 340, 22.0) pullsDown:NO];
NSPopUpButton *popupButton = [[NSPopUpButton alloc]
initWithFrame:NSMakeRect(50.0, 2, 340, 22.0) pullsDown:NO];
[popupButton addItemsWithTitles:filterInfo.fileTypeLabels];
[popupButton selectItemAtIndex:filterInfo.fileTypeIndex];
[popupButton setAction:@selector(saveFormat:)];
@@ -957,10 +1060,14 @@ Tk_GetSaveFileObjCmd(
[savepanel setAllowedFileTypes:[filterInfo.fileTypeExtensions objectAtIndex:filterInfo.fileTypeIndex]];
[savepanel setAllowsOtherFileTypes:filterInfo.allowedExtensionsAllowAll];
} else if (defaultType) {
/* If no filetypes are given, defaultextension is an alternative way
* to specify the attached extension. Just propose this extension,
* but don't display an accessory view */
/*
* If no filetypes are given, defaultextension is an alternative way to
* specify the attached extension. Just propose this extension, but
* don't display an accessory view.
*/
NSMutableArray *AllowedFileTypes = [NSMutableArray array];
[AllowedFileTypes addObject:defaultType];
[savepanel setAllowedFileTypes:AllowedFileTypes];
[savepanel setAllowsOtherFileTypes:YES];
@@ -970,62 +1077,56 @@ Tk_GetSaveFileObjCmd(
[savepanel setExtensionHidden:NO];
if (cmdObj) {
callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo));
if (Tcl_IsShared(cmdObj)) {
cmdObj = Tcl_DuplicateObj(cmdObj);
}
Tcl_IncrRefCount(cmdObj);
}
callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo));
callbackInfo->cmdObj = cmdObj;
callbackInfo->interp = interp;
callbackInfo->multiple = 0;
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
if (haveParentOption && parent && ![parent attachedSheet]) {
parentIsKey = [parent isKeyWindow];
if (directory) {
[savepanel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]];
}
/*check for file name, otherwise set to empty string; crashes with uncaught exception if set to nil*/
if (filename) {
[savepanel setNameFieldStringValue:filename];
} else {
[savepanel setNameFieldStringValue:@""];
}
[savepanel beginSheetModalForWindow:parent
completionHandler:^(NSInteger returnCode)
{ [NSApp tkFilePanelDidEnd:savepanel
returnCode:returnCode
contextInfo:callbackInfo ]; } ];
modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:savepanel];
} else {
if (directory) {
[savepanel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]];
}
/*check for file name, otherwise set to empty string; crashes with uncaught exception if set to nil*/
if (filename) {
[savepanel setNameFieldStringValue:filename];
} else {
[savepanel setNameFieldStringValue:@""];
}
modalReturnCode = [savepanel runModal];
[NSApp tkFilePanelDidEnd:savepanel returnCode:modalReturnCode
contextInfo:callbackInfo];
if (directory) {
[savepanel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]];
}
/*
* Check for file name and set to the empty string if nil. This prevents a crash
* with an uncaught exception.
*/
if (filename) {
[savepanel setNameFieldStringValue:filename];
} else {
[savepanel setNameFieldStringValue:@""];
}
if (haveParentOption) {
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
parentIsKey = parent && [parent isKeyWindow];
} else {
parent = nil;
parentIsKey = False;
}
modalReturnCode = showOpenSavePanel(savepanel, parent, callbackInfo);
result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR;
if (parentIsKey) {
[parent makeKeyWindow];
}
if ((typeVariablePtr && (modalReturnCode == NSOKButton)) && filterInfo.doFileTypes) {
if (typeVariablePtr && (modalReturnCode == NSOKButton)
&& filterInfo.doFileTypes) {
/*
* The -typevariable must be set to the selected file type, if the dialog was not cancelled
* The -typevariable must be set to the selected file type, if the
* dialog was not cancelled.
*/
NSString * selectedFilter = [filterInfo.fileTypeNames objectAtIndex:filterInfo.fileTypeIndex];
Tcl_ObjSetVar2(interp, typeVariablePtr, NULL,
Tcl_NewStringObj([selectedFilter UTF8String], -1), TCL_GLOBAL_ONLY);
}
NSString *selectedFilter =
[filterInfo.fileTypeNames objectAtIndex:filterInfo.fileTypeIndex];
Tcl_ObjSetVar2(interp, typeVariablePtr, NULL,
Tcl_NewStringObj([selectedFilter UTF8String], -1),
TCL_GLOBAL_ONLY);
}
end:
return result;
@@ -1070,6 +1171,8 @@ Tk_ChooseDirectoryObjCmd(
NSInteger modalReturnCode = modalError;
BOOL parentIsKey = NO;
[panel setDelegate:NSApp];
for (i = 1; i < objc; i += 2) {
if (Tcl_GetIndexFromObjStruct(interp, objv[i], chooseOptionStrings,
sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
@@ -1125,35 +1228,34 @@ Tk_ChooseDirectoryObjCmd(
[panel setCanChooseDirectories:YES];
[panel setCanCreateDirectories:!mustexist];
if (cmdObj) {
callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo));
if (Tcl_IsShared(cmdObj)) {
cmdObj = Tcl_DuplicateObj(cmdObj);
}
Tcl_IncrRefCount(cmdObj);
}
callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo));
callbackInfo->cmdObj = cmdObj;
callbackInfo->interp = interp;
callbackInfo->multiple = 0;
/*check for directory value, set to root if not specified; otherwise crashes with exception because of nil string parameter*/
/*
* Check for directory value, set to root if not specified; otherwise
* crashes with exception because of nil string parameter.
*/
if (!directory) {
directory = @"/";
}
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
if (haveParentOption && parent && ![parent attachedSheet]) {
parentIsKey = [parent isKeyWindow];
[panel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]];
[panel beginSheetModalForWindow:parent
completionHandler:^(NSInteger returnCode)
{ [NSApp tkFilePanelDidEnd:panel
returnCode:returnCode
contextInfo:callbackInfo ]; } ];
modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:panel];
[panel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]];
if (haveParentOption) {
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
parentIsKey = parent && [parent isKeyWindow];
} else {
[panel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]];
modalReturnCode = [panel runModal];
[NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode
contextInfo:callbackInfo];
parent = nil;
parentIsKey = False;
}
modalReturnCode = showOpenSavePanel(panel, parent, callbackInfo);
result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR;
if (parentIsKey) {
[parent makeKeyWindow];
@@ -1198,18 +1300,19 @@ TkAboutDlg(void)
NSString *year = [dateFormatter stringFromDate:[NSDate date]];
[dateFormatter release];
/*
* This replaces the old about dialog with a standard alert that displays
* correctly on 10.14.
*/
NSString *version = @"Tcl " TCL_PATCH_LEVEL " & Tk " TCL_PATCH_LEVEL;
NSString *url = @"www.tcl-lang.org";
NSString *url = @"www.tcl-lang.org";
NSTextView *credits = [[NSTextView alloc] initWithFrame:NSMakeRect(0,0,300,300)];
NSFont *font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
NSDictionary *textAttributes = [NSDictionary dictionaryWithObject:font
forKey:NSFontAttributeName];
[credits insertText: [[NSAttributedString alloc]
initWithString:[NSString stringWithFormat: @"\n"
"Tcl and Tk are distributed under a modified BSD license: "
@@ -1223,11 +1326,13 @@ TkAboutDlg(void)
"%1$C 1998-2000 Jim Ingham & Ray Johnson\n\n"
"%1$C 1998-2000 Scriptics Inc.\n\n"
"%1$C 1996-1997 Sun Microsystems Inc.", 0xA9, year]
attributes:textAttributes]
replacementRange:NSMakeRange(0,0)];
attributes:textAttributes]
replacementRange:NSMakeRange(0,0)];
[credits setDrawsBackground:NO];
[credits setEditable:NO];
NSAlert *about = [[NSAlert alloc] init];
NSAlert *about = [[NSAlert alloc] init];
[[about window] setTitle:@"About Tcl & Tk"];
[about setMessageText: version];
[about setInformativeText:url];
@@ -1382,7 +1487,8 @@ Tk_MessageBoxObjCmd(
*/
if (Tcl_GetIndexFromObjStruct(interp, objv[indexDefaultOption + 1],
alertButtonStrings, sizeof(char *), "-default value", TCL_EXACT, &index) != TCL_OK) {
alertButtonStrings, sizeof(char *), "-default value",
TCL_EXACT, &index) != TCL_OK) {
goto end;
}
@@ -1403,7 +1509,7 @@ Tk_MessageBoxObjCmd(
[alert setAlertStyle:alertStyles[iconIndex]];
i = 0;
while (i < 3 && alertButtonNames[typeIndex][i]) {
[alert addButtonWithTitle:(NSString*)alertButtonNames[typeIndex][i++]];
[alert addButtonWithTitle:(NSString*) alertButtonNames[typeIndex][i++]];
}
buttons = [alert buttons];
for (NSButton *b in buttons) {
@@ -1418,24 +1524,25 @@ Tk_MessageBoxObjCmd(
[[buttons objectAtIndex: defaultNativeButtonIndex-1]
setKeyEquivalent: @"\r"];
if (cmdObj) {
callbackInfo = ckalloc(sizeof(AlertCallbackInfo));
if (Tcl_IsShared(cmdObj)) {
cmdObj = Tcl_DuplicateObj(cmdObj);
}
Tcl_IncrRefCount(cmdObj);
}
callbackInfo = ckalloc(sizeof(AlertCallbackInfo));
callbackInfo->cmdObj = cmdObj;
callbackInfo->interp = interp;
callbackInfo->typeIndex = typeIndex;
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
if (haveParentOption && parent && ![parent attachedSheet]) {
parentIsKey = [parent isKeyWindow];
#if MAC_OS_X_VERSION_MIN_REQUIRED > 1090
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
[alert beginSheetModalForWindow:parent
completionHandler:^(NSModalResponse returnCode)
{ [NSApp tkAlertDidEnd:alert
returnCode:returnCode
contextInfo:callbackInfo ]; } ];
completionHandler:^(NSModalResponse returnCode) {
[NSApp tkAlertDidEnd:alert
returnCode:returnCode
contextInfo:callbackInfo];
}];
#else
[alert beginSheetModalForWindow:parent
modalDelegate:NSApp
@@ -1443,7 +1550,7 @@ Tk_MessageBoxObjCmd(
contextInfo:callbackInfo];
#endif
modalReturnCode = cmdObj ? 0 :
[NSApp runModalForWindow:[alert window]];
[alert runModal];
} else {
modalReturnCode = [alert runModal];
[NSApp tkAlertDidEnd:alert returnCode:modalReturnCode
@@ -1475,7 +1582,10 @@ typedef struct FontchooserData {
Tk_Window parent;
} FontchooserData;
enum FontchooserEvent { FontchooserClosed, FontchooserSelection };
enum FontchooserEvent {
FontchooserClosed,
FontchooserSelection
};
static void FontchooserEvent(int kind);
static Tcl_Obj * FontchooserCget(FontchooserData *fcdPtr,
@@ -1567,8 +1677,8 @@ enum FontchooserOption {
*
* FontchooserEvent --
*
* This processes events generated by user interaction with the
* font panel.
* This processes events generated by user interaction with the font
* panel.
*
* Results:
* None.
@@ -1627,9 +1737,8 @@ FontchooserEvent(
*
* FontchooserCget --
*
* Helper for the FontchooserConfigure command to return the
* current value of any of the options (which may be NULL in
* the structure)
* Helper for the FontchooserConfigure command to return the current value
* of any of the options (which may be NULL in the structure).
*
* Results:
* Tcl object of option value.
@@ -1692,8 +1801,8 @@ FontchooserCget(
*
* FontchooserConfigureCmd --
*
* Implementation of the 'tk fontchooser configure' ensemble command.
* See the user documentation for what it does.
* Implementation of the 'tk fontchooser configure' ensemble command. See
* the user documentation for what it does.
*
* Results:
* See the user documentation.
@@ -1826,7 +1935,8 @@ FontchooserConfigureCmd(
[fm setSelectedAttributes:fontPanelFontAttributes
isMultiple:NO];
if ([fp isVisible]) {
TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserFontChanged", NULL);
TkSendVirtualEvent(fcdPtr->parent,
"TkFontchooserFontChanged", NULL);
}
break;
case FontchooserCmd:
@@ -1854,9 +1964,9 @@ FontchooserConfigureCmd(
*
* FontchooserShowCmd --
*
* Implements the 'tk fontchooser show' ensemble command. The
* per-interp configuration data for the dialog is held in an interp
* associated structure.
* Implements the 'tk fontchooser show' ensemble command. The per-interp
* configuration data for the dialog is held in an interp associated
* structure.
*
* Results:
* See the user documentation.
@@ -1882,8 +1992,10 @@ FontchooserShowCmd(
Tk_CreateEventHandler(fcdPtr->parent, StructureNotifyMask,
FontchooserParentEventHandler, fcdPtr);
}
NSFontManager *fm = [NSFontManager sharedFontManager];
NSFontPanel *fp = [fm fontPanel:YES];
if ([fp delegate] != NSApp) {
[fp setDelegate:NSApp];
}
@@ -1901,8 +2013,8 @@ FontchooserShowCmd(
*
* FontchooserHideCmd --
*
* Implementation of the 'tk fontchooser hide' ensemble. See the
* user documentation for details.
* Implementation of the 'tk fontchooser hide' ensemble. See the user
* documentation for details.
*
* Results:
* See the user documentation.
@@ -1921,6 +2033,7 @@ FontchooserHideCmd(
Tcl_Obj *const objv[])
{
NSFontPanel *fp = [[NSFontManager sharedFontManager] fontPanel:NO];
if ([fp isVisible]) {
[fp orderOut:NSApp];
}
@@ -1954,7 +2067,7 @@ FontchooserParentEventHandler(
if (eventPtr->type == DestroyNotify) {
Tk_DeleteEventHandler(fcdPtr->parent, StructureNotifyMask,
FontchooserParentEventHandler, fcdPtr);
fcdPtr->parent = None;
fcdPtr->parent = NULL;
FontchooserHideCmd(NULL, NULL, 0, NULL);
}
}
@@ -2001,8 +2114,8 @@ DeleteFontchooserData(
*
* TkInitFontchooser --
*
* Associate the font chooser configuration data with the Tcl
* interpreter. There is one font chooser per interp.
* Associate the font chooser configuration data with the Tcl interpreter.
* There is one font chooser per interp.
*
* Results:
* None.

File diff suppressed because it is too large Load Diff

View File

@@ -272,7 +272,14 @@ TkpUseWindow(
}
usePtr = (TkWindow *) Tk_IdToWindow(winPtr->display, (Window) parent);
if (usePtr != NULL && !(usePtr->flags & TK_CONTAINER)) {
if (usePtr == NULL) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"couldn't create child of window \"%s\"", string));
Tcl_SetErrorCode(interp, "TK", "EMBED", "NO_TARGET", NULL);
}
return TCL_ERROR;
} else if (!(usePtr->flags & TK_CONTAINER)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"window \"%s\" doesn't have -container option set",
usePtr->pathName));
@@ -281,15 +288,9 @@ TkpUseWindow(
}
/*
* The code below can probably be simplified given we have already
* discovered 'usePtr' above.
*/
/*
* Save information about the container and the embedded window in a
* Container structure. Currently, there must already be an existing
* Container structure, since we only allow the case where both container
* and embedded app. are in the same process.
* Since we do not allow embedding into windows belonging to a different
* process, we know that a container will exist showing the parent window
* as the parent. This loop finds that container.
*/
for (containerPtr = firstContainerPtr; containerPtr != NULL;
@@ -312,16 +313,6 @@ TkpUseWindow(
}
macWin->winPtr = winPtr;
winPtr->privatePtr = macWin;
/*
* The grafPtr will be NULL for a Tk in Tk embedded window. It is none of
* our business what it is for a Tk not in Tk embedded window, but we will
* initialize it to NULL, and let the registerWinProc set it. In any case,
* you must always use TkMacOSXGetDrawablePort to get the portPtr. It will
* correctly find the container's port.
*/
macWin->view = nil;
macWin->context = NULL;
macWin->size = CGSizeZero;
@@ -333,6 +324,7 @@ TkpUseWindow(
macWin->toplevel = macWin;
macWin->toplevel->referenceCount++;
winPtr->privatePtr = macWin;
winPtr->flags |= TK_EMBEDDED;
/*
@@ -341,64 +333,28 @@ TkpUseWindow(
*/
macWin->flags |= TK_EMBEDDED;
macWin->xOff = parent->winPtr->privatePtr->xOff +
parent->winPtr->changes.border_width +
winPtr->changes.x;
macWin->yOff = parent->winPtr->privatePtr->yOff +
parent->winPtr->changes.border_width +
winPtr->changes.y;
/*
* Now check whether it is embedded in another Tk widget. If not (the
* first case below) we see if there is an in-process embedding handler
* registered, and if so, let that fill in the rest of the macWin.
* Finish filling up the container structure with the embedded window's
* information.
*/
if (containerPtr == NULL) {
/*
* If someone has registered an in-process embedding handler, then
* see if it can handle this window...
*/
containerPtr->embedded = (Window) macWin;
containerPtr->embeddedPtr = macWin->winPtr;
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));
Tcl_SetErrorCode(interp, "TK", "EMBED", "HANDLE", NULL);
return TCL_ERROR;
}
/*
* Create an event handler to clean up the Container structure when
* tkwin is eventually deleted.
*/
containerPtr = ckalloc(sizeof(Container));
containerPtr->parentPtr = NULL;
containerPtr->embedded = (Window) macWin;
containerPtr->embeddedPtr = macWin->winPtr;
containerPtr->nextPtr = firstContainerPtr;
firstContainerPtr = containerPtr;
} else {
/*
* The window is embedded in another Tk window.
*/
macWin->xOff = parent->winPtr->privatePtr->xOff +
parent->winPtr->changes.border_width +
winPtr->changes.x;
macWin->yOff = parent->winPtr->privatePtr->yOff +
parent->winPtr->changes.border_width +
winPtr->changes.y;
/*
* Finish filling up the container structure with the embedded
* window's information.
*/
containerPtr->embedded = (Window) macWin;
containerPtr->embeddedPtr = macWin->winPtr;
/*
* Create an event handler to clean up the Container structure when
* tkwin is eventually deleted.
*/
Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc,
winPtr);
}
Tk_CreateEventHandler(tkwin, StructureNotifyMask,
EmbeddedEventProc, winPtr);
return TCL_OK;
}
@@ -494,7 +450,7 @@ TkMacOSXContainerId(
}
}
Tcl_Panic("TkMacOSXContainerId couldn't find window");
return None;
return NULL;
}
/*
@@ -530,8 +486,8 @@ TkMacOSXGetHostToplevel(
* TODO: Here we should handle out of process embedding.
*/
if (contWinPtr == NULL) {
return None;
if (!contWinPtr) {
return NULL;
}
return TkMacOSXGetHostToplevel(contWinPtr);
}
@@ -542,9 +498,7 @@ TkMacOSXGetHostToplevel(
* TkpClaimFocus --
*
* This procedure is invoked when someone asks for the input focus to be
* put on a window in an embedded application, but the application
* doesn't currently have the focus. It requests the input focus from the
* container application.
* put on a window in an embedded application.
*
* Results:
* None.
@@ -583,7 +537,7 @@ TkpClaimFocus(
event.xfocus.window = containerPtr->parent;
event.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
event.xfocus.detail = force;
Tk_QueueWindowEvent(&event,TCL_QUEUE_TAIL);
Tk_HandleEvent(&event);
}
/*
@@ -614,6 +568,7 @@ TkpTestembedCmd(
Container *containerPtr;
Tcl_DString dString;
char buffer[50];
Tcl_Interp *embeddedInterp = NULL, *parentInterp = NULL;
if ((objc > 1) && (strcmp(Tcl_GetString(objv[1]), "all") == 0)) {
all = 1;
@@ -623,30 +578,54 @@ TkpTestembedCmd(
Tcl_DStringInit(&dString);
for (containerPtr = firstContainerPtr; containerPtr != NULL;
containerPtr = containerPtr->nextPtr) {
if (containerPtr->embeddedPtr != NULL) {
embeddedInterp = containerPtr->embeddedPtr->mainPtr->interp;
}
if (containerPtr->parentPtr != NULL) {
parentInterp = containerPtr->parentPtr->mainPtr->interp;
}
if (embeddedInterp != interp && parentInterp != interp) {
continue;
}
Tcl_DStringStartSublist(&dString);
/*
* Parent id
*/
if (containerPtr->parent == None) {
Tcl_DStringAppendElement(&dString, "");
} else if (all) {
sprintf(buffer, "0x%x", (int) containerPtr->parent);
sprintf(buffer, "0x%lx", containerPtr->parent);
Tcl_DStringAppendElement(&dString, buffer);
} else {
Tcl_DStringAppendElement(&dString, "XXX");
}
if (containerPtr->parentPtr == NULL) {
/*
* Parent pathName
*/
if (containerPtr->parentPtr == NULL ||
parentInterp != interp) {
Tcl_DStringAppendElement(&dString, "");
} else {
Tcl_DStringAppendElement(&dString,
containerPtr->parentPtr->pathName);
}
if (containerPtr->embedded == None) {
Tcl_DStringAppendElement(&dString, "");
} else if (all) {
sprintf(buffer, "0x%x", (int) containerPtr->embedded);
Tcl_DStringAppendElement(&dString, buffer);
} else {
Tcl_DStringAppendElement(&dString, "XXX");
}
if (containerPtr->embeddedPtr == NULL) {
/*
* On X11 embedded is a wrapper, which does not exist on macOS.
*/
Tcl_DStringAppendElement(&dString, "");
/*
* Embedded window pathName
*/
if (containerPtr->embeddedPtr == NULL ||
embeddedInterp != interp) {
Tcl_DStringAppendElement(&dString, "");
} else {
Tcl_DStringAppendElement(&dString,
@@ -803,6 +782,7 @@ ContainerEventProc(
/*
* When the interpreter is being dismantled this can be nil.
*/
return;
}
@@ -868,7 +848,9 @@ ContainerEventProc(
eventPtr->xmaprequest.window);
} else if (eventPtr->type == DestroyNotify) {
/*
* The embedded application is gone. Destroy the container window.
* It is not clear whether the container should be destroyed
* when an embedded window is destroyed. See ticket [67384bce7d].
* Here we are following unix, by destroying the container.
*/
Tk_DestroyWindow((Tk_Window) winPtr);
@@ -904,6 +886,14 @@ EmbedStructureProc(
Tk_ErrorHandler errHandler;
if (eventPtr->type == ConfigureNotify) {
/*
* Send a ConfigureNotify to the embedded application.
*/
if (containerPtr->embeddedPtr != None) {
TkDoConfigureNotify(containerPtr->embeddedPtr);
}
if (containerPtr->embedded != None) {
/*
* Ignore errors, since the embedded application could have
@@ -1052,11 +1042,10 @@ EmbedGeometryRequest(
/*
* Forward the requested size into our geometry management hierarchy via
* the container window. We need to send a Configure event back to the
* embedded application if we decide not to honor its request; to make
* this happen, process all idle event handlers synchronously here (so
* that the geometry managers have had a chance to do whatever they want
* to do), and if the window's size didn't change then generate a
* configure event.
* embedded application if we decide not to honor its request; to make this
* happen, process all idle event handlers synchronously here (so that the
* geometry managers have had a chance to do whatever they want to do), and
* if the window's size didn't change then generate a configure event.
*/
Tk_GeometryRequest((Tk_Window) winPtr, width, height);
@@ -1078,8 +1067,8 @@ EmbedGeometryRequest(
* application of its current size and location. This procedure is called
* when the embedded application made a geometry request that we did not
* grant, so that the embedded application knows that its geometry didn't
* change after all. It is a response to ConfigureRequest events, which
* we do not currently synthesize on the Mac
* change after all. It is a response to ConfigureRequest events, which we
* do not currently synthesize on the Mac
*
* Results:
* None.
@@ -1139,8 +1128,8 @@ EmbedWindowDeleted(
containerPtr->parentPtr->flags & TK_BOTH_HALVES) {
XEvent event;
event.xany.serial =
LastKnownRequestProcessed(Tk_Display(containerPtr->parentPtr));
event.xany.serial = LastKnownRequestProcessed(
Tk_Display(containerPtr->parentPtr));
event.xany.send_event = False;
event.xany.display = Tk_Display(containerPtr->parentPtr);

View File

@@ -123,11 +123,18 @@ TkpDrawEntryBorderAndFocus(
if (isSpinbox) {
int incDecWidth;
oldWidth = Tk_Width(tkwin);
/*
* If native spinbox buttons are going to be drawn, then temporarily
* change the width of the widget so that the same code can be used
* for drawing the Entry portion of the Spinbox as is used to draw
* an ordinary Entry. The width must be restored before returning.
*/
ComputeIncDecParameters(Tk_Height(tkwin) - 2 * MAC_OSX_FOCUS_WIDTH,
&incDecWidth);
Tk_Width(tkwin) -= incDecWidth + 1;
oldWidth = Tk_Width(tkwin);
if (ComputeIncDecParameters(Tk_Height(tkwin) - 2 * MAC_OSX_FOCUS_WIDTH,
&incDecWidth) != 0) {
Tk_Width(tkwin) -= incDecWidth + 1;
}
}
/*
@@ -149,6 +156,15 @@ TkpDrawEntryBorderAndFocus(
bounds.size.width = Tk_Width(tkwin) - 2*MAC_OSX_FOCUS_WIDTH;
bounds.size.height = Tk_Height(tkwin) - 2*MAC_OSX_FOCUS_WIDTH;
if (!TkMacOSXSetupDrawingContext(d, NULL, 1, &dc)) {
/*
* No graphics context is available. If the widget is a Spinbox, we
* must restore its width before returning 0. (Ticket [273b6a4996].)
*/
if (isSpinbox) {
Tk_Width(tkwin) = oldWidth;
}
return 0;
}
ChkErr(HIThemeDrawFrame, &bounds, &info, dc.context, HIOrientation);
@@ -171,10 +187,10 @@ TkpDrawEntryBorderAndFocus(
* have to implement it.
*
* Results:
* 1 if it has drawn the border, 0 if not.
* 1 if it has drawn the buttons, 0 if not.
*
* Side effects:
* May draw the entry border into pixmap.
* May draw the buttons into pixmap.
*
*--------------------------------------------------------------
*/
@@ -243,9 +259,9 @@ TkpDrawSpinboxButtons(
*/
bgGC = Tk_GCForColor(sbPtr->entry.highlightBgColorPtr, d);
rects[0].x = bounds.origin.x;
rects[0].x = Tk_Width(tkwin) - incDecWidth - 1;
rects[0].y = 0;
rects[0].width = Tk_Width(tkwin);
rects[0].width = incDecWidth + 1;
rects[0].height = Tk_Height(tkwin);
XFillRectangles(Tk_Display(tkwin), d, bgGC, rects, 1);

View File

@@ -114,21 +114,16 @@ enum {
*
* This routine is a stub called by XSync, which is called during the Tk
* update command. The language specification does not require that the
* update command be synchronous but many of the tests assume that is the
* case. It is not naturally the case on macOS since many idle tasks are
* run inside of the drawRect method of a window's contentView, and that
* method will not be called until after this function returns. To make
* the tests work, we attempt to force this to be synchronous by waiting
* until drawRect has been called for each window. The mechanism we use
* for this is to have drawRect post an ApplicationDefined NSEvent on the
* AppKit event queue when it finishes drawing, and wait for it here.
* update command be synchronous but many of the tests implicitly assume
* that it is. It is definitely asynchronous on macOS since many idle
* tasks are run inside of the drawRect method of a window's contentView,
* which will not be called until after this function returns.
*
* Results:
* None.
*
* Side effects:
* Calls the drawRect method of the contentView of each visible
* window.
* Side effects: Processes all pending idle events then calls the display
* method of each visible window.
*
*----------------------------------------------------------------------
*/
@@ -136,15 +131,12 @@ enum {
MODULE_SCOPE void
TkMacOSXFlushWindows(void)
{
NSArray *macWindows = [NSApp orderedWindows];
if ([NSApp simulateDrawing]) {
[NSApp setSimulateDrawing:NO];
if (Tk_GetNumMainWindows() == 0) {
return;
}
for (NSWindow *w in macWindows) {
if (TkMacOSXGetXWindow(w)) {
[w displayIfNeeded];
}
while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)){}
for (NSWindow *w in [NSApp orderedWindows]) {
[w display];
}
}

View File

@@ -1,8 +1,8 @@
/*
* tkMacOSXFont.c --
*
* Contains the Macintosh implementation of the platform-independant
* font package interface.
* Contains the Macintosh implementation of the platform-independent font
* package interface.
*
* Copyright 2002-2004 Benjamin Riefenstahl, Benjamin.Riefenstahl@epost.de
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
@@ -32,9 +32,8 @@
*/
typedef struct {
TkFont font; /* Stuff used by generic font package. Must
* be first in structure. */
TkFont font; /* Stuff used by generic font package. Must be
* first in structure. */
NSFont *nsFont;
NSDictionary *nsAttributes;
} MacFont;
@@ -83,27 +82,167 @@ static int antialiasedTextEnabled = -1;
static NSCharacterSet *whitespaceCharacterSet = nil;
static NSCharacterSet *lineendingCharacterSet = nil;
static void GetTkFontAttributesForNSFont(NSFont *nsFont,
TkFontAttributes *faPtr);
static NSFont *FindNSFont(const char *familyName, NSFontTraitMask traits,
NSInteger weight, CGFloat size, int fallbackToDefault);
static void InitFont(NSFont *nsFont, const TkFontAttributes *reqFaPtr,
MacFont * fontPtr);
static int CreateNamedSystemFont(Tcl_Interp *interp, Tk_Window tkwin,
const char* name, TkFontAttributes *faPtr);
static void DrawCharsInContext(Display *display, Drawable drawable, GC gc,
Tk_Font tkfont, const char *source, int numBytes, int rangeStart,
int rangeLength, int x, int y, double angle);
@interface NSFont(TKFont)
- (NSFont *) bestMatchingFontForCharacters: (const UTF16Char *) characters
length: (NSUInteger) length attributes: (NSDictionary *) attributes
actualCoveredLength: (NSUInteger *) coveredLength;
@end
static void GetTkFontAttributesForNSFont(NSFont *nsFont,
TkFontAttributes *faPtr);
static NSFont * FindNSFont(const char *familyName,
NSFontTraitMask traits, NSInteger weight,
CGFloat size, int fallbackToDefault);
static void InitFont(NSFont *nsFont,
const TkFontAttributes *reqFaPtr,
MacFont *fontPtr);
static int CreateNamedSystemFont(Tcl_Interp *interp,
Tk_Window tkwin, const char *name,
TkFontAttributes *faPtr);
static void DrawCharsInContext(Display *display, Drawable drawable,
GC gc, Tk_Font tkfont, const char *source,
int numBytes, int rangeStart, int rangeLength,
int x, int y, double angle);
#pragma mark -
#pragma mark Font Helpers:
/*
*---------------------------------------------------------------------------
*
* TclUniToNSString --
*
* When Tcl is compiled with TCL_UTF_MAX = 3 (the default for 8.6) it cannot
* deal directly with UTF-8 encoded non-BMP characters, since their UTF-8
* encoding requires 4 bytes.
*
* As a workaround, these versions of Tcl encode non-BMP characters as a string
* of length 6 in which the high and low UTF-16 surrogates have been encoded
* using the UTF-8 algorithm. The UTF-8 encoding does not allow encoding
* surrogates, so these 6-byte strings are not valid UTF-8, and hence Apple's
* NString class will refuse to instantiate an NSString from the 6-byte
* encoding. This function allows creating an NSString from a C-string which
* has been encoded using this scheme.
*
* Results:
* An NSString, which may be nil.
*
* Side effects:
* None.
*---------------------------------------------------------------------------
*/
MODULE_SCOPE NSString*
TclUniToNSString(
const char *source,
int numBytes)
{
NSString *string = [[NSString alloc] initWithBytesNoCopy:(void *)source
length:numBytes
encoding:NSUTF8StringEncoding
freeWhenDone:NO];
if (!string) {
const unichar *characters = ckalloc(numBytes*sizeof(unichar));
const char *in = source;
unichar *out = (unichar *) characters;
while (in < source + numBytes) {
in += Tcl_UtfToUniChar(in, out++);
}
string = [[NSString alloc] initWithCharacters:characters
length:(out - characters)];
ckfree(characters);
}
return string;
}
/*
*---------------------------------------------------------------------------
*
* TclUniAtIndex --
*
* Write a sequence of bytes up to length 6 which is an encoding of a UTF-16
* character in an NSString. Also record the unicode code point of the character.
* this may be a non-BMP character constructed by reading two surrogates from
* the NSString.
*
* Results:
* Returns the number of bytes written.
*
* Side effects:
* Bytes are written to the char array referenced by the pointer uni and
* the unicode code point is written to the integer referenced by the
* pointer code.
*
*/
MODULE_SCOPE int
TclUniAtIndex(
NSString *string,
int index,
char *uni,
unsigned int *code)
{
char *ptr = uni;
UniChar uniChar = [string characterAtIndex: index];
if (CFStringIsSurrogateHighCharacter(uniChar)) {
UniChar lowChar = [string characterAtIndex: ++index];
*code = CFStringGetLongCharacterForSurrogatePair(
uniChar, lowChar);
ptr += Tcl_UniCharToUtf(uniChar, ptr);
ptr += Tcl_UniCharToUtf(lowChar, ptr);
return ptr - uni;
} else {
*code = (int) uniChar;
[[string substringWithRange: NSMakeRange(index, 1)]
getCString: uni
maxLength: XMaxTransChars
encoding: NSUTF8StringEncoding];
return strlen(uni);
}
}
/*
*---------------------------------------------------------------------------
*
* NSStringToTclUni --
*
* Encodes the unicode string represented by an NSString object with the
* internal encoding that Tcl uses when TCL_UTF_MAX = 3. This encoding
* is similar to UTF-8 except that non-BMP characters are encoded as two
* successive 3-byte sequences which are constructed from UTF-16 surrogates
* by applying the UTF-8 algorithm. Even though the UTF-8 encoding does not
* allow encoding surrogates, the algorithm does produce a well-defined
* 3-byte sequence.
*
* Results:
* Returns a pointer to a null-terminated byte array which encodes the
* NSString.
*
* Side effects:
* Memory is allocated to hold the byte array, which must be freed with
* ckalloc. If the pointer numBytes is not NULL the number of non-null
* bytes written to the array is stored in the integer it references.
*/
MODULE_SCOPE char*
NSStringToTclUni(
NSString *string,
int *numBytes)
{
unsigned int code;
int i;
char *ptr, *bytes = ckalloc(6*[string length] + 1);
ptr = bytes;
if (ptr) {
for (i = 0; i < [string length]; i++) {
ptr += TclUniAtIndex(string, i, ptr, &code);
if (code > 0xffff){
i++;
}
}
*ptr = '\0';
}
if (numBytes) {
*numBytes = ptr - bytes;
}
return bytes;
}
#define GetNSFontTraitsFromTkFontAttributes(faPtr) \
((faPtr)->weight == TK_FW_BOLD ? NSBoldFontMask : NSUnboldFontMask) | \
((faPtr)->slant == TK_FS_ITALIC ? NSItalicFontMask : NSUnitalicFontMask)
@@ -131,11 +270,11 @@ GetTkFontAttributesForNSFont(
{
NSFontTraitMask traits = [[NSFontManager sharedFontManager]
traitsOfFont:nsFont];
faPtr->family = Tk_GetUid([[nsFont familyName] UTF8String]);
faPtr->size = [nsFont pointSize];
faPtr->weight = (traits & NSBoldFontMask ? TK_FW_BOLD : TK_FW_NORMAL);
faPtr->slant = (traits & NSItalicFontMask ? TK_FS_ITALIC : TK_FS_ROMAN);
}
/*
@@ -179,6 +318,18 @@ FindNSFont(
size = [defaultFont pointSize];
}
nsFont = [fm fontWithFamily:family traits:traits weight:weight size:size];
/*
* A second bug in NSFontManager that Apple created for the Catalina OS
* causes requests as above to sometimes return fonts with additional
* traits that were not requested, even though fonts without those unwanted
* traits exist on the system. See bug [90d555e088]. As a workaround
* we ask the font manager to remove any unrequested traits.
*/
if (nsFont) {
nsFont = [fm convertFont:nsFont toNotHaveTrait:~traits];
}
if (!nsFont) {
NSArray *availableFamilies = [fm availableFontFamilies];
NSString *caseFamily = nil;
@@ -238,7 +389,7 @@ InitFont(
int ascent, descent/*, dontAA*/;
static const UniChar ch[] = {'.', 'W', ' ', 0xc4, 0xc1, 0xc2, 0xc3, 0xc7};
/* ., W, Space, Auml, Aacute, Acirc, Atilde, Ccedilla */
#define nCh (sizeof(ch) / sizeof(UniChar))
#define nCh (sizeof(ch) / sizeof(UniChar))
CGGlyph glyphs[nCh];
CGRect boundingRects[nCh];
@@ -250,7 +401,11 @@ InitFont(
TkInitFontAttributes(faPtr);
}
fontPtr->nsFont = nsFont;
// some don't like antialiasing on fixed-width even if bigger than limit
/*
* Some don't like antialiasing on fixed-width even if bigger than limit
*/
// dontAA = [nsFont isFixedPitch] && fontPtr->font.fa.size <= 10;
if (antialiasedTextEnabled >= 0/* || dontAA*/) {
renderingMode = (antialiasedTextEnabled == 0/* || dontAA*/) ?
@@ -300,7 +455,7 @@ InitFont(
NSLigatureAttributeName,
[NSNumber numberWithDouble:kern], NSKernAttributeName, nil];
fontPtr->nsAttributes = [nsAttributes retain];
#undef nCh
#undef nCh
}
/*
@@ -342,7 +497,7 @@ CreateNamedSystemFont(
*
* This procedure is called when an application is created. It
* initializes all the structures that are used by the
* platform-dependant code on a per application basis.
* platform-dependent code on a per application basis.
* Note that this is called before TkpInit() !
*
* Results:
@@ -364,10 +519,14 @@ TkpFontPkgInit(
NSFont *nsFont;
TkFontAttributes fa;
NSMutableCharacterSet *cs;
/* Since we called before TkpInit, we need our own autorelease pool. */
/*
* Since we called before TkpInit, we need our own autorelease pool.
*/
NSAutoreleasePool *pool = [NSAutoreleasePool new];
/* force this for now */
/*
* Force this for now.
*/
if (!mainPtr->winPtr->mainPtr) {
mainPtr->winPtr->mainPtr = mainPtr;
}
@@ -389,10 +548,25 @@ TkpFontPkgInit(
systemFont++;
}
TkInitFontAttributes(&fa);
#if 0
/*
* In macOS 10.15.1 Apple introduced a bug in NSFontManager which caused
* it to not recognize the familyName ".SF NSMono" which is the familyName
* of the default fixed pitch system fault on that system. See bug [855049e799].
* As a workaround we call [NSFont userFixedPitchFontOfSize:11] instead.
* This returns a user font in the "Menlo" family.
*/
nsFont = (NSFont*) CTFontCreateUIFontForLanguage(fixedPitch, 11, NULL);
#else
nsFont = [NSFont userFixedPitchFontOfSize:11];
#endif
if (nsFont) {
GetTkFontAttributesForNSFont(nsFont, &fa);
#if 0
CFRelease(nsFont);
#endif
} else {
fa.family = Tk_GetUid("Monaco");
fa.size = 11;
@@ -419,17 +593,17 @@ TkpFontPkgInit(
* Map a platform-specific native font name to a TkFont.
*
* Results:
* The return value is a pointer to a TkFont that represents the
* native font. If a native font by the given name could not be
* found, the return value is NULL.
* The return value is a pointer to a TkFont that represents the native
* font. If a native font by the given name could not be found, the return
* value is NULL.
*
* Every call to this procedure returns a new TkFont structure, even
* if the name has already been seen before. The caller should call
* Every call to this procedure returns a new TkFont structure, even if
* the name has already been seen before. The caller should call
* TkpDeleteFont() when the font is no longer needed.
*
* The caller is responsible for initializing the memory associated
* with the generic TkFont when this function returns and releasing
* the contents of the generics TkFont before calling TkpDeleteFont().
* The caller is responsible for initializing the memory associated with
* the generic TkFont when this function returns and releasing the
* contents of the generics TkFont before calling TkpDeleteFont().
*
* Side effects:
* None.
@@ -455,8 +629,8 @@ TkpGetNativeFont(
} else {
return NULL;
}
ctFont = CTFontCreateUIFontForLanguage(HIThemeGetUIFontType(
themeFontId), 0, NULL);
ctFont = CTFontCreateUIFontForLanguage(
HIThemeGetUIFontType(themeFontId), 0, NULL);
if (ctFont) {
fontPtr = ckalloc(sizeof(MacFont));
InitFont((NSFont*) ctFont, NULL, fontPtr);
@@ -474,19 +648,18 @@ TkpGetNativeFont(
* closest matching attributes.
*
* Results:
* The return value is a pointer to a TkFont that represents the font
* with the desired attributes. If a font with the desired attributes
* could not be constructed, some other font will be substituted
* automatically.
* The return value is a pointer to a TkFont that represents the font with
* the desired attributes. If a font with the desired attributes could not
* be constructed, some other font will be substituted automatically.
*
* Every call to this procedure returns a new TkFont structure, even
* if the specified attributes have already been seen before. The
* caller should call TkpDeleteFont() to free the platform- specific
* data when the font is no longer needed.
* Every call to this procedure returns a new TkFont structure, even if
* the specified attributes have already been seen before. The caller
* should call TkpDeleteFont() to free the platform- specific data when
* the font is no longer needed.
*
* The caller is responsible for initializing the memory associated
* with the generic TkFont when this function returns and releasing
* the contents of the generic TkFont before calling TkpDeleteFont().
* The caller is responsible for initializing the memory associated with
* the generic TkFont when this function returns and releasing the
* contents of the generic TkFont before calling TkpDeleteFont().
*
* Side effects:
* None.
@@ -498,16 +671,16 @@ TkFont *
TkpGetFontFromAttributes(
TkFont *tkFontPtr, /* If non-NULL, store the information in this
* existing TkFont structure, rather than
* allocating a new structure to hold the
* font; the existing contents of the font
* will be released. If NULL, a new TkFont
* structure is allocated. */
* allocating a new structure to hold the font;
* the existing contents of the font will be
* released. If NULL, a new TkFont structure is
* allocated. */
Tk_Window tkwin, /* For display where font will be used. */
const TkFontAttributes *faPtr)
/* Set of attributes to match. */
{
MacFont *fontPtr;
int points = (int)(TkFontGetPoints(tkwin, faPtr->size) + 0.5);
int points = (int) (TkFontGetPoints(tkwin, faPtr->size) + 0.5);
NSFontTraitMask traits = GetNSFontTraitsFromTkFontAttributes(faPtr);
NSInteger weight = (faPtr->weight == TK_FW_BOLD ? 9 : 5);
NSFont *nsFont;
@@ -544,9 +717,9 @@ TkpGetFontFromAttributes(
* TkpDeleteFont --
*
* Called to release a font allocated by TkpGetNativeFont() or
* TkpGetFontFromAttributes(). The caller should have already
* released the fields of the TkFont that are used exclusively by the
* generic TkFont code.
* TkpGetFontFromAttributes(). The caller should have already released the
* fields of the TkFont that are used exclusively by the generic TkFont
* code.
*
* Results:
* TkFont is deallocated.
@@ -573,8 +746,8 @@ TkpDeleteFont(
*
* TkpGetFontFamilies --
*
* Return information about the font families that are available on
* the display of the given window.
* Return information about the font families that are available on the
* display of the given window.
*
* Results:
* Modifies interp's result object to hold a list of all the available
@@ -606,12 +779,12 @@ TkpGetFontFamilies(
*
* TkpGetSubFonts --
*
* A function used by the testing package for querying the actual
* screen fonts that make up a font object.
* A function used by the testing package for querying the actual screen
* fonts that make up a font object.
*
* Results:
* Modifies interp's result object to hold a list containing the names
* of the screen fonts that make up the given font object.
* Modifies interp's result object to hold a list containing the names of
* the screen fonts that make up the given font object.
*
* Side effects:
* None.
@@ -648,8 +821,8 @@ TkpGetSubFonts(
*
* TkpGetFontAttrsForChar --
*
* Retrieve the font attributes of the actual font used to render a
* given character.
* Retrieve the font attributes of the actual font used to render a given
* character.
*
* Results:
* None.
@@ -751,10 +924,9 @@ Tk_MeasureChars(
* all the characters on the line for context.
*
* Results:
* The return value is the number of bytes from source that
* fit into the span that extends from 0 to maxLength. *lengthPtr is
* filled with the x-coordinate of the right edge of the last
* character that did fit.
* The return value is the number of bytes from source that fit into the
* span that extends from 0 to maxLength. *lengthPtr is filled with the
* x-coordinate of the right edge of the last character that did fit.
*
* Side effects:
* None.
@@ -780,11 +952,11 @@ TkpMeasureCharsInContext(
* TK_PARTIAL_OK means include the last char
* which only partially fits on this line.
* TK_WHOLE_WORDS means stop on a word
* boundary, if possible. TK_AT_LEAST_ONE
* means return at least one character even
* if no characters fit. If TK_WHOLE_WORDS
* and TK_AT_LEAST_ONE are set and the first
* word doesn't fit, we return at least one
* boundary, if possible. TK_AT_LEAST_ONE means
* return at least one character even if no
* characters fit. If TK_WHOLE_WORDS and
* TK_AT_LEAST_ONE are set and the first word
* doesn't fit, we return at least one
* character or whatever characters fit into
* maxLength. TK_ISOLATE_END means that the
* last character should not be considered in
@@ -814,8 +986,7 @@ TkpMeasureCharsInContext(
if (maxLength > 32767) {
maxLength = 32767;
}
string = [[NSString alloc] initWithBytesNoCopy:(void*)source
length:numBytes encoding:NSUTF8StringEncoding freeWhenDone:NO];
string = TclUniToNSString((const char *)source, numBytes);
if (!string) {
length = 0;
fit = rangeLength;
@@ -870,14 +1041,13 @@ TkpMeasureCharsInContext(
}
/*
* If there is no line breakpoint in the source string between
* its start and the index position that fits in maxWidth, then
* If there is no line breakpoint in the source string between its
* start and the index position that fits in maxWidth, then
* CTTypesetterSuggestLineBreak() returns that very last index.
* However if the TK_WHOLE_WORDS flag is set, we want to break
* at a word boundary. In this situation, unless TK_AT_LEAST_ONE
* is set, we must report that zero chars actually fit (in other
* words the smallest word of the source string is still larger
* than maxWidth).
* However if the TK_WHOLE_WORDS flag is set, we want to break at a
* word boundary. In this situation, unless TK_AT_LEAST_ONE is set, we
* must report that zero chars actually fit (in other words the
* smallest word of the source string is still larger than maxWidth).
*/
if ((index >= start) && (index < len) &&
@@ -909,9 +1079,12 @@ TkpMeasureCharsInContext(
CFRelease(line);
}
/* The call to CTTypesetterSuggestClusterBreak above will always
return at least one character regardless of whether it exceeded
it or not. Clean that up now. */
/*
* The call to CTTypesetterSuggestClusterBreak above will always return
* at least one character regardless of whether it exceeded it or not.
* Clean that up now.
*/
while (width > maxWidth && !(flags & TK_PARTIAL_OK)
&& index > start+(flags & TK_AT_LEAST_ONE)) {
range.length = --index;
@@ -952,7 +1125,7 @@ done:
* actual implementation in TkpDrawCharsInContext().
*
* Results:
* None.
* None.
*
* Side effects:
* Information gets drawn on the screen.
@@ -970,8 +1143,8 @@ Tk_DrawChars(
const char *source, /* UTF-8 string to be displayed. Need not be
* '\0' terminated. All Tk meta-characters
* (tabs, control characters, and newlines)
* should be stripped out of the string that
* is passed to this function. If they are not
* should be stripped out of the string that is
* passed to this function. If they are not
* stripped out, they will be displayed as
* regular printing characters. */
int numBytes, /* Number of bytes in string. */
@@ -992,8 +1165,8 @@ TkDrawAngledChars(
const char *source, /* UTF-8 string to be displayed. Need not be
* '\0' terminated. All Tk meta-characters
* (tabs, control characters, and newlines)
* should be stripped out of the string that
* is passed to this function. If they are not
* should be stripped out of the string that is
* passed to this function. If they are not
* stripped out, they will be displayed as
* regular printing characters. */
int numBytes, /* Number of bytes in string. */
@@ -1035,8 +1208,8 @@ TkpDrawCharsInContext(
const char * source, /* UTF-8 string to be displayed. Need not be
* '\0' terminated. All Tk meta-characters
* (tabs, control characters, and newlines)
* should be stripped out of the string that
* is passed to this function. If they are not
* should be stripped out of the string that is
* passed to this function. If they are not
* stripped out, they will be displayed as
* regular printing characters. */
int numBytes, /* Number of bytes in string. */
@@ -1060,8 +1233,8 @@ DrawCharsInContext(
const char * source, /* UTF-8 string to be displayed. Need not be
* '\0' terminated. All Tk meta-characters
* (tabs, control characters, and newlines)
* should be stripped out of the string that
* is passed to this function. If they are not
* should be stripped out of the string that is
* passed to this function. If they are not
* stripped out, they will be displayed as
* regular printing characters. */
int numBytes, /* Number of bytes in string. */
@@ -1092,8 +1265,7 @@ DrawCharsInContext(
!TkMacOSXSetupDrawingContext(drawable, gc, 1, &drawingContext)) {
return;
}
string = [[NSString alloc] initWithBytesNoCopy:(void*)source
length:numBytes encoding:NSUTF8StringEncoding freeWhenDone:NO];
string = TclUniToNSString((const char *)source, numBytes);
if (!string) {
return;
}
@@ -1125,6 +1297,7 @@ DrawCharsInContext(
len = Tcl_NumUtfChars(source, rangeStart + rangeLength);
if (start > 0) {
CGRect clipRect = CGRectInfinite, startBounds;
line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, start));
startBounds = CTLineGetImageBounds(line, context);
CFRelease(line);
@@ -1247,9 +1420,10 @@ TkMacOSXFontDescriptionForNSFontAndNSFontAttributes(
NSUnderlineStyleAttributeName];
id strikethrough = [nsAttributes objectForKey:
NSStrikethroughStyleAttributeName];
objv[i++] = Tcl_NewStringObj(familyName, -1);
objv[i++] = Tcl_NewIntObj([nsFont pointSize]);
#define S(s) Tcl_NewStringObj(STRINGIFY(s),(int)(sizeof(STRINGIFY(s))-1))
#define S(s) Tcl_NewStringObj(STRINGIFY(s),(int)(sizeof(STRINGIFY(s))-1))
objv[i++] = (traits & NSBoldFontMask) ? S(bold) : S(normal);
objv[i++] = (traits & NSItalicFontMask) ? S(italic) : S(roman);
if ([underline respondsToSelector:@selector(intValue)] &&
@@ -1273,8 +1447,9 @@ TkMacOSXFontDescriptionForNSFontAndNSFontAttributes(
* TkMacOSXUseAntialiasedText --
*
* Enables or disables application-wide use of antialiased text (where
* available). Sets up a linked Tcl global variable to allow
* disabling of antialiased text from tcl.
* available). Sets up a linked Tcl global variable to allow disabling of
* antialiased text from Tcl.
*
* The possible values for this variable are:
*
* -1 - Use system default as configurable in "System Prefs" -> "General".

View File

@@ -1,7 +1,7 @@
/*
* tkMacOSXFont.h --
*
* Contains the Macintosh implementation of the platform-independant
* Contains the Macintosh implementation of the platform-independent
* font package interface.
*
* Copyright (c) 1990-1994 The Regents of the University of California.

View File

@@ -1,13 +1,13 @@
/*
* tkMacOSXHLEvents.c --
*
* Implements high level event support for the Macintosh. Currently, the
* only event that really does anything is the Quit event.
* Implements high level event support for the Macintosh.
*
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
* Copyright (c) 2015 Marc Culler
* Copyright (c) 2015-2019 Marc Culler
* Copyright (c) 2019 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.
@@ -29,16 +29,35 @@ typedef struct KillEvent {
* AppleEvent */
} KillEvent;
/*
* When processing an AppleEvent as an idle task, a pointer to one
* of these structs is passed as the clientData.
*/
typedef struct AppleEventInfo {
Tcl_Interp *interp;
const char *procedure;
Tcl_DString command;
NSAppleEventDescriptor *replyEvent; /* Only used for DoScriptText. */
} AppleEventInfo;
/*
* Static functions used only in this file.
*/
static void tkMacOSXProcessFiles(NSAppleEventDescriptor* event,
NSAppleEventDescriptor* replyEvent,
Tcl_Interp *interp,
const char* procedure);
static int MissedAnyParameters(const AppleEvent *theEvent);
static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
static void ProcessAppleEvent(ClientData clientData);
/*
* Names of the procedures which can be used to process AppleEvents.
*/
static const char *openDocumentProc = "::tk::mac::OpenDocument";
static const char *launchURLProc = "::tk::mac::LaunchURL";
static const char *printDocProc = "::tk::mac::PrintDocument";
static const char *scriptFileProc = "::tk::mac::DoScriptFile";
static const char *scriptTextProc = "::tk::mac::DoScriptText";
#pragma mark TKApplication(TKHLEvents)
@@ -78,9 +97,7 @@ static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
- (void) handleOpenApplicationEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
Tcl_Interp *interp = _eventInterp;
if (interp &&
if (_eventInterp &&
Tcl_FindCommand(_eventInterp, "::tk::mac::OpenApplication", NULL, 0)){
int code = Tcl_EvalEx(_eventInterp, "::tk::mac::OpenApplication",
-1, TCL_EVAL_GLOBAL);
@@ -93,12 +110,7 @@ static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
- (void) handleReopenApplicationEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
ProcessSerialNumber thePSN = {0, kCurrentProcess};
SetFrontProcess(&thePSN);
#else
[[NSApplication sharedApplication] activateIgnoringOtherApps: YES];
#endif
[NSApp activateIgnoringOtherApps: YES];
if (_eventInterp && Tcl_FindCommand(_eventInterp,
"::tk::mac::ReopenApplication", NULL, 0)) {
int code = Tcl_EvalEx(_eventInterp, "::tk::mac::ReopenApplication",
@@ -124,160 +136,6 @@ static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
- (void) handleOpenDocumentsEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
tkMacOSXProcessFiles(event, replyEvent, _eventInterp, "::tk::mac::OpenDocument");
}
- (void) handlePrintDocumentsEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
tkMacOSXProcessFiles(event, replyEvent, _eventInterp, "::tk::mac::PrintDocument");
}
- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
OSStatus err;
const AEDesc *theDesc = nil;
DescType type = 0, initialType = 0;
Size actual;
int tclErr = -1;
char URLBuffer[1 + URL_MAX_LENGTH];
char errString[128];
char typeString[5];
/*
* The DoScript event receives one parameter that should be text data or a
* fileURL.
*/
theDesc = [event aeDesc];
if (theDesc == nil) {
return;
}
err = AEGetParamPtr(theDesc, keyDirectObject, typeWildCard, &initialType,
NULL, 0, NULL);
if (err != noErr) {
sprintf(errString, "AEDoScriptHandler: GetParamDesc error %d", (int)err);
AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
errString, strlen(errString));
return;
}
if (MissedAnyParameters((AppleEvent*)theDesc)) {
sprintf(errString, "AEDoScriptHandler: extra parameters");
AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
errString, strlen(errString));
return;
}
if (initialType == typeFileURL || initialType == typeAlias) {
/*
* The descriptor can be coerced to a file url. Source the file, or
* pass the path as a string argument to ::tk::mac::DoScriptFile if
* that procedure exists.
*/
err = AEGetParamPtr(theDesc, keyDirectObject, typeFileURL, &type,
(Ptr) URLBuffer, URL_MAX_LENGTH, &actual);
if (err == noErr && actual > 0){
URLBuffer[actual] = '\0';
NSString *urlString = [NSString stringWithUTF8String:(char*)URLBuffer];
NSURL *fileURL = [NSURL URLWithString:urlString];
Tcl_DString command;
Tcl_DStringInit(&command);
if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptFile", NULL, 0)){
Tcl_DStringAppend(&command, "::tk::mac::DoScriptFile", -1);
} else {
Tcl_DStringAppend(&command, "source", -1);
}
Tcl_DStringAppendElement(&command, [[fileURL path] UTF8String]);
tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command),
Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
}
} else if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
NULL, 0, &actual)) {
if (actual > 0) {
/*
* The descriptor can be coerced to UTF8 text. Evaluate as Tcl, or
* or pass the text as a string argument to ::tk::mac::DoScriptText
* if that procedure exists.
*/
char *data = ckalloc(actual + 1);
if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
data, actual, NULL)) {
if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptText", NULL, 0)){
Tcl_DString command;
Tcl_DStringInit(&command);
Tcl_DStringAppend(&command, "::tk::mac::DoScriptText", -1);
Tcl_DStringAppendElement(&command, data);
tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command),
Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
} else {
tclErr = Tcl_EvalEx(_eventInterp, data, actual, TCL_EVAL_GLOBAL);
}
}
ckfree(data);
}
} else {
/*
* The descriptor can not be coerced to a fileURL or UTF8 text.
*/
for (int i = 0; i < 4; i++) {
typeString[i] = ((char*)&initialType)[3-i];
}
typeString[4] = '\0';
sprintf(errString, "AEDoScriptHandler: invalid script type '%s', "
"must be coercable to 'furl' or 'utf8'", typeString);
AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar, errString,
strlen(errString));
}
/*
* If we ran some Tcl code, put the result in the reply.
*/
if (tclErr >= 0) {
int reslen;
const char *result =
Tcl_GetStringFromObj(Tcl_GetObjResult(_eventInterp), &reslen);
if (tclErr == TCL_OK) {
AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyDirectObject, typeChar,
result, reslen);
} else {
AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
result, reslen);
AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorNumber, typeSInt32,
(Ptr) &tclErr,sizeof(int));
}
}
return;
}
@end
#pragma mark -
/*
*----------------------------------------------------------------------
*
* TkMacOSXProcessFiles --
*
* Extract a list of fileURLs from an AppleEvent and call the specified
* procedure with the file paths as arguments.
*
* Results:
* None.
*
* Side effects:
* The event is handled by running the procedure.
*
*----------------------------------------------------------------------
*/
static void
tkMacOSXProcessFiles(
NSAppleEventDescriptor* event,
NSAppleEventDescriptor* replyEvent,
Tcl_Interp *interp,
const char* procedure)
{
Tcl_Encoding utf8;
const AEDesc *fileSpecDesc = nil;
@@ -288,14 +146,13 @@ tkMacOSXProcessFiles(
Size actual;
long count, index;
AEKeyword keyword;
Tcl_DString command, pathName;
int code;
Tcl_DString pathName;
/*
* Do nothing if we don't have an interpreter or the procedure doesn't exist.
* Do nothing if we don't have an interpreter.
*/
if (!interp || !Tcl_FindCommand(interp, procedure, NULL, 0)) {
if (!_eventInterp) {
return;
}
@@ -325,12 +182,14 @@ tkMacOSXProcessFiles(
}
/*
* Construct a Tcl command which calls the procedure, passing the
* paths contained in the AppleEvent as arguments.
* Construct a Tcl expression which calls the ::tk::mac::OpenDocument
* procedure, passing the paths contained in the AppleEvent as arguments.
*/
Tcl_DStringInit(&command);
Tcl_DStringAppend(&command, procedure, -1);
AppleEventInfo *AEInfo = ckalloc(sizeof(AppleEventInfo));
Tcl_DString *openCommand = &AEInfo->command;
Tcl_DStringInit(openCommand);
Tcl_DStringAppend(openCommand, openDocumentProc, -1);
utf8 = Tcl_GetEncoding(NULL, "utf-8");
for (index = 1; index <= count; index++) {
@@ -347,23 +206,203 @@ tkMacOSXProcessFiles(
continue;
}
Tcl_ExternalToUtfDString(utf8, [[fileURL path] UTF8String], -1, &pathName);
Tcl_DStringAppendElement(&command, Tcl_DStringValue(&pathName));
Tcl_DStringAppendElement(openCommand, Tcl_DStringValue(&pathName));
Tcl_DStringFree(&pathName);
}
Tcl_FreeEncoding(utf8);
AEDisposeDesc(&contents);
AEInfo->interp = _eventInterp;
AEInfo->procedure = openDocumentProc;
AEInfo->replyEvent = nil;
Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
}
- (void) handlePrintDocumentsEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
NSString* file = [[event paramDescriptorForKeyword:keyDirectObject]
stringValue];
const char *printFile = [file UTF8String];
AppleEventInfo *AEInfo = ckalloc(sizeof(AppleEventInfo));
Tcl_DString *printCommand = &AEInfo->command;
Tcl_DStringInit(printCommand);
Tcl_DStringAppend(printCommand, printDocProc, -1);
Tcl_DStringAppendElement(printCommand, printFile);
AEInfo->interp = _eventInterp;
AEInfo->procedure = printDocProc;
AEInfo->replyEvent = nil;
Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
}
- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
OSStatus err;
const AEDesc *theDesc = nil;
DescType type = 0, initialType = 0;
Size actual;
char URLBuffer[1 + URL_MAX_LENGTH];
char errString[128];
/*
* Handle the event by evaluating the Tcl expression we constructed.
* The DoScript event receives one parameter that should be text data or a
* fileURL.
*/
code = Tcl_EvalEx(interp, Tcl_DStringValue(&command),
Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
if (code != TCL_OK) {
Tcl_BackgroundException(interp, code);
theDesc = [event aeDesc];
if (theDesc == nil) {
return;
}
Tcl_DStringFree(&command);
err = AEGetParamPtr(theDesc, keyDirectObject, typeWildCard, &initialType,
NULL, 0, NULL);
if (err != noErr) {
sprintf(errString, "AEDoScriptHandler: GetParamDesc error %d", (int)err);
AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString,
typeChar, errString, strlen(errString));
return;
}
if (MissedAnyParameters((AppleEvent*)theDesc)) {
sprintf(errString, "AEDoScriptHandler: extra parameters");
AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString,
typeChar,errString, strlen(errString));
return;
}
if (initialType == typeFileURL || initialType == typeAlias) {
/*
* This descriptor can be coerced to a file url. Construct a Tcl
* expression which passes the file path as a string argument to
* ::tk::mac::DoScriptFile.
*/
if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeFileURL, &type,
(Ptr) URLBuffer, URL_MAX_LENGTH, &actual)) {
if (actual > 0) {
URLBuffer[actual] = '\0';
NSString *urlString = [NSString stringWithUTF8String:(char*)URLBuffer];
NSURL *fileURL = [NSURL URLWithString:urlString];
AppleEventInfo *AEInfo = ckalloc(sizeof(AppleEventInfo));
Tcl_DString *scriptFileCommand = &AEInfo->command;
Tcl_DStringInit(scriptFileCommand);
Tcl_DStringAppend(scriptFileCommand, scriptFileProc, -1);
Tcl_DStringAppendElement(scriptFileCommand, [[fileURL path] UTF8String]);
AEInfo->interp = _eventInterp;
AEInfo->procedure = scriptFileProc;
AEInfo->replyEvent = nil;
Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
}
}
} else if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
NULL, 0, &actual)) {
/*
* The descriptor cannot be coerced to a file URL but can be coerced to
* text. Construct a Tcl expression which passes the text as a string
* argument to ::tk::mac::DoScriptText.
*/
if (actual > 0) {
char *data = ckalloc(actual + 1);
if (noErr == AEGetParamPtr(theDesc, keyDirectObject,
typeUTF8Text, &type,
data, actual, NULL)) {
AppleEventInfo *AEInfo = ckalloc(sizeof(AppleEventInfo));
Tcl_DString *scriptTextCommand = &AEInfo->command;
Tcl_DStringInit(scriptTextCommand);
Tcl_DStringAppend(scriptTextCommand, scriptTextProc, -1);
Tcl_DStringAppendElement(scriptTextCommand, data);
AEInfo->interp = _eventInterp;
AEInfo->procedure = scriptTextProc;
if (Tcl_FindCommand(AEInfo->interp, AEInfo->procedure, NULL, 0)) {
AEInfo->replyEvent = replyEvent;
ProcessAppleEvent((ClientData)AEInfo);
} else {
AEInfo->replyEvent = nil;
Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
}
}
}
}
}
- (void)handleURLEvent:(NSAppleEventDescriptor*)event
withReplyEvent:(NSAppleEventDescriptor*)replyEvent
{
NSString* url = [[event paramDescriptorForKeyword:keyDirectObject]
stringValue];
const char *cURL=[url UTF8String];
AppleEventInfo *AEInfo = ckalloc(sizeof(AppleEventInfo));
Tcl_DString *launchCommand = &AEInfo->command;
Tcl_DStringInit(launchCommand);
Tcl_DStringAppend(launchCommand, launchURLProc, -1);
Tcl_DStringAppendElement(launchCommand, cURL);
AEInfo->interp = _eventInterp;
AEInfo->procedure = launchURLProc;
AEInfo->replyEvent = nil;
Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
}
@end
#pragma mark -
/*
*----------------------------------------------------------------------
*
* ProcessAppleEvent --
*
* Usually used as an idle task which evaluates a Tcl expression generated
* from an AppleEvent. If the AppleEventInfo passed as the client data
* has a non-null replyEvent, the result of evaluating the expression will
* be added to the reply. This must not be done when this function is
* called as an idle task, but is done when handling DoScriptText events
* when this function is called directly.
*
* Results:
* None.
*
* Side effects:
* The expression will be evaluated and the clientData will be freed.
* The replyEvent may be modified to contain the result of evaluating
* a Tcl expression.
*
*----------------------------------------------------------------------
*/
static void ProcessAppleEvent(
ClientData clientData)
{
int code;
AppleEventInfo *AEInfo = (AppleEventInfo*) clientData;
if (!AEInfo->interp ||
!Tcl_FindCommand(AEInfo->interp, AEInfo->procedure, NULL, 0)) {
return;
}
code = Tcl_EvalEx(AEInfo->interp, Tcl_DStringValue(&AEInfo->command),
Tcl_DStringLength(&AEInfo->command), TCL_EVAL_GLOBAL);
if (code != TCL_OK) {
Tcl_BackgroundException(AEInfo->interp, code);
}
if (AEInfo->replyEvent && code >= 0) {
int reslen;
const char *result = Tcl_GetStringFromObj(Tcl_GetObjResult(AEInfo->interp),
&reslen);
if (code == TCL_OK) {
AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
keyDirectObject, typeChar, result, reslen);
} else {
AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
keyErrorString, typeChar, result, reslen);
AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
keyErrorNumber, typeSInt32, (Ptr) &code, sizeof(int));
}
}
Tcl_DStringFree(&AEInfo->command);
ckfree(clientData);
}
/*
@@ -414,12 +453,17 @@ TkMacOSXInitAppleEvents(
forEventClass:kCoreEventClass andEventID:kAEOpenDocuments];
[aeManager setEventHandler:NSApp
andSelector:@selector(handleOpenDocumentsEvent:withReplyEvent:)
andSelector:@selector(handlePrintDocumentsEvent:withReplyEvent:)
forEventClass:kCoreEventClass andEventID:kAEPrintDocuments];
[aeManager setEventHandler:NSApp
andSelector:@selector(handleDoScriptEvent:withReplyEvent:)
forEventClass:kAEMiscStandards andEventID:kAEDoScript];
[aeManager setEventHandler:NSApp
andSelector:@selector(handleURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass andEventID:kAEGetURL];
}
}

View File

@@ -23,7 +23,7 @@ _XInitImageFuncPtrs(
{
return 0;
}
/*
*----------------------------------------------------------------------
*
@@ -81,27 +81,37 @@ TkMacOSXCreateCGImageWithXImage(
data = memcpy(ckalloc(len), image->data + image->xoffset, len);
}
if (data) {
provider = CGDataProviderCreateWithData(data, data, len, releaseData);
provider = CGDataProviderCreateWithData(data, data, len,
releaseData);
}
if (provider) {
img = CGImageMaskCreate(image->width, image->height, bitsPerComponent,
bitsPerPixel, image->bytes_per_line, provider, decode, 0);
img = CGImageMaskCreate(image->width, image->height,
bitsPerComponent, bitsPerPixel, image->bytes_per_line,
provider, decode, 0);
}
} else if (image->format == ZPixmap && image->bits_per_pixel == 32) {
} else if ((image->format == ZPixmap) && (image->bits_per_pixel == 32)) {
/*
* Color image
*/
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
if (image->width == 0 && image->height == 0) {
/*
* CGCreateImage complains on early macOS releases.
*/
return NULL;
}
bitsPerComponent = 8;
bitsPerPixel = 32;
bitmapInfo = (image->byte_order == MSBFirst ?
kCGBitmapByteOrder32Little : kCGBitmapByteOrder32Big);
kCGBitmapByteOrder32Little : kCGBitmapByteOrder32Big);
bitmapInfo |= kCGImageAlphaLast;
data = memcpy(ckalloc(len), image->data + image->xoffset, len);
if (data) {
provider = CGDataProviderCreateWithData(data, data, len, releaseData);
provider = CGDataProviderCreateWithData(data, data, len,
releaseData);
}
if (provider) {
img = CGImageCreate(image->width, image->height, bitsPerComponent,
@@ -118,7 +128,6 @@ TkMacOSXCreateCGImageWithXImage(
return img;
}
/*
*----------------------------------------------------------------------
*
@@ -170,15 +179,14 @@ XGetImage(
if (win && has_retina == unknown) {
#ifdef __clang__
has_retina = [win respondsToSelector:@selector(backingScaleFactor)]?
yes : no;
has_retina = [win respondsToSelector:@selector(backingScaleFactor)] ?
yes : no;
#else
has_retina = no;
#endif
}
if (has_retina == yes) {
/*
* We only allow scale factors 1 or 2, as Apple currently does.
*/
@@ -196,7 +204,7 @@ XGetImage(
}
bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(drawable,
x, y, width, height);
x, y, width, height);
if (!bitmap_rep) {
TkMacOSXDbgMsg("XGetImage: Failed to construct NSBitmapRep");
return NULL;
@@ -205,12 +213,12 @@ XGetImage(
size = [bitmap_rep bytesPerPlane];
bytes_per_row = [bitmap_rep bytesPerRow];
bitmap = ckalloc(size);
if (!bitmap ||
(bitmap_fmt != 0 && bitmap_fmt != 1) ||
[bitmap_rep samplesPerPixel] != 4 ||
[bitmap_rep isPlanar] != 0 ||
bytes_per_row < 4 * scaled_width ||
size != bytes_per_row*scaled_height ) {
if (!bitmap
|| (bitmap_fmt != 0 && bitmap_fmt != 1)
|| [bitmap_rep samplesPerPixel] != 4
|| [bitmap_rep isPlanar] != 0
|| bytes_per_row < 4 * scaled_width
|| size != bytes_per_row * scaled_height) {
TkMacOSXDbgMsg("XGetImage: Unrecognized bitmap format");
CFRelease(bitmap_rep);
return NULL;
@@ -219,8 +227,8 @@ XGetImage(
CFRelease(bitmap_rep);
/*
* When Apple extracts a bitmap from an NSView, it may be in
* either BGRA or ABGR format. For an XImage we need RGBA.
* When Apple extracts a bitmap from an NSView, it may be in either
* BGRA or ABGR format. For an XImage we need RGBA.
*/
struct pixel_fmt pixel = bitmap_fmt == 0 ? bgra : abgr;
@@ -239,16 +247,16 @@ XGetImage(
}
}
imagePtr = XCreateImage(display, NULL, depth, format, offset,
(char*)bitmap, scaled_width, scaled_height,
bitmap_pad, bytes_per_row);
(char*) bitmap, scaled_width, scaled_height,
bitmap_pad, bytes_per_row);
if (scalefactor == 2) {
imagePtr->pixelpower = 1;
}
} else {
/*
* There are some calls to XGetImage in the generic Tk
* code which pass an XYPixmap rather than a ZPixmap.
* XYPixmaps should be handled here.
* There are some calls to XGetImage in the generic Tk code which pass
* an XYPixmap rather than a ZPixmap. XYPixmaps should be handled
* here.
*/
TkMacOSXDbgMsg("XGetImage does not handle XYPixmaps at the moment.");
}
@@ -314,40 +322,40 @@ ImageGetPixel(
+ (((image->xoffset + x) * image->bits_per_pixel) / NBBY);
switch (image->bits_per_pixel) {
case 32: {
r = (*((unsigned int*) srcPtr) >> 16) & 0xff;
g = (*((unsigned int*) srcPtr) >> 8) & 0xff;
b = (*((unsigned int*) srcPtr) ) & 0xff;
/*if (image->byte_order == LSBFirst) {
r = srcPtr[2]; g = srcPtr[1]; b = srcPtr[0];
} else {
r = srcPtr[1]; g = srcPtr[2]; b = srcPtr[3];
}*/
break;
}
case 16:
r = (*((unsigned short*) srcPtr) >> 7) & 0xf8;
g = (*((unsigned short*) srcPtr) >> 2) & 0xf8;
b = (*((unsigned short*) srcPtr) << 3) & 0xf8;
break;
case 8:
r = (*srcPtr << 2) & 0xc0;
g = (*srcPtr << 4) & 0xc0;
b = (*srcPtr << 6) & 0xc0;
r |= r >> 2 | r >> 4 | r >> 6;
g |= g >> 2 | g >> 4 | g >> 6;
b |= b >> 2 | b >> 4 | b >> 6;
break;
case 4: {
unsigned char c = (x % 2) ? *srcPtr : (*srcPtr >> 4);
r = (c & 0x04) ? 0xff : 0;
g = (c & 0x02) ? 0xff : 0;
b = (c & 0x01) ? 0xff : 0;
break;
}
case 1:
r = g = b = ((*srcPtr) & (0x80 >> (x % 8))) ? 0xff : 0;
break;
case 32:
r = (*((unsigned int*) srcPtr) >> 16) & 0xff;
g = (*((unsigned int*) srcPtr) >> 8) & 0xff;
b = (*((unsigned int*) srcPtr) ) & 0xff;
/*if (image->byte_order == LSBFirst) {
r = srcPtr[2]; g = srcPtr[1]; b = srcPtr[0];
} else {
r = srcPtr[1]; g = srcPtr[2]; b = srcPtr[3];
}*/
break;
case 16:
r = (*((unsigned short*) srcPtr) >> 7) & 0xf8;
g = (*((unsigned short*) srcPtr) >> 2) & 0xf8;
b = (*((unsigned short*) srcPtr) << 3) & 0xf8;
break;
case 8:
r = (*srcPtr << 2) & 0xc0;
g = (*srcPtr << 4) & 0xc0;
b = (*srcPtr << 6) & 0xc0;
r |= r >> 2 | r >> 4 | r >> 6;
g |= g >> 2 | g >> 4 | g >> 6;
b |= b >> 2 | b >> 4 | b >> 6;
break;
case 4: {
unsigned char c = (x % 2) ? *srcPtr : (*srcPtr >> 4);
r = (c & 0x04) ? 0xff : 0;
g = (c & 0x02) ? 0xff : 0;
b = (c & 0x01) ? 0xff : 0;
break;
}
case 1:
r = g = b = ((*srcPtr) & (0x80 >> (x % 8))) ? 0xff : 0;
break;
}
}
return (PIXEL_MAGIC << 24) | (r << 16) | (g << 8) | b;
@@ -380,6 +388,7 @@ ImagePutPixel(
unsigned char *dstPtr = ((unsigned char*) image->data)
+ (y * image->bytes_per_line)
+ (((image->xoffset + x) * image->bits_per_pixel) / NBBY);
if (image->bits_per_pixel == 32) {
*((unsigned int*) dstPtr) = pixel;
} else {
@@ -411,7 +420,7 @@ ImagePutPixel(
}
return 0;
}
/*
*----------------------------------------------------------------------
*
@@ -442,6 +451,7 @@ XCreateImage(
int bytes_per_line)
{
XImage *ximage;
display->request++;
ximage = ckalloc(sizeof(XImage));
@@ -452,9 +462,12 @@ XCreateImage(
ximage->format = format;
ximage->data = data;
ximage->obdata = NULL;
/* The default pixelpower is 0. This must be explicitly set to 1 in the
/*
* The default pixelpower is 0. This must be explicitly set to 1 in the
* case of an XImage extracted from a Retina display.
*/
ximage->pixelpower = 0;
if (format == ZPixmap) {
@@ -467,7 +480,10 @@ XCreateImage(
if (bitmap_pad) {
ximage->bitmap_pad = bitmap_pad;
} else {
/* Use 16 byte alignment for best Quartz perfomance */
/*
* Use 16 byte alignment for best Quartz perfomance.
*/
ximage->bitmap_pad = 128;
}
if (bytes_per_line) {
@@ -500,11 +516,11 @@ XCreateImage(
/*
*----------------------------------------------------------------------
*
* TkPutImage --
* TkPutImage, XPutImage --
*
* Copies a rectangular subimage of an XImage into a drawable.
* Currently this is only called by TkImgPhotoDisplay, using
* a Window as the drawable.
* Copies a rectangular subimage of an XImage into a drawable. Currently
* this is only called by TkImgPhotoDisplay, using a Window as the
* drawable.
*
* Results:
* None.
@@ -516,9 +532,7 @@ XCreateImage(
*/
int
TkPutImage(
unsigned long *colors, /* Unused on Macintosh. */
int ncolors, /* Unused on Macintosh. */
XPutImage(
Display* display, /* Display. */
Drawable drawable, /* Drawable to place image on. */
GC gc, /* GC to use. */
@@ -550,13 +564,15 @@ TkPutImage(
}
if (img) {
/* If the XImage has big pixels, the source is rescaled to reflect
/*
* If the XImage has big pixels, the source is rescaled to reflect
* the actual pixel dimensions. This is not currently used, but
* could arise if the image were copied from a retina monitor and
* redrawn on an ordinary monitor.
*/
int pp = image->pixelpower;
bounds = CGRectMake(0, 0, image->width, image->height);
srcRect = CGRectMake(src_x<<pp, src_y<<pp, width<<pp, height<<pp);
dstRect = CGRectMake(dest_x, dest_y, width, height);
@@ -573,6 +589,23 @@ TkPutImage(
TkMacOSXRestoreDrawingContext(&dc);
return Success;
}
int
TkPutImage(
unsigned long *colors, /* Array of pixel values used by this image.
* May be NULL. */
int ncolors, /* Number of colors used, or 0. */
Display *display,
Drawable d, /* Destination drawable. */
GC gc,
XImage *image, /* Source image. */
int src_x, int src_y, /* Offset of subimage. */
int dest_x, int dest_y, /* Position of subimage origin in drawable. */
unsigned int width, unsigned int height)
/* Dimensions of subimage. */
{
return XPutImage(display, d, gc, image, src_x, src_y, dest_x, dest_y, width, height);
}
/*
* Local Variables:

View File

@@ -30,24 +30,10 @@ static char scriptPath[PATH_MAX + 1] = "";
#pragma mark TKApplication(TKInit)
@interface TKApplication(TKKeyboard)
- (void) keyboardChanged: (NSNotification *) notification;
@end
#define TKApplication_NSApplicationDelegate <NSApplicationDelegate>
@interface TKApplication(TKWindowEvent) TKApplication_NSApplicationDelegate
- (void) _setupWindowNotifications;
@end
@interface TKApplication(TKMenus)
- (void) _setupMenus;
@end
@implementation TKApplication
@synthesize poolLock = _poolLock;
@synthesize macMinorVersion = _macMinorVersion;
@synthesize isDrawing = _isDrawing;
@synthesize simulateDrawing = _simulateDrawing;
@end
/*
@@ -59,7 +45,7 @@ static char scriptPath[PATH_MAX + 1] = "";
@implementation TKApplication(TKInit)
- (void) _resetAutoreleasePool
{
if([self poolLock] == 0) {
if ([self poolLock] == 0) {
[_mainPool drain];
_mainPool = [NSAutoreleasePool new];
} else {
@@ -116,7 +102,6 @@ static char scriptPath[PATH_MAX + 1] = "";
_defaultMainMenu = nil;
[self _setupMenus];
/*
* Initialize event processing.
*/
@@ -132,11 +117,27 @@ static char scriptPath[PATH_MAX + 1] = "";
-(void)applicationDidFinishLaunching:(NSNotification *)notification
{
/*
* It is not safe to force activation of the NSApp until this
* method is called. Activating too early can cause the menu
* bar to be unresponsive.
* It is not safe to force activation of the NSApp until this method is
* called. Activating too early can cause the menu bar to be unresponsive.
* The call to activateIgnoringOtherApps was moved here to avoid this.
* However, with the release of macOS 10.15 (Catalina) this was no longer
* sufficient. (See ticket bf93d098d7.) Apparently apps were being
* activated automatically, and this was sometimes being done too early.
* As a workaround we deactivate and then reactivate the app, even though
* Apple says that "Normally, you shouldnt invoke this method".
*/
[NSApp deactivate];
[NSApp activateIgnoringOtherApps: YES];
/*
* Process events to ensure that the root window is fully initialized. See
* ticket 56a1823c73.
*/
[NSApp _lockAutoreleasePool];
while (Tcl_DoOneEvent(TCL_WINDOW_EVENTS| TCL_DONT_WAIT)) {}
[NSApp _unlockAutoreleasePool];
}
- (void) _setup: (Tcl_Interp *) interp
@@ -156,7 +157,7 @@ static char scriptPath[PATH_MAX + 1] = "";
* Record the OS version we are running on.
*/
int minorVersion;
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101000
Gestalt(gestaltSystemVersionMinor, (SInt32*)&minorVersion);
#else
NSOperatingSystemVersion systemVersion;
@@ -166,15 +167,15 @@ static char scriptPath[PATH_MAX + 1] = "";
[NSApp setMacMinorVersion: minorVersion];
/*
* We are not drawing yet.
* We are not drawing right now.
*/
[NSApp setIsDrawing:NO];
[NSApp setSimulateDrawing:NO];
/*
* Be our own delegate.
*/
[self setDelegate:self];
/*
@@ -187,6 +188,7 @@ static char scriptPath[PATH_MAX + 1] = "";
* If no icon has been set from an Info.plist file, use the Wish icon from
* the Tk framework.
*/
NSString *iconFile = [[NSBundle mainBundle] objectForInfoDictionaryKey:
@"CFBundleIconFile"];
if (!iconFile) {
@@ -315,8 +317,8 @@ TkpInit(
}
/*
* Instantiate our NSApplication object. This needs to be
* done before we check whether to open a console window.
* Instantiate our NSApplication object. This needs to be done before
* we check whether to open a console window.
*/
NSAutoreleasePool *pool = [NSAutoreleasePool new];
@@ -330,8 +332,44 @@ TkpInit(
[TKApplication sharedApplication];
[pool drain];
[NSApp _setup:interp];
/*
* WARNING: The finishLaunching method runs asynchronously, apparently
* in a separate thread. This creates a race between the
* initialization of the NSApplication and the initialization of Tk.
* If Tk wins the race bad things happen with the root window (see
* below). If the NSApplication wins then an AppleEvent created during
* launch, e.g. by dropping a file icon on the application icon, will
* be delivered before the procedure meant to to handle the AppleEvent
* has been defined. This is now handled by processing the AppleEvent
* as an idle task. See tkMacOSXHLEvents.c.
*/
[NSApp finishLaunching];
/*
* Create a Tk event source based on the Appkit event queue.
*/
Tk_MacOSXSetupTkNotifier();
/*
* If Tk initialization wins the race, the root window is mapped before
* the NSApplication is initialized. This can cause bad things to
* happen. The root window can open off screen with no way to make it
* appear on screen until the app icon is clicked. This will happen if
* a Tk application opens a modal window in its startup script (see
* ticket 56a1823c73). In other cases, an empty root window can open
* on screen and remain visible for a noticeable amount of time while
* the Tk initialization finishes (see ticket d1989fb7cf). The call
* below forces Tk to block until the Appkit event queue has been
* created. This seems to be sufficient to ensure that the
* NSApplication initialization wins the race, avoiding these bad
* window behaviors.
*/
Tcl_DoOneEvent(TCL_WINDOW_EVENTS | TCL_DONT_WAIT);
/*
* If we don't have a TTY and stdin is a special character file of
* length 0, (e.g. /dev/null, which is what Finder sets when double
@@ -347,8 +385,8 @@ TkpInit(
Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDERR));
/*
* Only show the console if we don't have a startup script
* and tcl_interactive hasn't been set already.
* Only show the console if we don't have a startup script and
* tcl_interactive hasn't been set already.
*/
if (Tcl_GetStartupScript(NULL) == NULL) {
@@ -365,9 +403,14 @@ TkpInit(
}
}
}
/*
* Initialize the NSServices object here. Apple's docs say to do this
* in applicationDidFinishLaunching, but the Tcl interpreter is not
* initialized until this function call.
*/
Tk_MacOSXSetupTkNotifier();
TkMacOSXServices_Init(interp);
}
if (tkLibPath[0] != '\0') {
Tcl_SetVar2(interp, "tk_library", NULL, tkLibPath, TCL_GLOBAL_ONLY);
@@ -382,7 +425,7 @@ TkpInit(
TkMacOSXStandardAboutPanelObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "::tk::mac::iconBitmap",
TkMacOSXIconBitmapObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "::tk::mac::GetAppPath", TkMacOSXGetAppPath, NULL, NULL);
return TCL_OK;
}
@@ -422,7 +465,58 @@ TkpGetAppName(
}
Tcl_DStringAppend(namePtr, name, -1);
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXGetAppPath --
*
* Returns the path of the Wish application bundle.
*
* Results:
* Returns the application path.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int TkMacOSXGetAppPath(
ClientData cd,
Tcl_Interp *ip,
int objc,
Tcl_Obj *const objv[])
{
CFURLRef mainBundleURL = CFBundleCopyBundleURL(CFBundleGetMainBundle());
/*
* Convert the URL reference into a string reference.
*/
CFStringRef appPath = CFURLCopyFileSystemPath(mainBundleURL, kCFURLPOSIXPathStyle);
/*
* Get the system encoding method.
*/
CFStringEncoding encodingMethod = CFStringGetSystemEncoding();
/*
* Convert the string reference into a C string.
*/
char *path = (char *) CFStringGetCStringPtr(appPath, encodingMethod);
Tcl_SetResult(ip, path, NULL);
CFRelease(mainBundleURL);
CFRelease(appPath);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*

View File

@@ -71,6 +71,7 @@ struct TkWindowPrivate {
* gone. */
struct TkWindowPrivate *toplevel;
/* Pointer to the toplevel datastruct. */
CGFloat fillRGBA[4]; /* Background used by the ttk FillElement */
int flags; /* Various state see defines below. */
};
typedef struct TkWindowPrivate MacDrawable;
@@ -86,6 +87,7 @@ typedef struct TkWindowPrivate MacDrawable;
#define TK_IS_PIXMAP 0x10
#define TK_IS_BW_PIXMAP 0x20
#define TK_DO_NOT_DRAW 0x40
#define TTK_HAS_CONTRASTING_BG 0x80
/*
* I am reserving TK_EMBEDDED = 0x100 in the MacDrawable flags
@@ -200,7 +202,8 @@ MODULE_SCOPE void TkpReleaseRegion(TkRegion r);
MODULE_SCOPE void TkpShiftButton(NSButton *button, NSPoint delta);
MODULE_SCOPE Bool TkpAppIsDrawing(void);
MODULE_SCOPE void TkpDisplayWindow(Tk_Window tkwin);
MODULE_SCOPE void TkTestSimulateDrawing(Bool);
MODULE_SCOPE Bool TkTestLogDisplay(void);
MODULE_SCOPE Bool TkMacOSXInDarkMode(Tk_Window tkwin);
/*
* Include the stubbed internal platform-specific API.
@@ -209,3 +212,12 @@ MODULE_SCOPE void TkTestSimulateDrawing(Bool);
#include "tkIntPlatDecls.h"
#endif /* _TKMACINT */
/*
* Local Variables:
* mode: objc
* c-basic-offset: 4
* fill-column: 79
* coding: utf-8
* End:
*/

File diff suppressed because it is too large Load Diff

View File

@@ -180,13 +180,13 @@ InitKeyMaps(void)
for (kPtr = keyArray; kPtr->keycode != 0; kPtr++) {
hPtr = Tcl_CreateHashEntry(&keycodeTable, INT2PTR(kPtr->keycode),
&dummy);
Tcl_SetHashValue(hPtr, kPtr->keysym);
Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keysym));
}
Tcl_InitHashTable(&vkeyTable, TCL_ONE_WORD_KEYS);
for (kPtr = virtualkeyArray; kPtr->keycode != 0; kPtr++) {
hPtr = Tcl_CreateHashEntry(&vkeyTable, INT2PTR(kPtr->keycode),
&dummy);
Tcl_SetHashValue(hPtr, kPtr->keysym);
Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keysym));
}
initialized = 1;
}
@@ -443,8 +443,11 @@ TkpGetString(
* result. */
{
(void) winPtr; /*unused*/
int ch;
Tcl_DStringInit(dsPtr);
return Tcl_DStringAppend(dsPtr, eventPtr->xkey.trans_chars, -1);
return Tcl_DStringAppend(dsPtr, eventPtr->xkey.trans_chars,
TkUtfToUniChar(eventPtr->xkey.trans_chars, &ch));
}
/*
@@ -717,7 +720,7 @@ TkpSetKeycodeAndState(
}
if (keysym <= LATIN1_MAX) {
int done = Tcl_UniCharToUtf(keysym, eventPtr->xkey.trans_chars);
int done = TkUniCharToUtf(keysym, eventPtr->xkey.trans_chars);
eventPtr->xkey.trans_chars[done] = 0;
} else {
@@ -803,7 +806,7 @@ TkpGetKeySym(
/* If nbytes has been set, it's not a function key, but a regular key that
has been translated in tkMacOSXKeyEvent.c; just use that. */
if (eventPtr->xkey.nbytes) {
return eventPtr->xkey.keycode & 0xFFFF;
return eventPtr->xkey.keycode;
}
/*

View File

@@ -110,6 +110,11 @@ static int ModifierCharWidth(Tk_Font tkfont);
#pragma mark TKMenu
/*
* This interface is not declared in tkMacOSXPrivate.h because it requires
* tkMenu.h.
*/
@interface TKMenu(TKMenuPrivate)
- (id) initWithTkMenu: (TkMenu *) tkMenu;
- (TkMenu *) tkMenu;
@@ -117,10 +122,6 @@ static int ModifierCharWidth(Tk_Font tkfont);
- (void) insertItem: (NSMenuItem *) newItem atTkIndex: (NSInteger) index;
@end
#define TKMenu_NSMenuDelegate <NSMenuDelegate>
@interface TKMenu(TKMenuDelegate) TKMenu_NSMenuDelegate
@end
@implementation TKMenu
- (void) setSpecial: (NSUInteger) special
{
@@ -192,10 +193,10 @@ static int ModifierCharWidth(Tk_Font tkfont);
- (void) insertItem: (NSMenuItem *) newItem atIndex: (NSInteger) index
{
if (_tkMenu && index >= 0) {
if ((NSUInteger)index <= _tkOffset) {
if ((NSUInteger) index <= _tkOffset) {
_tkOffset++;
} else {
NSAssert((NSUInteger)index >= _tkItemCount + _tkOffset,
NSAssert((NSUInteger) index >= _tkItemCount + _tkOffset,
@"Cannot insert in the middle of Tk menu");
}
}
@@ -205,9 +206,9 @@ static int ModifierCharWidth(Tk_Font tkfont);
- (void) removeItemAtIndex: (NSInteger) index
{
if (_tkMenu && index >= 0) {
if ((NSUInteger)index < _tkOffset) {
if ((NSUInteger) index < _tkOffset) {
_tkOffset--;
} else if ((NSUInteger)index < _tkItemCount + _tkOffset) {
} else if ((NSUInteger) index < _tkItemCount + _tkOffset) {
_tkItemCount--;
}
}
@@ -220,20 +221,22 @@ static int ModifierCharWidth(Tk_Font tkfont);
action:@selector(tkMenuItemInvoke:) keyEquivalent:@""];
[menuItem setTarget:self];
[menuItem setTag:(NSInteger)mePtr];
[menuItem setTag:(NSInteger) mePtr];
return menuItem;
}
@end
@implementation TKMenu(TKMenuActions)
// target methods
- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
{
return [menuItem isEnabled];
}
// Workaround for bug 3572016; leaves menu items enabled during modal dialog.
/*
* Workaround for bug 3572016; leave menu items enabled during modal dialog.
*/
- (BOOL)worksWhenModal
{
return YES;
@@ -243,22 +246,25 @@ static int ModifierCharWidth(Tk_Font tkfont);
{
/*
* With the delegate matching key equivalents, when a menu action is sent
* in response to a key equivalent, sender is the whole menu and not the
* the specific menu item, use this to ignore key equivalents for our
* in response to a key equivalent, the sender is the whole menu and not the
* specific menu item. We use this to ignore key equivalents for Tk
* menus (as Tk handles them directly via bindings).
*/
if ([sender isKindOfClass:[NSMenuItem class]]) {
NSMenuItem *menuItem = (NSMenuItem *)sender;
TkMenu *menuPtr = (TkMenu *)_tkMenu;
TkMenuEntry *mePtr = (TkMenuEntry *)[menuItem tag];
NSMenuItem *menuItem = (NSMenuItem *) sender;
TkMenu *menuPtr = (TkMenu *) _tkMenu;
TkMenuEntry *mePtr = (TkMenuEntry *) [menuItem tag];
if (menuPtr && mePtr) {
Tcl_Interp *interp = menuPtr->interp;
/*Add time for errors to fire if necessary. This is sub-optimal
*but avoids issues with Tcl/Cocoa event loop integration.
/*
* Add time for errors to fire if necessary. This is sub-optimal
* but avoids issues with Tcl/Cocoa event loop integration.
*/
Tcl_Sleep(100);
//Tcl_Sleep(100);
Tcl_Preserve(interp);
Tcl_Preserve(menuPtr);
@@ -277,40 +283,55 @@ static int ModifierCharWidth(Tk_Font tkfont);
@end
@implementation TKMenu(TKMenuDelegate)
#define keyEquivModifiersMatch(km, m) (( \
((km) & NSCommandKeyMask) != ((m) & NSCommandKeyMask) || \
((km) & NSAlternateKeyMask) != ((m) & NSAlternateKeyMask) || \
((km) & NSControlKeyMask) != ((m) & NSControlKeyMask) || \
(((km) & NSShiftKeyMask) != ((m) & NSShiftKeyMask) && \
((m) & NSFunctionKeyMask))) ? NO : YES)
- (BOOL) menuHasKeyEquivalent: (NSMenu *) menu forEvent: (NSEvent *) event
target: (id *) target action: (SEL *) action
{
/*Use lowercaseString to keep "shift" from firing twice if bound to different procedure.*/
/*
* Use lowercaseString when comparing keyEquivalents since the notion of
* a shifted upper case letter does not make much sense.
*/
NSString *key = [[event charactersIgnoringModifiers] lowercaseString];
NSUInteger modifiers = [event modifierFlags] &
NSDeviceIndependentModifierFlagsMask;
if (modifiers == (NSCommandKeyMask | NSShiftKeyMask) &&
[key compare:@"?"] == NSOrderedSame) {
return NO;
}
/*
* Command-Shift-? has not been allowed as a keyboard equivalent since
* the first aqua port, for some mysterious reason.
*/
// For command key, take input manager's word so things
// like dvorak / qwerty layout work.
if (([event modifierFlags] & NSCommandKeyMask) == NSCommandKeyMask) {
key = [event characters];
return NO;
} else if (modifiers == (NSControlKeyMask | NSShiftKeyMask) &&
[event keyCode] == 48) {
/*
* Starting with OSX 10.12 Control-Tab and Control-Shift-Tab are used
* to select window tabs. But for some even more mysterious reason the
* Control-Shift-Tab event has character 0x19 = NSBackTabCharacter
* rather than 0x09 = NSTabCharacter. At the same time, the
* keyEquivalent must be \0x09 in order for it to be displayed
* correctly in the menu. This makes it impossible for the standard
* "Select Previous Tab" to work correctly, unless we intervene.
*/
key = @"\t";
} else if (([event modifierFlags] & NSCommandKeyMask) == NSCommandKeyMask) {
/*
* If the command modifier is set, use the full character string so
* things like the dvorak / qwerty layout will work.
*/
key = [event characters];
}
NSArray *itemArray = [self itemArray];
for (NSMenuItem *item in itemArray) {
if ([item isEnabled] && [[item keyEquivalent] compare:key] ==
NSOrderedSame) {
if ([item isEnabled] &&
[[item keyEquivalent] compare:key] == NSOrderedSame) {
NSUInteger keyEquivModifiers = [item keyEquivalentModifierMask];
if (keyEquivModifiersMatch(keyEquivModifiers, modifiers)) {
if (keyEquivModifiers == modifiers) {
*target = [item target];
*action = [item action];
return YES;
@@ -367,10 +388,6 @@ static int ModifierCharWidth(Tk_Font tkfont);
#pragma mark TKApplication(TKMenu)
@interface NSApplication(TKMenu)
- (void) setAppleMenu: (NSMenu *) menu;
@end
@implementation TKApplication(TKMenu)
- (void) menuBeginTracking: (NSNotification *) notification
@@ -611,6 +628,10 @@ TkpConfigureMenuEntry(
&imageHeight);
image = TkMacOSXGetNSImageWithBitmap(mePtr->menuPtr->display, bitmap,
gc, imageWidth, imageHeight);
if (gc->foreground == defaultFg) {
// Use a semantic foreground color by default
[image setTemplate:YES];
}
}
[menuItem setImage:image];
if ((!image || mePtr->compound != COMPOUND_NONE) && mePtr->labelPtr &&
@@ -633,7 +654,7 @@ TkpConfigureMenuEntry(
gc->foreground!=defaultFg? gc->foreground:gc->background);
attributes = [[attributes mutableCopy] autorelease];
[(NSMutableDictionary *)attributes setObject:color
[(NSMutableDictionary *) attributes setObject:color
forKey:NSForegroundColorAttributeName];
}
if (attributes) {
@@ -673,21 +694,31 @@ TkpConfigureMenuEntry(
[submenu setTitle:title];
if ([menuItem isEnabled]) {
/* This menuItem might have been previously disabled (XXX:
track this), which would have disabled entries; we must
re-enable the entries here. */
int i = 0;
NSArray *itemArray = [submenu itemArray];
for (NSMenuItem *item in itemArray) {
TkMenuEntry *submePtr = menuRefPtr->menuPtr->entries[i];
/* Work around an apparent bug where itemArray can have
more items than the menu's entries[] array. */
if (i >= menuRefPtr->menuPtr->numEntries) break;
[item setEnabled: !(submePtr->state == ENTRY_DISABLED)];
i++;
}
}
/*
* This menuItem might have been previously disabled (XXX:
* track this), which would have disabled entries; we must
* re-enable the entries here.
*/
int i = 0;
NSArray *itemArray = [submenu itemArray];
for (NSMenuItem *item in itemArray) {
TkMenuEntry *submePtr = menuRefPtr->menuPtr->entries[i];
/*
* Work around an apparent bug where itemArray can have
* more items than the menu's entries[] array.
*/
if (i >= (int) menuRefPtr->menuPtr->numEntries) {
break;
}
[item setEnabled: !(submePtr->state == ENTRY_DISABLED)];
i++;
}
}
}
}
}
@@ -738,10 +769,13 @@ TkpDestroyMenuEntry(
*
* TkpPostMenu --
*
* Posts a menu on the screen
* Posts a menu on the screen. If entry is < 0 then the menu is drawn so
* its top left corner is located at the point with screen coordinates
* (x,y). Otherwise the top left corner of the specified entry is located
* at that point.
*
* Results:
* None.
* Returns a standard Tcl result.
*
* Side effects:
* The menu is posted and handled.
@@ -753,54 +787,174 @@ int
TkpPostMenu(
Tcl_Interp *interp, /* The interpreter this menu lives in */
TkMenu *menuPtr, /* The menu we are posting */
int x, /* The global x-coordinate of the top, left-
* hand corner of where the menu is supposed
* to be posted. */
int y) /* The global y-coordinate */
int x, int y, /* The screen coordinates where the top left
* corner of the menu, or of the specified
* entry, will be located. */
int index)
{
/* Get the object that holds this Tk Window.*/
Tk_Window root;
root = Tk_MainWindow(interp);
if (root == NULL) {
return TCL_ERROR;
}
Drawable d = Tk_WindowId(root);
NSView *rootview = TkMacOSXGetRootControl(d);
NSWindow *win = [rootview window];
int result;
Tk_Window realWin = menuPtr->tkwin;
TkWindow *realWinPtr;
NSView *realWinView;
while (1) {
if (realWin == NULL) {
return TCL_ERROR;
}
/*
* Fix for bug 07cfc9f03e: use the view for the parent real (non-menu)
* toplevel window, rather than always using the root window.
* This allows menus to appear on a separate monitor than the root
* window, and to use the appearance of their parent real window
* rather than the appearance of the root window.
*/
realWinPtr = (TkWindow*) realWin;
realWinView = TkMacOSXDrawableView(realWinPtr->privatePtr);
if (realWinView != nil) {
break;
}
realWin = Tk_Parent(realWin);
}
NSWindow *win = [realWinView window];
NSView *view = [win contentView];
NSMenu *menu = (NSMenu *) menuPtr->platformData;
NSInteger itemIndex = index;
NSInteger numItems = [menu numberOfItems];
NSMenuItem *item = nil;
NSPoint location = NSMakePoint(x, TkMacOSXZeroScreenHeight() - y);
inPostMenu = 1;
result = TkPreprocessMenu(menuPtr);
if (result != TCL_OK) {
inPostMenu = 0;
return result;
}
if (itemIndex >= numItems) {
itemIndex = numItems - 1;
}
if (itemIndex >= 0) {
item = [menu itemAtIndex:itemIndex];
}
int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
NSView *view = [win contentView];
NSRect frame = NSMakeRect(x + 9, tkMacOSXZeroScreenHeight - y - 9, 1, 1);
/*
* The post commands could have deleted the menu, which means we are dead
* and should go away.
*/
frame.origin = [view convertPoint:
[win tkConvertPointFromScreen:frame.origin] fromView:nil];
if (menuPtr->tkwin == NULL) {
return TCL_OK;
}
NSMenu *menu = (NSMenu *) menuPtr->platformData;
NSPopUpButtonCell *popUpButtonCell = [[NSPopUpButtonCell alloc]
initTextCell:@"" pullsDown:NO];
[popUpButtonCell setAltersStateOfSelectedItem:NO];
[popUpButtonCell setMenu:menu];
[popUpButtonCell selectItem:nil];
[popUpButtonCell performClickWithFrame:frame inView:view];
[popUpButtonCell release];
Tcl_SetServiceMode(oldMode);
[menu popUpMenuPositioningItem:item
atLocation:[win tkConvertPointFromScreen:location]
inView:view];
inPostMenu = 0;
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TkpPostTearoffMenu --
*
* Tearoff menus are not supported on the Mac. This placeholder function,
* which is simply a copy of the unix function, posts a completely useless
* window with a black background on the screen. If entry is < 0 then the
* window is positioned so that its top left corner is located at the
* point with screen coordinates (x, y). Otherwise the window position is
* offset so that top left corner of the specified entry would be located
* at that point, if there actually were a menu.
*
* Mac menus steal all mouse or keyboard input from the application until
* the menu is dismissed, with or without a selection, by a mouse or key
* event. Posting a Mac menu in a regression test will cause the test to
* halt waiting for user input. This is why the TkpPostMenu function is
* not being used as the placeholder.
*
* Results:
* None.
*
* Side effects:
* A useless window is posted.
*
*----------------------------------------------------------------------
*/
int
TkpPostTearoffMenu(
Tcl_Interp *interp, /* The interpreter this menu lives in */
TkMenu *menuPtr, /* The menu we are posting */
int x, int y, int index) /* The screen coordinates where the top left
* corner of the menu, or of the specified
* entry, will be located. */
{
int vRootX, vRootY, vRootWidth, vRootHeight;
int result;
if (index >= (int) menuPtr->numEntries) {
index = menuPtr->numEntries - 1;
}
if (index >= 0) {
y -= menuPtr->entries[index]->y;
}
TkActivateMenuEntry(menuPtr, -1);
TkRecomputeMenu(menuPtr);
result = TkPostCommand(menuPtr);
if (result != TCL_OK) {
return result;
}
/*
* The post commands could have deleted the menu, which means we are dead
* and should go away.
*/
if (menuPtr->tkwin == NULL) {
return TCL_OK;
}
/*
* Adjust the position of the menu if necessary to keep it visible on the
* screen. There are two special tricks to make this work right:
*
* 1. If a virtual root window manager is being used then the coordinates
* are in the virtual root window of menuPtr's parent; since the menu
* uses override-redirect mode it will be in the *real* root window for
* the screen, so we have to map the coordinates from the virtual root
* (if any) to the real root. Can't get the virtual root from the menu
* itself (it will never be seen by the wm) so use its parent instead
* (it would be better to have an an option that names a window to use
* for this...).
* 2. The menu may not have been mapped yet, so its current size might be
* the default 1x1. To compute how much space it needs, use its
* requested size, not its actual size.
*/
Tk_GetVRootGeometry(Tk_Parent(menuPtr->tkwin), &vRootX, &vRootY,
&vRootWidth, &vRootHeight);
vRootWidth -= Tk_ReqWidth(menuPtr->tkwin);
if (x > vRootX + vRootWidth) {
x = vRootX + vRootWidth;
}
if (x < vRootX) {
x = vRootX;
}
vRootHeight -= Tk_ReqHeight(menuPtr->tkwin);
if (y > vRootY + vRootHeight) {
y = vRootY + vRootHeight;
}
if (y < vRootY) {
y = vRootY;
}
Tk_MoveToplevelWindow(menuPtr->tkwin, x, y);
if (!Tk_IsMapped(menuPtr->tkwin)) {
Tk_MapWindow(menuPtr->tkwin);
}
TkWmRestackToplevel((TkWindow *) menuPtr->tkwin, Above, NULL);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
@@ -835,12 +989,12 @@ TkpSetWindowMenuBar(
*
* TkpSetMainMenubar --
*
* Puts the menu associated with a window into the menubar. Should only
* be called when the window is in front.
* 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
* 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:
@@ -860,15 +1014,32 @@ TkpSetMainMenubar(
{
static Tcl_Interp *currentInterp = NULL;
TKMenu *menu = nil;
TkWindow *winPtr = (TkWindow *) tkwin;
/*
* We will be called when an embedded window receives an ActivationNotify
* event, but we should not change the menubar in that case.
*/
if (Tk_IsEmbedded(winPtr)) {
return;
}
if (menuName) {
TkWindow *winPtr = (TkWindow *) tkwin;
Tk_Window menubar = NULL;
if (winPtr->wmInfoPtr && winPtr->wmInfoPtr->menuPtr &&
winPtr->wmInfoPtr->menuPtr->masterMenuPtr &&
winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin &&
!strcmp(menuName, Tk_PathName(
winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin))) {
if (winPtr->wmInfoPtr &&
winPtr->wmInfoPtr->menuPtr &&
winPtr->wmInfoPtr->menuPtr->masterMenuPtr) {
menubar = winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin;
}
/*
* Attempt to find the NSMenu directly. If that fails, ask Tk to find
* it.
*/
if (menubar != NULL && strcmp(menuName, Tk_PathName(menubar)) == 0) {
menu = (TKMenu *) winPtr->wmInfoPtr->menuPtr->platformData;
} else {
TkMenuReferences *menuRefPtr = TkFindMenuReferences(interp,
@@ -880,6 +1051,12 @@ TkpSetMainMenubar(
}
}
}
/*
* If we couldn't find a menu, do nothing unless the window belongs to a
* different application. In that case, install the default menubar.
*/
if (menu || interp != currentInterp) {
[NSApp tkSetMainMenu:menu];
}
@@ -892,8 +1069,8 @@ TkpSetMainMenubar(
* CheckForSpecialMenu --
*
* Given a menu, check to see whether or not it is a cascade in a menubar
* with one of the special names .apple, .help or .window If it is, the
* entry that points to this menu will be marked.
* with one of the special names ".apple", ".help" or ".window". If it is,
* the entry that points to this menu will be marked.
*
* Results:
* None.
@@ -1070,26 +1247,32 @@ void
TkpComputeStandardMenuGeometry(
TkMenu *menuPtr) /* Structure describing menu. */
{
NSSize menuSize;
Tk_Font tkfont, menuFont;
Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
int modifierCharWidth, menuModifierCharWidth;
int x, y, modifierWidth, labelWidth, indicatorSpace;
int windowWidth, windowHeight, accelWidth;
int i, j, lastColumnBreak, maxWidth;
int i, maxWidth;
int entryWidth, maxIndicatorSpace, borderWidth, activeBorderWidth;
TkMenuEntry *mePtr, *columnEntryPtr;
TkMenuEntry *mePtr;
int haveAccel = 0;
if (menuPtr->tkwin == NULL) {
/*
* Do nothing if this menu is a clone.
*/
if (menuPtr->tkwin == NULL || menuPtr->masterMenuPtr != menuPtr) {
return;
}
menuSize = [(NSMenu *) menuPtr->platformData size];
Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
&borderWidth);
Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
&activeBorderWidth);
x = y = borderWidth;
windowHeight = maxWidth = lastColumnBreak = 0;
windowHeight = maxWidth = 0;
maxIndicatorSpace = 0;
/*
@@ -1097,16 +1280,16 @@ TkpComputeStandardMenuGeometry(
* want to do it intelligently. We are going to precalculate them and pass
* them down to all of the measuring and drawing routines. We will measure
* the font metrics of the menu once. If an entry does not have its own
* font set, then we give the geometry/drawing routines the menu's font
* and metrics. If an entry has its own font, we will measure that font
* and give all of the geometry/drawing the entry's font and metrics.
* font set, then we give the geometry/drawing routines the menu's font and
* metrics. If an entry has its own font, we will measure that font and
* give all of the geometry/drawing the entry's font and metrics.
*/
menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
Tk_GetFontMetrics(menuFont, &menuMetrics);
menuModifierCharWidth = ModifierCharWidth(menuFont);
for (i = 0; i < menuPtr->numEntries; i++) {
for (i = 0; i < (int) menuPtr->numEntries; i++) {
mePtr = menuPtr->entries[i];
if (mePtr->type == CASCADE_ENTRY || mePtr->accelLength > 0) {
haveAccel = 1;
@@ -1114,8 +1297,11 @@ TkpComputeStandardMenuGeometry(
}
}
for (i = 0; i < menuPtr->numEntries; i++) {
for (i = 0; i < (int) menuPtr->numEntries; i++) {
mePtr = menuPtr->entries[i];
if (mePtr->type == TEAROFF_ENTRY) {
continue;
}
if (mePtr->fontPtr == NULL) {
tkfont = menuFont;
fmPtr = &menuMetrics;
@@ -1126,26 +1312,8 @@ TkpComputeStandardMenuGeometry(
fmPtr = &entryMetrics;
modifierCharWidth = ModifierCharWidth(tkfont);
}
if ((i > 0) && mePtr->columnBreak) {
if (maxIndicatorSpace != 0) {
maxIndicatorSpace += 2;
}
for (j = lastColumnBreak; j < i; j++) {
columnEntryPtr = menuPtr->entries[j];
columnEntryPtr->indicatorSpace = maxIndicatorSpace;
columnEntryPtr->width = maxIndicatorSpace + maxWidth
+ 2 * activeBorderWidth;
columnEntryPtr->x = x;
columnEntryPtr->entryFlags &= ~ENTRY_LAST_COLUMN;
}
x += maxIndicatorSpace + maxWidth + 2 * activeBorderWidth;
maxWidth = maxIndicatorSpace = 0;
lastColumnBreak = i;
y = borderWidth;
}
accelWidth = modifierWidth = indicatorSpace = 0;
if (mePtr->type == SEPARATOR_ENTRY || mePtr->type == TEAROFF_ENTRY) {
if (mePtr->type == SEPARATOR_ENTRY) {
mePtr->height = menuSeparatorHeight;
} else {
/*
@@ -1163,12 +1331,14 @@ TkpComputeStandardMenuGeometry(
if (mePtr->image) {
Tk_SizeOfImage(mePtr->image, &width, &height);
haveImage = 1;
height += 2; /* tweak */
} else if (mePtr->bitmapPtr) {
Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin,
mePtr->bitmapPtr);
Tk_SizeOfBitmap(menuPtr->display, bitmap, &width, &height);
haveImage = 1;
height += 2; /* tweak */
}
if (!haveImage || (mePtr->compound != COMPOUND_NONE)) {
NSAttributedString *attrTitle = [menuItem attributedTitle];
@@ -1180,11 +1350,8 @@ TkpComputeStandardMenuGeometry(
size = [[menuItem title] sizeWithAttributes:
TkMacOSXNSFontAttributesForFont(tkfont)];
}
size.width += menuTextLeadingEdgeMargin +
menuTextTrailingEdgeMargin;
if (size.height < fmPtr->linespace) {
size.height = fmPtr->linespace;
}
size.width += menuTextLeadingEdgeMargin + menuTextTrailingEdgeMargin;
size.height -= 1; /* tweak */
if (haveImage && (mePtr->compound != COMPOUND_NONE)) {
int margin = width + menuIconTrailingEdgeMargin;
@@ -1200,9 +1367,11 @@ TkpComputeStandardMenuGeometry(
height = size.height;
}
}
else {
/* image only. */
}
labelWidth = width + menuItemExtraWidth;
mePtr->height = height + menuItemExtraHeight;
if (mePtr->type == CASCADE_ENTRY) {
modifierWidth = modifierCharWidth;
} else if (mePtr->accelLength == 0) {
@@ -1233,30 +1402,18 @@ TkpComputeStandardMenuGeometry(
if (entryWidth > maxWidth) {
maxWidth = entryWidth;
}
menuPtr->entries[i]->width = entryWidth;
mePtr->height += 2 * activeBorderWidth;
}
mePtr->x = x;
mePtr->y = y;
y += menuPtr->entries[i]->height + borderWidth;
if (y > windowHeight) {
windowHeight = y;
}
}
for (j = lastColumnBreak; j < menuPtr->numEntries; j++) {
columnEntryPtr = menuPtr->entries[j];
columnEntryPtr->indicatorSpace = maxIndicatorSpace;
columnEntryPtr->width = maxIndicatorSpace + maxWidth
+ 2 * activeBorderWidth;
columnEntryPtr->x = x;
columnEntryPtr->entryFlags |= ENTRY_LAST_COLUMN;
}
windowWidth = x + maxIndicatorSpace + maxWidth
+ 2 * activeBorderWidth + borderWidth;
windowHeight += borderWidth;
windowWidth = menuSize.width;
if (windowWidth <= 0) {
windowWidth = 1;
}
windowHeight = menuSize.height;
if (windowHeight <= 0) {
windowHeight = 1;
}
@@ -1290,7 +1447,7 @@ GenerateMenuSelectEvent(
if (menuPtr) {
int index = [menu tkIndexOfItem:menuItem];
if (index < 0 || index >= menuPtr->numEntries ||
if (index < 0 || index >= (int) menuPtr->numEntries ||
(menuPtr->entries[index])->state == ENTRY_DISABLED) {
TkActivateMenuEntry(menuPtr, -1);
} else {
@@ -1369,7 +1526,7 @@ RecursivelyClearActiveMenu(
int i;
TkActivateMenuEntry(menuPtr, -1);
for (i = 0; i < menuPtr->numEntries; i++) {
for (i = 0; i < (int) menuPtr->numEntries; i++) {
TkMenuEntry *mePtr = menuPtr->entries[i];
if (mePtr->type == CASCADE_ENTRY
@@ -1404,7 +1561,10 @@ TkMacOSXClearMenubarActive(void)
if (mainMenu && [mainMenu isKindOfClass:[TKMenu class]]) {
TkMenu *menuPtr = [(TKMenu *) mainMenu tkMenu];
if (menuPtr && menuPtr->numEntries && menuPtr->entries) {
if (menuPtr &&
!(menuPtr->menuFlags & MENU_DELETION_PENDING) &&
menuPtr->numEntries > 0 &&
menuPtr->entries != NULL) {
RecursivelyClearActiveMenu(menuPtr);
}
}
@@ -1464,10 +1624,10 @@ TkpMenuInit(void)
#undef observe
[NSMenuItem setUsesUserKeyEquivalents:NO];
tkColPtr = TkpGetColor(None, DEF_MENU_BG_COLOR);
tkColPtr = TkpGetColor(NULL, DEF_MENU_BG_COLOR);
defaultBg = tkColPtr->color.pixel;
ckfree(tkColPtr);
tkColPtr = TkpGetColor(None, DEF_MENU_FG);
tkColPtr = TkpGetColor(NULL, DEF_MENU_FG);
defaultFg = tkColPtr->color.pixel;
ckfree(tkColPtr);
@@ -1658,7 +1818,7 @@ TkMacOSXPreprocessMenu(void)
* TkMacOSXUseID --
*
* Take the ID out of the available list for new menus. Used by the
* default menu bar's menus so that they do not get created at the tk
* default menu bar's menus so that they do not get created at the Tk
* level. See TkMacOSXGetNewMenuID for more information.
*
* Results:
@@ -1683,8 +1843,7 @@ TkMacOSXUseMenuID(
*
* TkMacOSXDispatchMenuEvent --
*
* Given a menu id and an item, dispatches the command associated with
* it.
* Given a menu id and an item, dispatches the command associated with it.
*
* Results:
* None.
@@ -1734,9 +1893,10 @@ TkMacOSXHandleTearoffMenu(void)
*
* TkMacOSXSetHelpMenuItemCount --
*
* Has to be called after the first call to InsertMenu. Sets up the
* global variable for the number of items in the unmodified help menu.
* NB. Nobody uses this any more, since you can get the number of system
* Has to be called after the first call to InsertMenu. Sets up the global
* variable for the number of items in the unmodified help menu.
*
* NB: Nobody uses this any more, since you can get the number of system
* help items from HMGetHelpMenu trivially. But it is in the stubs
* table...
*

View File

@@ -1,8 +1,8 @@
/*
* tkMacOSXMenubutton.c --
*
* This file implements the Macintosh specific portion of the
* menubutton widget.
* This file implements the Macintosh specific portion of the menubutton
* widget.
*
* Copyright (c) 1996 by Sun Microsystems, Inc.
* Copyright 2001, Apple Computer, Inc.
@@ -32,7 +32,6 @@ typedef struct {
int hasImageOrBitmap;
} DrawParams;
/*
* Declaration of Mac specific button structure.
*/
@@ -47,18 +46,27 @@ typedef struct MacMenuButton {
} MacMenuButton;
/*
* Forward declarations for procedures defined later in this file:
* Forward declarations for static functions 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);
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 void 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
@@ -70,11 +78,45 @@ Tk_ClassProcs tkpMenubuttonClass = {
TkMenuButtonWorldChanged, /* worldChangedProc */
};
/*
* We use Apple's Pop-Up Button widget to represent the Tk Menubutton.
* However, we do not use the NSPopUpButton class for this control. Instead we
* render the Pop-Up Button using the HITheme library. This imposes some
* constraints on what can be done. The HITheme renderer allows only specific
* dimensions for the button.
*
* The HITheme library allows drawing a Pop-Up Button with an arbitrary bounds
* rectangle. However the button is always drawn as a rounded box which is 22
* pixels high. If the bounds rectangle is less than 22 pixels high, the
* button is drawn at the top of the rectangle and the bottom of the button is
* clipped away. So we set a minimum height of 22 pixels for a Menubutton. If
* the bounds rectangle is more than 22 pixels high, then the button is drawn
* centered vertically in the bounds rectangle.
*
* The content rectangle of the button is inset by 14 pixels on the left and 28
* pixels on the right. The rightmost part of the button contains the blue
* double-arrow symbol which is 28 pixels wide.
*
* To maintain compatibility with code that runs on multiple operating systems,
* the width and height of the content rectangle includes the borderWidth, the
* highlightWidth and the padX and padY dimensions of the Menubutton. However,
* to be consistent with the standard Apple appearance, the content is always
* be drawn at the left side of the content rectangle. All of the excess space
* appears on the right side of the content, and the anchor property is
* ignored. The easiest way to comply with Apple's Human Interface Guidelines
* would be to set bd = highlightthickness = padx = 0 and to specify an
* explicit width for the button. Apple also recommends using the same width
* for all Pop-Up Buttons in a given window.
*/
#define LEFT_INSET 8
#define RIGHT_INSET 28
#define MIN_HEIGHT 22
/*
*----------------------------------------------------------------------
*
* TkpCreateMenuButton --
* TkpCreateMenuButton --
*
* Allocate a new TkMenuButton structure.
*
@@ -93,13 +135,11 @@ TkpCreateMenuButton(
{
MacMenuButton *mbPtr = (MacMenuButton *) ckalloc(sizeof(MacMenuButton));
Tk_CreateEventHandler(tkwin, ActivateMask,
MenuButtonEventProc, (ClientData) mbPtr);
Tk_CreateEventHandler(tkwin, ActivateMask, MenuButtonEventProc, mbPtr);
mbPtr->flags = FIRST_DRAW;
mbPtr->btnkind = kThemePopupButton;
bzero(&mbPtr->drawinfo, sizeof(mbPtr->drawinfo));
bzero(&mbPtr->lastdrawinfo, sizeof(mbPtr->lastdrawinfo));
return (TkMenuButton *) mbPtr;
}
@@ -114,8 +154,7 @@ TkpCreateMenuButton(
* None.
*
* Side effects:
* Commands are output to X to display the menubutton in its
* current mode.
* Commands are output to X to display the menubutton in its current mode.
*
*----------------------------------------------------------------------
*/
@@ -124,11 +163,11 @@ void
TkpDisplayMenuButton(
ClientData clientData) /* Information about widget. */
{
MacMenuButton *mbPtr = (MacMenuButton *)clientData;
TkMenuButton *butPtr = (TkMenuButton *) clientData;
Tk_Window tkwin = butPtr->tkwin;
MacMenuButton *mbPtr = clientData;
TkMenuButton *butPtr = clientData;
Tk_Window tkwin = butPtr->tkwin;
Pixmap pixmap;
DrawParams* dpPtr = &mbPtr->drawParams;
DrawParams *dpPtr = &mbPtr->drawParams;
butPtr->flags &= ~REDRAW_PENDING;
if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
@@ -140,22 +179,27 @@ TkpDisplayMenuButton(
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.
* 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. */
/*
* Draw the native portion of the buttons.
*/
TkMacOSXDrawMenuButton(mbPtr, dpPtr->gc, pixmap);
/* Draw highlight border, if needed. */
/*
* 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);
}
if (butPtr->flags & GOT_FOCUS) {
GC gc = Tk_GCForColor(butPtr->highlightColorPtr, pixmap);
TkMacOSXDrawSolidBorder(tkwin, gc, 0, butPtr->highlightWidth);
}
}
}
@@ -164,13 +208,14 @@ TkpDisplayMenuButton(
*
* TkpDestroyMenuButton --
*
* Free data structures associated with the menubutton control.
* Free data structures associated with the menubutton control. This is a
* no-op on the Mac.
*
* Results:
* None.
*
* Side effects:
* Restores the default control state.
* None.
*
*----------------------------------------------------------------------
*/
@@ -204,15 +249,12 @@ TkpComputeMenuButtonGeometry(butPtr)
register TkMenuButton *butPtr; /* Widget record for menu button. */
{
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;
int highlightWidth = butPtr->highlightWidth > 0 ? butPtr->highlightWidth : 0;
/*
* First figure out the size of the contents of the button.
* First compute the size of the contents of the button.
*/
width = 0;
@@ -221,8 +263,6 @@ TkpComputeMenuButtonGeometry(butPtr)
txtHeight = 0;
avgWidth = 0;
TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
if (butPtr->image != NULL) {
Tk_SizeOfImage(butPtr->image, &width, &height);
haveImage = 1;
@@ -231,58 +271,55 @@ TkpComputeMenuButtonGeometry(butPtr)
haveImage = 1;
}
if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
if (butPtr->text && strlen(butPtr->text) > 0) {
haveText = 1;
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);
}
/*
* 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 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) {
switch ((enum compound) butPtr->compound) {
case COMPOUND_TOP:
case COMPOUND_BOTTOM: {
/*
* Image is above or below text
*/
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
*/
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 += 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;}
width = (width > txtWidth ? width : txtWidth);
height = (height > txtHeight ? height : txtHeight);
break;
case COMPOUND_NONE:
break;
}
if (butPtr->width > 0) {
@@ -293,76 +330,29 @@ TkpComputeMenuButtonGeometry(butPtr)
}
} else {
if (haveImage) {
if (haveImage) { /* Image only */
if (butPtr->width > 0) {
width = butPtr->width;
}
if (butPtr->height > 0) {
height = butPtr->height;
}
} else {
} else { /* Text only */
width = txtWidth;
height = txtHeight;
if (butPtr->width > 0) {
width = butPtr->width * avgWidth;
width = butPtr->width * avgWidth + 2*butPtr->padX;
}
if (butPtr->height > 0) {
height = butPtr->height * fm.linespace;
height = butPtr->height * fm.linespace + 2*butPtr->padY;
}
}
}
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;
}
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;
}
if (paddingy > 0) {
height += paddingy;
}
width += butPtr->inset*2;
height += butPtr->inset*2;
butPtr->inset = highlightWidth + butPtr->borderWidth;
width += LEFT_INSET + RIGHT_INSET + 2*butPtr->inset;
height += 2*butPtr->inset;
height = height < MIN_HEIGHT ? MIN_HEIGHT : height;
Tk_GeometryRequest(butPtr->tkwin, width, height);
Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
}
@@ -384,32 +374,24 @@ TkpComputeMenuButtonGeometry(butPtr)
*/
void
DrawMenuButtonImageAndText(
TkMenuButton* butPtr)
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;
MacMenuButton *mbPtr = (MacMenuButton *) butPtr;
Tk_Window tkwin = butPtr->tkwin;
Pixmap pixmap;
int haveImage = 0, haveText = 0;
int imageWidth = 0, imageHeight = 0;
int imageXOffset = 0, imageYOffset = 0;
int textXOffset = 0, textYOffset = 0;
int width = 0, height = 0;
int fullWidth = 0, fullHeight = 0;
if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
return;
}
DrawParams* dpPtr = &mbPtr->drawParams;
pixmap = (Pixmap)Tk_WindowId(tkwin);
DrawParams *dpPtr = &mbPtr->drawParams;
pixmap = (Pixmap) Tk_WindowId(tkwin);
if (butPtr->image != None) {
Tk_SizeOfImage(butPtr->image, &width, &height);
@@ -419,86 +401,80 @@ DrawMenuButtonImageAndText(
haveImage = 1;
}
imageWidth = width;
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 = 0, y = 0;
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;
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
*/
case COMPOUND_TOP:
case COMPOUND_BOTTOM:
/*
* Image is above or below 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
*/
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
*/
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;}
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,
butPtr->padX + butPtr->inset, butPtr->padY + butPtr->inset,
fullWidth, fullHeight, &x, &y);
imageXOffset += x;
imageXOffset = LEFT_INSET;
imageYOffset += y;
textYOffset -= 1;
if (butPtr->image != NULL) {
Tk_RedrawImage(butPtr->image, 0, 0, width,
height, pixmap, imageXOffset, imageYOffset);
Tk_RedrawImage(butPtr->image, 0, 0, width,
height, pixmap, imageXOffset, imageYOffset);
} else {
XSetClipOrigin(butPtr->display, dpPtr->gc,
imageXOffset, imageYOffset);
@@ -512,56 +488,49 @@ DrawMenuButtonImageAndText(
dpPtr->gc, butPtr->textLayout,
x + textXOffset, y + textYOffset, 0, -1);
Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc,
butPtr->textLayout,
x + textXOffset, y + textYOffset,
butPtr->textLayout, x + textXOffset, y + textYOffset,
butPtr->underline);
} else {
int x, y;
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);
imageXOffset = LEFT_INSET;
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);
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 eight pixels to give the menubutton arrows room.*/
int x = 0;
int y;
textXOffset = 8;
textXOffset = LEFT_INSET;
TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
butPtr->textWidth, butPtr->textHeight, &x, &y);
butPtr->textWidth, butPtr->textHeight, &x, &y);
Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc,
butPtr->textLayout, x - textXOffset, y, 0, -1);
butPtr->textLayout, 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.
* This function draws the tk menubutton using Mac controls. In
* addition, this code may apply custom colors passed in the
* TkMenubutton.
*
* Results:
* None.
@@ -571,45 +540,39 @@ DrawMenuButtonImageAndText(
*
*--------------------------------------------------------------
*/
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 */
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;
TkMenuButton *butPtr = (TkMenuButton *) mbPtr;
TkWindow *winPtr = (TkWindow *) butPtr->tkwin;
HIRect cntrRect;
TkMacOSXDrawingContext dc;
DrawParams* dpPtr = &mbPtr->drawParams;
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);
cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff,
Tk_Width(butPtr->tkwin), Tk_Height(butPtr->tkwin));
if (useNewerHITools == 1) {
HIRect contHIRec;
static HIThemeButtonDrawInfo hiinfo;
MenuButtonBackgroundDrawCB((MacMenuButton*) mbPtr, 32, true);
MenuButtonBackgroundDrawCB(mbPtr, 32, true);
if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
return;
}
hiinfo.version = 0;
hiinfo.state = mbPtr->drawinfo.state;
hiinfo.kind = mbPtr->btnkind;
hiinfo.kind = mbPtr->btnkind;
hiinfo.value = mbPtr->drawinfo.value;
hiinfo.adornment = mbPtr->drawinfo.adornment;
hiinfo.animation.time.current = CFAbsoluteTimeGetCurrent();
@@ -617,17 +580,26 @@ TkMacOSXDrawMenuButton(
hiinfo.animation.time.start = hiinfo.animation.time.current;
}
HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec);
/*
* To avoid menubuttons with white text on a white background, we
* always set the state to inactive in Dark Mode. It isn't perfect but
* it is usable. Using a ttk::menubutton would be a better choice,
* however.
*/
if (TkMacOSXInDarkMode(butPtr->tkwin)) {
hiinfo.state = kThemeStateInactive;
}
HIThemeDrawButton(&cntrRect, &hiinfo, dc.context,
kHIThemeOrientationNormal, &contHIRec);
TkMacOSXRestoreDrawingContext(&dc);
MenuButtonContentDrawCB( mbPtr->btnkind, &mbPtr->drawinfo, (MacMenuButton *)mbPtr, 32, true);
MenuButtonContentDrawCB(mbPtr->btnkind, &mbPtr->drawinfo,
mbPtr, 32, true);
} else {
if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
return;
}
TkMacOSXRestoreDrawingContext(&dc);
}
mbPtr->lastdrawinfo = mbPtr->drawinfo;
@@ -638,33 +610,34 @@ TkMacOSXDrawMenuButton(
*
* MenuButtonBackgroundDrawCB --
*
* This function draws the background that
* lies under checkboxes and radiobuttons.
* This function draws the background that lies under checkboxes and
* radiobuttons.
*
* Results:
* None.
* None.
*
* Side effects:
* The background gets updated to the current color.
* 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;
TkMenuButton* butPtr = (TkMenuButton *) ptr;
Tk_Window tkwin = butPtr->tkwin;
Pixmap pixmap;
if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
return;
}
pixmap = (Pixmap)Tk_WindowId(tkwin);
pixmap = (Pixmap) Tk_WindowId(tkwin);
Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
}
/*
@@ -672,16 +645,17 @@ MenuButtonBackgroundDrawCB (
*
* MenuButtonContentDrawCB --
*
* This function draws the label and image for the button.
* This function draws the label and image for the button.
*
* Results:
* None.
* None.
*
* Side effects:
* The content of the button gets updated.
* The content of the button gets updated.
*
*--------------------------------------------------------------
*/
static void
MenuButtonContentDrawCB (
ThemeButtonKind kind,
@@ -690,14 +664,13 @@ MenuButtonContentDrawCB (
SInt16 depth,
Boolean isColorDev)
{
TkMenuButton *butPtr = (TkMenuButton *)ptr;
Tk_Window tkwin = butPtr->tkwin;
TkMenuButton *butPtr = (TkMenuButton *) ptr;
Tk_Window tkwin = butPtr->tkwin;
if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
return;
}
DrawMenuButtonImageAndText( butPtr);
DrawMenuButtonImageAndText(butPtr);
}
/*
@@ -705,8 +678,8 @@ MenuButtonContentDrawCB (
*
* MenuButtonEventProc --
*
* This procedure is invoked by the Tk dispatcher for various
* events on buttons.
* This procedure is invoked by the Tk dispatcher for various events on
* buttons.
*
* Results:
* None.
@@ -722,8 +695,8 @@ MenuButtonEventProc(
ClientData clientData, /* Information about window. */
XEvent *eventPtr) /* Information about event. */
{
TkMenuButton *buttonPtr = (TkMenuButton *) clientData;
MacMenuButton *mbPtr = (MacMenuButton *) clientData;
TkMenuButton *buttonPtr = clientData;
MacMenuButton *mbPtr = clientData;
if (eventPtr->type == ActivateNotify
|| eventPtr->type == DeactivateNotify) {
@@ -747,9 +720,9 @@ MenuButtonEventProc(
*
* TkMacOSXComputeMenuButtonParams --
*
* This procedure computes the various parameters used
* when creating a Carbon Appearance control.
* These are determined by the various tk button parameters
* This procedure computes the various parameters used when creating a
* Carbon Appearance control. These are determined by the various Tk
* button parameters
*
* Results:
* None.
@@ -761,19 +734,18 @@ MenuButtonEventProc(
*/
static void
TkMacOSXComputeMenuButtonParams(TkMenuButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo *drawinfo)
TkMacOSXComputeMenuButtonParams(
TkMenuButton *butPtr,
ThemeButtonKind *btnkind,
HIThemeButtonDrawInfo *drawinfo)
{
MacMenuButton *mbPtr = (MacMenuButton *)butPtr;
MacMenuButton *mbPtr = (MacMenuButton *) butPtr;
if (butPtr->image || butPtr->bitmap) {
if (butPtr->image || butPtr->bitmap || butPtr->text) {
/* TODO: allow for Small and Mini menubuttons. */
*btnkind = kThemePopupButton;
} else {
if (!butPtr->text || !*butPtr->text) {
*btnkind = kThemeArrowButton;
} else {
*btnkind = kThemePopupButton;
}
} else { /* This should never happen. */
*btnkind = kThemeArrowButton;
}
drawinfo->value = kThemeButtonOff;
@@ -812,24 +784,25 @@ TkMacOSXComputeMenuButtonParams(TkMenuButton * butPtr, ThemeButtonKind* btnkind,
*
* TkMacOSXComputeMenuButtonDrawParams --
*
* This procedure computes the various parameters used
* when drawing a button
* These are determined by the various tk button parameters
* This procedure selects an appropriate drawing context for drawing a
* menubutton.
*
* Results:
* 1 if control will be used, 0 otherwise.
* None.
*
* Side effects:
* Sets the button draw parameters
* Sets the button draw parameters.
*
*----------------------------------------------------------------------
*/
static int
TkMacOSXComputeMenuButtonDrawParams(TkMenuButton * butPtr, DrawParams * dpPtr)
static void
TkMacOSXComputeMenuButtonDrawParams(
TkMenuButton *butPtr,
DrawParams *dpPtr)
{
dpPtr->hasImageOrBitmap = ((butPtr->image != NULL)
|| (butPtr->bitmap != None));
dpPtr->hasImageOrBitmap =
((butPtr->image != NULL) || (butPtr->bitmap != None));
dpPtr->border = butPtr->normalBorder;
if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
dpPtr->gc = butPtr->disabledGC;
@@ -839,10 +812,8 @@ TkMacOSXComputeMenuButtonDrawParams(TkMenuButton * butPtr, DrawParams * dpPtr)
} else {
dpPtr->gc = butPtr->normalTextGC;
}
return 1;
}
/*
* Local Variables:
* mode: objc

View File

@@ -17,6 +17,7 @@
static void GenerateEditEvent(const char *name);
static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
#pragma mark TKApplication(TKMenus)
@@ -69,9 +70,8 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
[NSMenuItem itemWithTitle:
[NSString stringWithFormat:@"About %@", aboutName]
action:@selector(orderFrontStandardAboutPanel:)] atIndex:0];
TKMenu *fileMenu = [TKMenu menuWithTitle:@"File" menuItems:
[NSArray arrayWithObjects:
_defaultFileMenuItems =
[[NSArray arrayWithObjects:
[NSMenuItem itemWithTitle:
[NSString stringWithFormat:@"Source%C", 0x2026]
action:@selector(tkSource:)],
@@ -79,7 +79,10 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
action:@selector(tkDemo:)],
[NSMenuItem itemWithTitle:@"Close" action:@selector(performClose:)
target:nil keyEquivalent:@"w"],
nil]];
nil] retain];
_demoMenuItem = [_defaultFileMenuItems objectAtIndex:1];
TKMenu *fileMenu = [TKMenu menuWithTitle:@"File"
menuItems: _defaultFileMenuItems];
TKMenu *editMenu = [TKMenu menuWithTitle:@"Edit" menuItems:
[NSArray arrayWithObjects:
[NSMenuItem itemWithTitle:@"Undo" action:@selector(undo:)
@@ -97,29 +100,56 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
target:nil],
nil]];
_defaultWindowsMenuItems = [[NSArray arrayWithObjects:
[NSMenuItem itemWithTitle:@"Minimize"
action:@selector(performMiniaturize:) target:nil
keyEquivalent:@"m"],
[NSMenuItem itemWithTitle:@"Zoom" action:@selector(performZoom:)
target:nil],
[NSMenuItem separatorItem],
_defaultWindowsMenuItems = [NSArray arrayWithObjects:
[NSMenuItem itemWithTitle:@"Minimize"
action:@selector(performMiniaturize:) target:nil
keyEquivalent:@"m"],
[NSMenuItem itemWithTitle:@"Zoom" action:@selector(performZoom:)
target:nil],
nil];
/*
* On OS X 10.12 we get duplicate tab control items if we create them here.
*/
if ([NSApp macMinorVersion] > 12) {
_defaultWindowsMenuItems = [_defaultWindowsMenuItems
arrayByAddingObjectsFromArray:
[NSArray arrayWithObjects:
[NSMenuItem separatorItem],
[NSMenuItem itemWithTitle:@"Show Previous Tab"
action:@selector(selectPreviousTab:)
target:nil
keyEquivalent:@"\t"
keyEquivalentModifierMask:
NSControlKeyMask|NSShiftKeyMask],
[NSMenuItem itemWithTitle:@"Show Next Tab"
action:@selector(selectNextTab:)
target:nil
keyEquivalent:@"\t"
keyEquivalentModifierMask:NSControlKeyMask],
[NSMenuItem itemWithTitle:@"Move Tab To New Window"
action:@selector(moveTabToNewWindow:)
target:nil],
[NSMenuItem itemWithTitle:@"Merge All Windows"
action:@selector(mergeAllWindows:)
target:nil],
[NSMenuItem separatorItem],
nil]];
}
_defaultWindowsMenuItems = [_defaultWindowsMenuItems arrayByAddingObject:
[NSMenuItem itemWithTitle:@"Bring All to Front"
action:@selector(arrangeInFront:)],
nil] retain];
action:@selector(arrangeInFront:)]];
[_defaultWindowsMenuItems retain];
TKMenu *windowsMenu = [TKMenu menuWithTitle:@"Window" menuItems:
_defaultWindowsMenuItems];
_defaultWindowsMenuItems];
_defaultHelpMenuItems = [[NSArray arrayWithObjects:
[NSMenuItem itemWithTitle:
[NSString stringWithFormat:@"%@ Help", applicationName]
action:@selector(showHelp:) keyEquivalent:@"?"],
nil] retain];
TKMenu *helpMenu = [TKMenu menuWithTitle:@"Help" menuItems:
_defaultHelpMenuItems];
[self setServicesMenu:_servicesMenu];
[self setWindowsMenu:windowsMenu];
_defaultMainMenu = [[TKMenu menuWithTitle:@"" submenus:[NSArray
@@ -138,6 +168,7 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
[_defaultHelpMenuItems release];
[_defaultWindowsMenuItems release];
[_defaultApplicationMenuItems release];
[_defaultFileMenuItems release];
[super dealloc];
}
@@ -146,7 +177,6 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
SEL action = [anItem action];
if (sel_isEqual(action, @selector(preferences:))) {
return (_eventInterp && Tcl_FindCommand(_eventInterp,
"::tk::mac::ShowPreferences", NULL, 0));
} else if (sel_isEqual(action, @selector(tkDemo:))) {
@@ -232,6 +262,7 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
if (path) {
Tcl_IncrRefCount(path);
[_demoMenuItem setHidden:YES];
int code = Tcl_FSEvalFileEx(_eventInterp, path, NULL);
if (code != TCL_OK) {

View File

@@ -24,16 +24,19 @@ typedef struct {
Point global;
Point local;
} MouseEventData;
static Tk_Window captureWinPtr = NULL; /* Current capture window; may be
* NULL. */
static int GenerateButtonEvent(MouseEventData *medPtr);
static unsigned int ButtonModifiers2State(UInt32 buttonState,
UInt32 keyModifiers);
UInt32 keyModifiers);
#pragma mark TKApplication(TKMouseEvent)
enum {
NSWindowWillMoveEventType = 20
};
/*
* In OS X 10.6 an NSEvent of type NSMouseMoved would always have a non-Nil
* window attribute pointing to the active window. As of 10.8 this behavior
@@ -47,14 +50,19 @@ enum {
@implementation TKApplication(TKMouseEvent)
- (NSEvent *) tkProcessMouseEvent: (NSEvent *) theEvent
{
NSWindow *eventWindow = [theEvent window];
NSEventType eventType = [theEvent type];
TkWindow *winPtr = NULL, *grabWinPtr;
Tk_Window tkwin;
NSPoint local, global;
#if 0
NSTrackingArea *trackingArea = nil;
NSInteger eventNumber, clickCount, buttonNumber;
#endif
[NSEvent stopPeriodicEvents];
#ifdef TK_MAC_DEBUG_EVENTS
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent);
#endif
NSWindow* eventWindow = [theEvent window];
NSEventType eventType = [theEvent type];
#if 0
NSTrackingArea *trackingArea = nil;
NSInteger eventNumber, clickCount, buttonNumber;
#endif
switch (eventType) {
case NSMouseEntered:
@@ -73,74 +81,152 @@ enum {
case NSTabletPoint:
case NSTabletProximity:
case NSScrollWheel:
break;
break;
default: /* Unrecognized mouse event. */
return theEvent;
}
/* Remember the window in case we need it next time. */
if (eventWindow && eventWindow != _windowWithMouse) {
if (_windowWithMouse) {
[_windowWithMouse release];
}
_windowWithMouse = eventWindow;
[_windowWithMouse retain];
}
/*
* Compute the mouse position in Tk screen coordinates (global) and in the
* Tk coordinates of its containing Tk Window (local). If a grab is in effect,
* the local coordinates should be relative to the grab window.
*/
/* Create an Xevent to add to the Tk queue. */
NSPoint global, local = [theEvent locationInWindow];
if (eventWindow) { /* local will be in window coordinates. */
if (eventWindow) {
local = [theEvent locationInWindow];
global = [eventWindow tkConvertPointToScreen: local];
tkwin = TkMacOSXGetCapture();
if (tkwin) {
winPtr = (TkWindow *) tkwin;
eventWindow = TkMacOSXDrawableWindow(winPtr->window);
if (eventWindow) {
local = [eventWindow tkConvertPointFromScreen: global];
} else {
return theEvent;
}
}
local.y = [eventWindow frame].size.height - local.y;
global.y = tkMacOSXZeroScreenHeight - global.y;
} else { /* local will be in screen coordinates. */
if (_windowWithMouse ) {
eventWindow = _windowWithMouse;
global = local;
local = [eventWindow tkConvertPointFromScreen: local];
local.y = [eventWindow frame].size.height - local.y;
global.y = tkMacOSXZeroScreenHeight - global.y;
} else { /* We have no window. Use the screen???*/
local.y = tkMacOSXZeroScreenHeight - local.y;
global = local;
global.y = TkMacOSXZeroScreenHeight() - global.y;
} else {
/*
* If the event has no NSWindow, the location is in screen coordinates.
*/
global = [theEvent locationInWindow];
tkwin = TkMacOSXGetCapture();
if (tkwin) {
winPtr = (TkWindow *) tkwin;
eventWindow = TkMacOSXDrawableWindow(winPtr->window);
} else {
eventWindow = [NSApp mainWindow];
}
if (!eventWindow) {
return theEvent;
}
local = [eventWindow tkConvertPointFromScreen: global];
local.y = [eventWindow frame].size.height - local.y;
global.y = TkMacOSXZeroScreenHeight() - global.y;
}
/*
* If we still don't have a window, try using the toplevel that
* manages the NSWindow.
*/
if (!tkwin) {
winPtr = TkMacOSXGetTkWindow(eventWindow);
tkwin = (Tk_Window) winPtr;
}
if (!tkwin) {
/*
* We can't find a window for this event. We have to ignore it.
*/
#ifdef TK_MAC_DEBUG_EVENTS
TkMacOSXDbgMsg("tkwin == NULL");
#endif
return theEvent;
}
/*
* Ignore the event if a local grab is in effect and the Tk event window is
* not in the grabber's subtree.
*/
grabWinPtr = winPtr->dispPtr->grabWinPtr;
if (grabWinPtr && /* There is a grab in effect ... */
!winPtr->dispPtr->grabFlags && /* and it is a local grab ... */
grabWinPtr->mainPtr == winPtr->mainPtr){ /* in the same application. */
Tk_Window tkwin2, tkEventWindow = Tk_CoordsToWindow(global.x, global.y, tkwin);
if (!tkEventWindow) {
return theEvent;
}
for (tkwin2 = tkEventWindow;
!Tk_IsTopLevel(tkwin2);
tkwin2 = Tk_Parent(tkwin2)) {
if (tkwin2 == (Tk_Window) grabWinPtr) {
break;
}
}
if (tkwin2 != (Tk_Window) grabWinPtr) {
return theEvent;
}
}
Window window = TkMacOSXGetXWindow(eventWindow);
Tk_Window tkwin = window ? Tk_IdToWindow(TkGetDisplayList()->display,
window) : NULL;
if (!tkwin) {
tkwin = TkMacOSXGetCapture();
}
if (!tkwin) {
return theEvent; /* Give up. No window for this event. */
/*
* Convert local from NSWindow flipped coordinates to the toplevel's
* coordinates.
*/
if (Tk_IsEmbedded(winPtr)) {
TkWindow *contPtr = TkpGetOtherWindow(winPtr);
if (Tk_IsTopLevel(contPtr)) {
local.x -= contPtr->wmInfoPtr->xInParent;
local.y -= contPtr->wmInfoPtr->yInParent;
} else {
TkWindow *topPtr = TkMacOSXGetHostToplevel(winPtr)->winPtr;
local.x -= (topPtr->wmInfoPtr->xInParent + contPtr->changes.x);
local.y -= (topPtr->wmInfoPtr->yInParent + contPtr->changes.y);
}
} else {
local.x -= winPtr->wmInfoPtr->xInParent;
local.y -= winPtr->wmInfoPtr->yInParent;
}
TkWindow *winPtr = (TkWindow *) tkwin;
local.x -= winPtr->wmInfoPtr->xInParent;
local.y -= winPtr->wmInfoPtr->yInParent;
/*
* Use the toplevel coordinates to find the containing Tk window. Then
* convert local into the coordinates of that window. (The converted
* local coordinates are only needed for scrollwheel events.)
*/
int win_x, win_y;
tkwin = Tk_TopCoordsToWindow(tkwin, local.x, local.y,
&win_x, &win_y);
tkwin = Tk_TopCoordsToWindow(tkwin, local.x, local.y, &win_x, &win_y);
local.x = win_x;
local.y = win_y;
/*
* Generate an XEvent for this mouse event.
*/
unsigned int state = 0;
NSInteger button = [theEvent buttonNumber];
int button = [theEvent buttonNumber] + Button1;
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;
} else if (button < 5) {
state |= (buttons & 0x1F) * Button1Mask;
} else if (button <= Button5) {
switch (eventType) {
case NSLeftMouseDown:
case NSRightMouseDown:
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSOtherMouseDown:
state |= 1 << (button + 8);
state |= TkGetButtonMask(button);
break;
default:
break;
@@ -172,11 +258,22 @@ enum {
}
if (eventType != NSScrollWheel) {
/*
* For normal mouse events, Tk_UpdatePointer will send the XEvent.
*/
#ifdef TK_MAC_DEBUG_EVENTS
TKLog(@"UpdatePointer %p x %f.0 y %f.0 %d", tkwin, global.x, global.y, state);
TKLog(@"UpdatePointer %p x %f.0 y %f.0 %d",
tkwin, global.x, global.y, state);
#endif
Tk_UpdatePointer(tkwin, global.x, global.y, state);
} else { /* handle scroll wheel event */
} else {
/*
* For scroll wheel events we need to send the XEvent here.
*/
CGFloat delta;
int coarseDelta;
XEvent xEvent;
@@ -193,7 +290,7 @@ enum {
delta = [theEvent deltaY];
if (delta != 0.0) {
coarseDelta = (delta > -1.0 && delta < 1.0) ?
(signbit(delta) ? -1 : 1) : lround(delta);
(signbit(delta) ? -1 : 1) : lround(delta);
xEvent.xbutton.state = state;
xEvent.xkey.keycode = coarseDelta;
xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
@@ -202,7 +299,7 @@ enum {
delta = [theEvent deltaX];
if (delta != 0.0) {
coarseDelta = (delta > -1.0 && delta < 1.0) ?
(signbit(delta) ? -1 : 1) : lround(delta);
(signbit(delta) ? -1 : 1) : lround(delta);
xEvent.xbutton.state = state | ShiftMask;
xEvent.xkey.keycode = coarseDelta;
xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
@@ -299,10 +396,10 @@ ButtonModifiers2State(
unsigned int state;
/*
* Tk supports at most 5 buttons.
* Tk on OSX supports at most 5 buttons.
*/
state = (buttonState & ((1<<5) - 1)) << 8;
state = (buttonState & 0x1F) * Button1Mask;
if (keyModifiers & alphaLock) {
state |= LockMask;
@@ -385,7 +482,7 @@ XQueryPointer(
}
if (getGlobal) {
*root_x_return = global.x;
*root_y_return = tkMacOSXZeroScreenHeight - global.y;
*root_y_return = TkMacOSXZeroScreenHeight() - global.y;
}
}
if (mask_return) {
@@ -437,7 +534,7 @@ TkGenerateButtonEventForXPointer(
* TkGenerateButtonEvent --
*
* Given a global x & y position and the button key status this procedure
* generates the appropiate X button event. It also handles the state
* generates the appropriate X button event. It also handles the state
* changes needed to implement implicit grabs.
*
* Results:
@@ -469,7 +566,7 @@ TkGenerateButtonEvent(
med.local = med.global;
if (win) {
NSPoint local = NSMakePoint(x, tkMacOSXZeroScreenHeight - y);
NSPoint local = NSMakePoint(x, TkMacOSXZeroScreenHeight() - y);
local = [win tkConvertPointFromScreen:local];
local.y = [win frame].size.height - local.y;
@@ -478,7 +575,7 @@ TkGenerateButtonEvent(
local.y -= macWin->winPtr->wmInfoPtr->yInParent;
}
med.local.h = local.x;
med.local.v = tkMacOSXZeroScreenHeight - local.y;
med.local.v = TkMacOSXZeroScreenHeight() - local.y;
}
return GenerateButtonEvent(&med);
@@ -511,6 +608,7 @@ GenerateButtonEvent(
TkDisplay *dispPtr;
#if UNUSED
/*
* ButtonDown events will always occur in the front window. ButtonUp
* events, however, may occur anywhere on the screen. ButtonUp events
@@ -543,32 +641,95 @@ TkpWarpPointer(
TkDisplay *dispPtr)
{
CGPoint pt;
UInt32 buttonState;
NSPoint loc;
int wNum;
if (dispPtr->warpWindow) {
int x, y;
TkWindow *winPtr = (TkWindow *) dispPtr->warpWindow;
TkWindow *topPtr = winPtr->privatePtr->toplevel->winPtr;
NSWindow *w = TkMacOSXDrawableWindow(winPtr->window);
wNum = [w windowNumber];
Tk_GetRootCoords(dispPtr->warpWindow, &x, &y);
pt.x = x + dispPtr->warpX;
pt.y = y + dispPtr->warpY;
loc.x = dispPtr->warpX;
loc.y = Tk_Height(topPtr) - dispPtr->warpY;
} else {
pt.x = dispPtr->warpX;
wNum = 0;
pt.x = loc.x = dispPtr->warpX;
pt.y = dispPtr->warpY;
loc.y = TkMacOSXZeroScreenHeight() - pt.y;
}
/*
* Tell the OSX core to generate the events to make it happen.
* Generate an NSEvent of type NSMouseMoved.
*
* It is not clear why this is necessary. For example, calling
* event generate $w <Motion> -warp 1 -x $X -y $Y
* will cause two <Motion> events to be added to the Tcl queue.
*/
buttonState = [NSEvent pressedMouseButtons];
CGEventType type = kCGEventMouseMoved;
CGEventRef theEvent = CGEventCreateMouseEvent(NULL,
type,
pt,
buttonState);
CGWarpMouseCursorPosition(pt);
CGEventPost(kCGHIDEventTap, theEvent);
CFRelease(theEvent);
NSEvent *warpEvent = [NSEvent mouseEventWithType:NSMouseMoved
location:loc
modifierFlags:0
timestamp:GetCurrentEventTime()
windowNumber:wNum
context:nil
eventNumber:0
clickCount:1
pressure:0.0];
[NSApp postEvent:warpEvent atStart:NO];
}
/*
*----------------------------------------------------------------------
*
* TkpSetCapture --
*
* This function captures the mouse so that all future events will be
* reported to this window, even if the mouse is outside the window. If
* the specified window is NULL, then the mouse is released.
*
* Results:
* None.
*
* Side effects:
* Sets the capture flag and captures the mouse.
*
*----------------------------------------------------------------------
*/
void
TkpSetCapture(
TkWindow *winPtr) /* Capture window, or NULL. */
{
while (winPtr && !Tk_IsTopLevel(winPtr)) {
winPtr = winPtr->parentPtr;
}
[NSEvent stopPeriodicEvents];
captureWinPtr = (Tk_Window) winPtr;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXGetCapture --
*
* Results:
* Returns the current grab window
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
Tk_Window
TkMacOSXGetCapture(void)
{
return captureWinPtr;
}
/*

View File

@@ -33,7 +33,7 @@ static void TkMacOSXEventsSetupProc(ClientData clientData, int flags);
static void TkMacOSXEventsCheckProc(ClientData clientData, int flags);
#ifdef TK_MAC_DEBUG_EVENTS
static char* Tk_EventName[39] = {
static const char *Tk_EventName[39] = {
"",
"",
"KeyPress", /*2*/
@@ -84,7 +84,7 @@ InspectQueueRestrictProc(
const char *name;
long serial = ve->serial;
long time = eventPtr->xkey.time;
if (eventPtr->type == VirtualEvent) {
name = ve->name;
} else {
@@ -113,11 +113,6 @@ void DebugPrintQueue(void)
#pragma mark TKApplication(TKNotify)
@interface NSApplication(TKNotify)
/* We need to declare this hidden method. */
- (void) _modalSession: (NSModalSession) session sendEvent: (NSEvent *) event;
@end
@implementation TKApplication(TKNotify)
/*
* Earlier versions of Tk would override nextEventMatchingMask here, adding a
@@ -140,14 +135,16 @@ void DebugPrintQueue(void)
*/
/*
* Call super then check the pasteboard.
* Since the contentView is the first responder for a Tk Window, it is
* responsible for sending events up the responder chain. We also check the
* pasteboard here.
*/
- (void) sendEvent: (NSEvent *) theEvent
{
[super sendEvent:theEvent];
[NSApp tkCheckPasteboard];
#ifdef TK_MAC_DEBUG_EVENTS
fprintf(stderr, "Sending event of type %d\n", (int)[theEvent type]);
fprintf(stderr, "Sending event of type %d\n", (int)[theEvent type]);
DebugPrintQueue();
#endif
}
@@ -193,8 +190,8 @@ GetRunLoopMode(NSModalSession modalSession)
*
* Tk_MacOSXSetupTkNotifier --
*
* This procedure is called during Tk initialization to create
* the event source for TkAqua events.
* This procedure is called during Tk initialization to create the event
* source for TkAqua events.
*
* Results:
* None.
@@ -227,8 +224,7 @@ Tk_MacOSXSetupTkNotifier(void)
"first [load] of TkAqua has to occur in the main thread!");
}
Tcl_CreateEventSource(TkMacOSXEventsSetupProc,
TkMacOSXEventsCheckProc,
NULL);
TkMacOSXEventsCheckProc, NULL);
TkCreateExitHandler(TkMacOSXNotifyExitHandler, NULL);
Tcl_SetServiceMode(TCL_SERVICE_ALL);
TclMacOSXNotifierAddRunLoopMode(NSEventTrackingRunLoopMode);
@@ -261,8 +257,7 @@ TkMacOSXNotifyExitHandler(
TSD_INIT();
Tcl_DeleteEventSource(TkMacOSXEventsSetupProc,
TkMacOSXEventsCheckProc,
NULL);
TkMacOSXEventsCheckProc, NULL);
tsdPtr->initialized = 0;
}
@@ -271,19 +266,19 @@ TkMacOSXNotifyExitHandler(
*
* TkMacOSXEventsSetupProc --
*
* 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.
* 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 NSEvents are queued, then the maximum block time will be set
* to 0 to ensure that control returns immediately to Tcl.
* If NSEvents are queued, then the maximum block time will be set to 0 to
* ensure that control returns immediately to Tcl.
*
*----------------------------------------------------------------------
*/
@@ -293,20 +288,43 @@ TkMacOSXEventsSetupProc(
ClientData clientData,
int flags)
{
static Bool havePeriodicEvents = NO;
NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode];
/* runloopMode will be nil if we are in a Tcl event loop. */
/*
* runloopMode will be nil if we are in a Tcl event loop.
*/
if (flags & TCL_WINDOW_EVENTS && !runloopMode) {
static const Tcl_Time zeroBlockTime = { 0, 0 };
[NSApp _resetAutoreleasePool];
/* 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];
/*
* 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) {
if (currentEvent.type > 0) {
Tcl_SetMaxBlockTime(&zeroBlockTime);
[NSEvent stopPeriodicEvents];
havePeriodicEvents = NO;
}
} else if (!havePeriodicEvents){
/*
* When the user is not generating events we schedule a "hearbeat"
* event to fire every 0.1 seconds. This helps to make the vwait
* command more responsive when there is no user input, e.g. when
* running the test suite.
*/
havePeriodicEvents = YES;
[NSEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.1];
}
}
}
@@ -316,15 +334,15 @@ TkMacOSXEventsSetupProc(
*
* TkMacOSXEventsCheckProc --
*
* This procedure loops through all NSEvents waiting in the
* TKApplication event queue, generating X events from them.
* This procedure loops through all NSEvents waiting in the TKApplication
* event queue, generating X events from them.
*
* Results:
* None.
*
* Side effects:
* NSevents are used to generate X events, which are added to the
* Tcl event queue.
* NSevents are used to generate X events, which are added to the Tcl
* event queue.
*
*----------------------------------------------------------------------
*/
@@ -334,38 +352,52 @@ TkMacOSXEventsCheckProc(
int flags)
{
NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode];
/* runloopMode will be nil if we are in a Tcl event loop. */
/*
* runloopMode will be nil if we are in a Tcl event loop.
*/
if (flags & TCL_WINDOW_EVENTS && !runloopMode) {
NSEvent *currentEvent = nil;
NSEvent *testEvent = nil;
NSModalSession modalSession;
/* It is possible for the SetupProc to be called before this function
/*
* It is possible for the SetupProc to be called before this function
* returns. This happens, for example, when we process an event which
* opens a modal window. To prevent premature release of our
* application-wide autorelease pool by a nested call to the SetupProc,
* we must lock it here.
*/
[NSApp _lockAutoreleasePool];
do {
modalSession = TkMacOSXGetModalSession();
testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(modalSession)
dequeue:NO];
/* We must not steal any events during LiveResize. */
testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(modalSession)
dequeue:NO];
/*
* We must not steal any events during LiveResize.
*/
if (testEvent && [[testEvent window] inLiveResize]) {
break;
}
currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(modalSession)
dequeue:YES];
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(modalSession)
dequeue:YES];
if (currentEvent) {
/* Generate Xevents. */
/*
* Generate Xevents.
*/
int oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
NSEvent *processedEvent = [NSApp tkProcessEvent:currentEvent];
Tcl_SetServiceMode(oldServiceMode);
if (processedEvent) { /* Should always be non-NULL. */
if (processedEvent) {
#ifdef TK_MAC_DEBUG_EVENTS
TKLog(@" event: %@", currentEvent);
#endif
@@ -379,11 +411,14 @@ TkMacOSXEventsCheckProc(
break;
}
} while (1);
/* Now we can unlock the pool. */
/*
* Now we can unlock the pool.
*/
[NSApp _unlockAutoreleasePool];
}
}
/*
* Local Variables:

View File

@@ -23,6 +23,7 @@
#include <math.h>
#include <pwd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <sys/file.h>
@@ -110,12 +111,19 @@
* no-op functions on the Macintosh.
*/
#define XFlush(display)
#define XFree(data) {if ((data) != NULL) ckfree(data);}
#define XGrabServer(display)
#define XNoOp(display) {display->request++;}
#define XUngrabServer(display)
#define XSynchronize(display, bool) {display->request++;}
#undef XFlush
#define XFlush(display) (0)
#undef XFree
#define XFree(data) (((data) != NULL) ? (ckfree(data),0) : 0)
#undef XGrabServer
#define XGrabServer(display) (0)
#undef XNoOp
#define XNoOp(display) (display->request++,0)
#undef XUngrabServer
#define XUngrabServer(display) (0)
#undef XSynchronize
#define XSynchronize(display, onoff) (display->request++,NULL)
#undef XVisualIDFromVisual
#define XVisualIDFromVisual(visual) (visual->visualid)
/*
@@ -128,15 +136,15 @@
#define TkpSync(display)
/*
* The following macro returns the pixel value that corresponds to the
* RGB values in the given XColor structure.
* TkMacOSXGetCapture is a legacy function used on the Mac. When fixing
* [943d5ebe51], TkpGetCapture was added to the Windows port. Both
* are actually the same feature and should bear the same name. However,
* in order to avoid potential backwards incompatibilities, renaming
* TkMacOSXGetCapture into TkpGetCapture in *PlatDecls.h shall not be
* done in a patch release, therefore use a define here.
*/
#define PIXEL_MAGIC ((unsigned char) 0x69)
#define TkpGetPixel(p) ((((((PIXEL_MAGIC << 8) \
| (((p)->red >> 8) & 0xff)) << 8) \
| (((p)->green >> 8) & 0xff)) << 8) \
| (((p)->blue >> 8) & 0xff))
#define TkpGetCapture TkMacOSXGetCapture
/*
* This macro stores a representation of the window handle in a string.
@@ -159,19 +167,20 @@
*/
#define TRANSPARENT_PIXEL 30
#define HIGHLIGHT_PIXEL 31
#define HIGHLIGHT_SECONDARY_PIXEL 32
#define HIGHLIGHT_TEXT_PIXEL 33
#define HIGHLIGHT_ALTERNATE_PIXEL 34
#define CONTROL_TEXT_PIXEL 35
#define CONTROL_BODY_PIXEL 37
#define CONTROL_FRAME_PIXEL 39
#define WINDOW_BODY_PIXEL 41
#define MENU_ACTIVE_PIXEL 43
#define MENU_ACTIVE_TEXT_PIXEL 45
#define MENU_BACKGROUND_PIXEL 47
#define MENU_DISABLED_PIXEL 49
#define MENU_TEXT_PIXEL 51
#define APPEARANCE_PIXEL 52
#define PIXEL_MAGIC ((unsigned char) 0x69)
/*
* The following macro returns the pixel value that corresponds to the
* 16-bit RGB values in the given XColor structure.
* The format is: (PIXEL_MAGIC <<< 24) | (R << 16) | (G << 8) | B
* where each of R, G and B is the high order byte of a 16-bit component.
*/
#define TkpGetPixel(p) ((((((PIXEL_MAGIC << 8) \
| (((p)->red >> 8) & 0xff)) << 8) \
| (((p)->green >> 8) & 0xff)) << 8) \
| (((p)->blue >> 8) & 0xff))
#endif /* _TKMACPORT */

View File

@@ -137,8 +137,6 @@ typedef struct TkMacOSXDrawingContext {
* Variables internal to TkAqua.
*/
MODULE_SCOPE CGFloat tkMacOSXZeroScreenHeight;
MODULE_SCOPE CGFloat tkMacOSXZeroScreenTop;
MODULE_SCOPE long tkMacOSXMacOSXVersion;
/*
@@ -177,6 +175,8 @@ MODULE_SCOPE OSStatus TkMacOSHIShapeUnion(HIShapeRef inShape1,
MODULE_SCOPE void * TkMacOSXGetNamedSymbol(const char *module,
const char *symbol);
MODULE_SCOPE void TkMacOSXDisplayChanged(Display *display);
MODULE_SCOPE CGFloat TkMacOSXZeroScreenHeight();
MODULE_SCOPE CGFloat TkMacOSXZeroScreenTop();
MODULE_SCOPE int TkMacOSXUseAntialiasedText(Tcl_Interp *interp,
int enable);
MODULE_SCOPE int TkMacOSXInitCGDrawing(Tcl_Interp *interp, int enable,
@@ -233,6 +233,16 @@ MODULE_SCOPE int TkMacOSXStandardAboutPanelObjCmd(ClientData clientData,
MODULE_SCOPE int TkMacOSXIconBitmapObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE void TkMacOSXDrawSolidBorder(Tk_Window tkwin, GC gc,
int inset, int thickness);
MODULE_SCOPE int TkMacOSXServices_Init(Tcl_Interp *interp);
MODULE_SCOPE int TkMacOSXRegisterServiceWidgetObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE NSString* TclUniToNSString(const char *source, int numBytes);
MODULE_SCOPE int TclUniAtIndex(NSString *string, int index, char *uni,
unsigned int *code);
MODULE_SCOPE char* NSStringToTclUni(NSString *string, int *numBytes);
#pragma mark Private Objective-C Classes
@@ -250,28 +260,29 @@ VISIBILITY_HIDDEN
- (BOOL)isSpecial:(NSUInteger)special;
@end
@interface TKMenu(TKMenuDelegate) <NSMenuDelegate>
@end
VISIBILITY_HIDDEN
@interface TKApplication : NSApplication {
@private
Tcl_Interp *_eventInterp;
NSMenu *_servicesMenu;
TKMenu *_defaultMainMenu, *_defaultApplicationMenu;
NSMenuItem *_demoMenuItem;
NSArray *_defaultApplicationMenuItems, *_defaultWindowsMenuItems;
NSArray *_defaultHelpMenuItems;
NSWindow *_windowWithMouse;
NSArray *_defaultHelpMenuItems, *_defaultFileMenuItems;
NSAutoreleasePool *_mainPool;
#ifdef __i386__
/* The Objective C runtime used on i386 requires this. */
int _poolLock;
int _macMinorVersion;
Bool _isDrawing;
Bool _simulateDrawing;
#endif
}
@property int poolLock;
@property int macMinorVersion;
@property Bool isDrawing;
@property Bool simulateDrawing;
@end
@interface TKApplication(TKInit)
@@ -280,6 +291,24 @@ VISIBILITY_HIDDEN
- (void)_lockAutoreleasePool;
- (void)_unlockAutoreleasePool;
@end
@interface TKApplication(TKKeyboard)
- (void) keyboardChanged: (NSNotification *) notification;
@end
@interface TKApplication(TKWindowEvent) <NSApplicationDelegate>
- (void) _setupWindowNotifications;
@end
@interface TKApplication(TKDialog) <NSOpenSavePanelDelegate>
@end
@interface TKApplication(TKMenu)
- (void)tkSetMainMenu:(TKMenu *)menu;
@end
@interface TKApplication(TKMenus)
- (void) _setupMenus;
@end
@interface NSApplication(TKNotify)
/* We need to declare this hidden method. */
- (void) _modalSession: (NSModalSession) session sendEvent: (NSEvent *) event;
@end
@interface TKApplication(TKEvent)
- (NSEvent *)tkProcessEvent:(NSEvent *)theEvent;
@end
@@ -289,9 +318,6 @@ VISIBILITY_HIDDEN
@interface TKApplication(TKKeyEvent)
- (NSEvent *)tkProcessKeyEvent:(NSEvent *)theEvent;
@end
@interface TKApplication(TKMenu)
- (void)tkSetMainMenu:(TKMenu *)menu;
@end
@interface TKApplication(TKClipboard)
- (void)tkProvidePasteboard:(TkDisplay *)dispPtr;
- (void)tkCheckPasteboard;
@@ -313,18 +339,23 @@ VISIBILITY_HIDDEN
withReplyEvent: (NSAppleEventDescriptor *)replyEvent;
- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent;
- (void)handleURLEvent: (NSAppleEventDescriptor*)event
withReplyEvent: (NSAppleEventDescriptor*)replyEvent;
@end
VISIBILITY_HIDDEN
@interface TKContentView : NSView <NSTextInput> {
/*
* Subclass TKContentView from NSTextInputClient to enable composition and
* input from the Character Palette.
*/
@interface TKContentView : NSView <NSTextInputClient>
{
@private
/*Remove private API calls.*/
#if 0
id _savedSubviews;
BOOL _subviewsSetAside;
#endif
NSString *privateWorkingText;
Bool _needsRedisplay;
}
@property Bool needsRedisplay;
@end
@interface TKContentView(TKKeyEvent)
@@ -332,22 +363,27 @@ VISIBILITY_HIDDEN
@end
@interface TKContentView(TKWindowEvent)
- (void) drawRect: (NSRect) rect;
- (void) generateExposeEvents: (HIShapeRef) shape;
- (void) generateExposeEvents: (HIShapeRef) shape;
- (void) tkToolbarButton: (id) sender;
- (BOOL) isOpaque;
- (BOOL) wantsDefaultClipping;
- (BOOL) acceptsFirstResponder;
- (void) keyDown: (NSEvent *) theEvent;
@end
@interface NSWindow(TKWm)
- (NSPoint) tkConvertPointToScreen:(NSPoint)point;
- (NSPoint) tkConvertPointFromScreen:(NSPoint)point;
@end
VISIBILITY_HIDDEN
@interface TKWindow : NSWindow
@end
@interface NSWindow(TKWm)
- (NSPoint) tkConvertPointToScreen:(NSPoint)point;
- (NSPoint) tkConvertPointFromScreen:(NSPoint)point;
@interface TKWindow(TKWm)
- (void) tkLayoutChanged;
@end
@interface NSDrawerWindow : NSWindow
{
id _i1, _i2;
}
@end
#pragma mark NSMenu & NSMenuItem Utilities
@@ -378,4 +414,34 @@ VISIBILITY_HIDDEN
keyEquivalentModifierMask:(NSUInteger)keyEquivalentModifierMask;
@end
@interface NSColorPanel(TKDialog)
- (void) _setUseModalAppearance: (BOOL) flag;
@end
@interface NSFont(TKFont)
- (NSFont *) bestMatchingFontForCharacters: (const UTF16Char *) characters
length: (NSUInteger) length attributes: (NSDictionary *) attributes
actualCoveredLength: (NSUInteger *) coveredLength;
@end
/*
* This method of NSApplication is not declared in NSApplication.h so we
* declare it here to be a method of the TKMenu category.
*/
@interface NSApplication(TKMenu)
- (void) setAppleMenu: (NSMenu *) menu;
@end
#endif /* _TKMACPRIV */
int TkMacOSXGetAppPath(ClientData cd, Tcl_Interp *ip, int objc, Tcl_Obj *const objv[]);
/*
* Local Variables:
* mode: objc
* c-basic-offset: 4
* fill-column: 79
* coding: utf-8
* End:
*/

View File

@@ -54,13 +54,14 @@ TkCreateRegion(void)
*----------------------------------------------------------------------
*/
void
int
TkDestroyRegion(
TkRegion r)
{
if (r) {
CFRelease(r);
}
return Success;
}
/*
@@ -80,7 +81,7 @@ TkDestroyRegion(
*----------------------------------------------------------------------
*/
void
int
TkIntersectRegion(
TkRegion sra,
TkRegion srb,
@@ -88,6 +89,7 @@ TkIntersectRegion(
{
ChkErr(HIShapeIntersect, (HIShapeRef) sra, (HIShapeRef) srb,
(HIMutableShapeRef) dr_return);
return Success;
}
/*
@@ -107,7 +109,7 @@ TkIntersectRegion(
*----------------------------------------------------------------------
*/
void
int
TkSubtractRegion(
TkRegion sra,
TkRegion srb,
@@ -115,6 +117,7 @@ TkSubtractRegion(
{
ChkErr(HIShapeDifference, (HIShapeRef) sra, (HIShapeRef) srb,
(HIMutableShapeRef) dr_return);
return Success;
}
/*
@@ -134,7 +137,7 @@ TkSubtractRegion(
*----------------------------------------------------------------------
*/
void
int
TkUnionRectWithRegion(
XRectangle* rectangle,
TkRegion src_region,
@@ -153,6 +156,7 @@ TkUnionRectWithRegion(
(HIMutableShapeRef) dest_region_return);
CFRelease(rectRgn);
}
return Success;
}
/*
@@ -187,8 +191,8 @@ TkMacOSXIsEmptyRegion(
* Xwindow documentation for more details.
*
* Results:
* Returns RectanglePart or RectangleOut. Note that this is not a
* complete implementation since it doesn't test for RectangleIn.
* Returns RectanglePart or RectangleOut. Note that this is not a complete
* implementation since it doesn't test for RectangleIn.
*
* Side effects:
* None.
@@ -204,13 +208,13 @@ TkRectInRegion(
unsigned int width,
unsigned int height)
{
if ( TkMacOSXIsEmptyRegion(region) ) {
return RectangleOut;
}
else {
if (TkMacOSXIsEmptyRegion(region)) {
return RectangleOut;
} else {
const CGRect r = CGRectMake(x, y, width, height);
return HIShapeIntersectsRect((HIShapeRef) region, &r) ?
RectanglePart : RectangleOut;
RectanglePart : RectangleOut;
}
}
@@ -231,10 +235,10 @@ TkRectInRegion(
*----------------------------------------------------------------------
*/
void
int
TkClipBox(
TkRegion r,
XRectangle* rect_return)
XRectangle *rect_return)
{
CGRect rect;
@@ -243,6 +247,7 @@ TkClipBox(
rect_return->y = rect.origin.y;
rect_return->width = rect.size.width;
rect_return->height = rect.size.height;
return Success;
}
/*

View File

@@ -51,10 +51,10 @@ static ControlActionUPP scaleActionProc = NULL; /* Pointer to func. */
* Forward declarations for procedures defined later in this file:
*/
static void MacScaleEventProc(ClientData clientData, XEvent *eventPtr);
static pascal void ScaleActionProc(ControlRef theControl,
ControlPartCode partCode);
static void MacScaleEventProc(ClientData clientData,
XEvent *eventPtr);
static pascal void ScaleActionProc(ControlRef theControl,
ControlPartCode partCode);
/*
*----------------------------------------------------------------------
@@ -84,7 +84,7 @@ TkpCreateScale(
}
Tk_CreateEventHandler(tkwin, ButtonPressMask,
MacScaleEventProc, (ClientData) macScalePtr);
MacScaleEventProc, macScalePtr);
return (TkScale *) macScalePtr;
}
@@ -125,8 +125,8 @@ TkpDestroyScale(
*
* TkpDisplayScale --
*
* This procedure is invoked as an idle handler to redisplay
* the contents of a scale widget.
* This procedure is invoked as an idle handler to redisplay the contents
* of a scale widget.
*
* Results:
* None.
@@ -141,12 +141,12 @@ void
TkpDisplayScale(
ClientData clientData) /* Widget record for scale. */
{
TkScale *scalePtr = (TkScale *) clientData;
TkScale *scalePtr = clientData;
Tk_Window tkwin = scalePtr->tkwin;
Tcl_Interp *interp = scalePtr->interp;
int result;
char string[TCL_DOUBLE_SPACE];
MacScale *macScalePtr = (MacScale *) clientData;
MacScale *macScalePtr = clientData;
Rect r;
WindowRef windowRef;
CGrafPtr destPort, savePort;
@@ -168,9 +168,9 @@ TkpDisplayScale(
* Invoke the scale's command if needed.
*/
Tcl_Preserve((ClientData) scalePtr);
Tcl_Preserve(scalePtr);
if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) {
Tcl_Preserve((ClientData) interp);
Tcl_Preserve(interp);
if (snprintf(string, TCL_DOUBLE_SPACE, scalePtr->format,
scalePtr->value) < 0) {
string[TCL_DOUBLE_SPACE - 1] = '\0';
@@ -185,19 +185,18 @@ TkpDisplayScale(
Tcl_AddErrorInfo(interp, "\n (command executed by scale)");
Tcl_BackgroundException(interp, result);
}
Tcl_Release((ClientData) interp);
Tcl_Release(interp);
}
scalePtr->flags &= ~INVOKE_COMMAND;
if (scalePtr->flags & SCALE_DELETED) {
Tcl_Release((ClientData) scalePtr);
Tcl_Release(scalePtr);
return;
}
Tcl_Release((ClientData) scalePtr);
Tcl_Release(scalePtr);
/*
* Now handle the part of redisplay that is the same for
* horizontal and vertical scales: border and traversal
* highlight.
* Now handle the part of redisplay that is the same for horizontal and
* vertical scales: border and traversal highlight.
*/
if (scalePtr->highlightWidth != 0) {
@@ -229,7 +228,7 @@ TkpDisplayScale(
#define MAC_OSX_SCROLL_WIDTH 10
if (scalePtr->orient == ORIENT_HORIZONTAL) {
int offset = (Tk_Height(tkwin) - MAC_OSX_SCROLL_WIDTH)/2;
int offset = (Tk_Height(tkwin) - MAC_OSX_SCROLL_WIDTH) / 2;
if (offset < 0) {
offset = 0;
@@ -240,7 +239,7 @@ TkpDisplayScale(
r.right = macDraw->xOff+Tk_Width(tkwin) - scalePtr->inset;
r.bottom = macDraw->yOff + offset + MAC_OSX_SCROLL_WIDTH/2;
} else {
int offset = (Tk_Width(tkwin) - MAC_OSX_SCROLL_WIDTH)/2;
int offset = (Tk_Width(tkwin) - MAC_OSX_SCROLL_WIDTH) / 2;
if (offset < 0) {
offset = 0;
@@ -249,7 +248,7 @@ TkpDisplayScale(
r.left = macDraw->xOff + offset;
r.top = macDraw->yOff + scalePtr->inset;
r.right = macDraw->xOff + offset + MAC_OSX_SCROLL_WIDTH/2;
r.bottom = macDraw->yOff+Tk_Height(tkwin) - scalePtr->inset;
r.bottom = macDraw->yOff + Tk_Height(tkwin) - scalePtr->inset;
}
if (macScalePtr->scaleHandle == NULL) {
@@ -273,7 +272,7 @@ TkpDisplayScale(
CreateSliderControl(windowRef, &r, initialValue, minValue, maxValue,
kControlSliderPointsDownOrRight, numTicks, 1, scaleActionProc,
&(macScalePtr->scaleHandle));
&macScalePtr->scaleHandle);
SetControlReference(macScalePtr->scaleHandle, (UInt32) scalePtr);
if (IsWindowActive(windowRef)) {
@@ -290,8 +289,8 @@ TkpDisplayScale(
* Finally draw the control.
*/
SetControlVisibility(macScalePtr->scaleHandle,true,true);
HiliteControl(macScalePtr->scaleHandle,0);
SetControlVisibility(macScalePtr->scaleHandle, true, true);
HiliteControl(macScalePtr->scaleHandle, 0);
Draw1Control(macScalePtr->scaleHandle);
if (portChanged) {
@@ -306,13 +305,12 @@ done:
*
* TkpScaleElement --
*
* Determine which part of a scale widget lies under a given
* point.
* Determine which part of a scale widget lies under a given point.
*
* Results:
* The return value is either TROUGH1, SLIDER, TROUGH2, or
* OTHER, depending on which of the scale's active elements
* (if any) is under the point at (x,y).
* The return value is either TROUGH1, SLIDER, TROUGH2, or OTHER,
* depending on which of the scale's active elements (if any) is under the
* point at (x,y).
*
* Side effects:
* None.
@@ -357,22 +355,22 @@ TkpScaleElement(
#endif
switch (part) {
case inSlider:
return SLIDER;
case inInc:
if (scalePtr->orient == ORIENT_VERTICAL) {
return TROUGH1;
} else {
return TROUGH2;
}
case inDecr:
if (scalePtr->orient == ORIENT_VERTICAL) {
return TROUGH2;
} else {
return TROUGH1;
}
default:
return OTHER;
case inSlider:
return SLIDER;
case inInc:
if (scalePtr->orient == ORIENT_VERTICAL) {
return TROUGH1;
} else {
return TROUGH2;
}
case inDecr:
if (scalePtr->orient == ORIENT_VERTICAL) {
return TROUGH2;
} else {
return TROUGH1;
}
default:
return OTHER;
}
}
@@ -381,15 +379,15 @@ TkpScaleElement(
*
* MacScaleEventProc --
*
* This procedure is invoked by the Tk dispatcher for
* ButtonPress events on scales.
* This procedure is invoked by the Tk dispatcher for ButtonPress events
* on scales.
*
* Results:
* None.
*
* Side effects:
* When the window gets deleted, internal structures get
* cleaned up. When it gets exposed, it is redisplayed.
* When the window gets deleted, internal structures get cleaned up. When
* it gets exposed, it is redisplayed.
*
*--------------------------------------------------------------
*/
@@ -411,9 +409,9 @@ MacScaleEventProc(
#endif
/*
* To call Macintosh control routines we must have the port
* set to the window containing the control. We will then test
* which part of the control was hit and act accordingly.
* To call Macintosh control routines we must have the port set to the
* window containing the control. We will then test which part of the
* control was hit and act accordingly.
*/
destPort = TkMacOSXGetDrawablePort(Tk_WindowId(macScalePtr->info.tkwin));
@@ -461,8 +459,8 @@ MacScaleEventProc(
* ScaleActionProc --
*
* Callback procedure used by the Macintosh toolbox call
* HandleControlClick. This call will update the display
* while the scrollbar is being manipulated by the user.
* HandleControlClick. This call will update the display while the
* scrollbar is being manipulated by the user.
*
* Results:
* None.
@@ -486,9 +484,9 @@ ScaleActionProc(
#endif
value = GetControlValue(theControl);
TkScaleSetValue(scalePtr, value, 1, 1);
Tcl_Preserve((ClientData) scalePtr);
Tcl_Preserve(scalePtr);
TkMacOSXRunTclEventLoop();
Tcl_Release((ClientData) scalePtr);
Tcl_Release(scalePtr);
}
#endif

View File

@@ -8,7 +8,8 @@
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
* Copyright (c) 2015 Kevin Walzer/WordTech Commununications LLC.
* Copyright (c) 2018 Marc Culler
* Copyright (c) 2018-2019 Marc Culler
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
@@ -17,28 +18,29 @@
#include "tkScrollbar.h"
#include "tkMacOSXPrivate.h"
#define MIN_SCROLLBAR_VALUE 0
/*
* Minimum slider length, in pixels (designed to make sure that the slider is
* always easy to grab with the mouse).
*/
#define MIN_SLIDER_LENGTH 5
#define MIN_SLIDER_LENGTH 18
#define MIN_GAP 4
/*
* Borrowed from ttkMacOSXTheme.c to provide appropriate scaling.
*/
/*Borrowed from ttkMacOSXTheme.c to provide appropriate scaling.*/
#ifdef __LP64__
#define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum))
#define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum))
#else
#define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum))
#define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum))
#endif /* __LP64__ */
/*
* Apple reversed the scroll direction with the release of OSX 10.7 Lion.
*/
#define SNOW_LEOPARD_STYLE (NSAppKitVersionNumber < 1138)
#define SNOW_LEOPARD_STYLE (NSAppKitVersionNumber < 1138)
/*
* Declaration of an extended scrollbar structure with Mac specific additions.
@@ -48,9 +50,9 @@ typedef struct MacScrollbar {
TkScrollbar information; /* Generic scrollbar info. */
GC troughGC; /* For drawing trough. */
GC copyGC; /* Used for copying from pixmap onto screen. */
Bool buttonDown; /* Is the mouse button down? */
Bool buttonDown; /* Is the mouse button down? */
Bool mouseOver; /* Is the pointer over the scrollbar. */
HIThemeTrackDrawInfo info; /* Controls how the scrollbar is drawn. */
HIThemeTrackDrawInfo info; /* Controls how the scrollbar is drawn. */
} MacScrollbar;
/* Used to initialize a MacScrollbar's info field. */
@@ -69,33 +71,36 @@ HIThemeTrackDrawInfo defaultInfo = {
const Tk_ClassProcs tkpScrollbarProcs = {
sizeof(Tk_ClassProcs), /* size */
NULL, /* worldChangedProc */
NULL, /* createProc */
NULL /* modalProc */
NULL, /* worldChangedProc */
NULL, /* createProc */
NULL /* modalProc */
};
/*
* Information on scrollbar layout, metrics, and draw info.
*/
/* Information on scrollbar layout, metrics, and draw info.*/
typedef struct ScrollbarMetrics {
SInt32 width, minThumbHeight;
int minHeight, topArrowHeight, bottomArrowHeight;
NSControlSize controlSize;
} ScrollbarMetrics;
static ScrollbarMetrics metrics = {
15, 54, 26, 14, 14, kControlSizeNormal /* kThemeScrollBarMedium */
/* kThemeScrollBarMedium */
15, MIN_SLIDER_LENGTH, 26, 14, 14, kControlSizeNormal
};
/*
* Declarations of static functions defined later in this file:
*/
static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr);
static int ScrollbarEvent(TkScrollbar *scrollPtr, XEvent *eventPtr);
static void UpdateControlValues(TkScrollbar *scrollPtr);
static void ScrollbarEventProc(ClientData clientData,
XEvent *eventPtr);
static int ScrollbarEvent(TkScrollbar *scrollPtr,
XEvent *eventPtr);
static void UpdateControlValues(TkScrollbar *scrollPtr);
/*
*----------------------------------------------------------------------
*
@@ -114,26 +119,25 @@ static void UpdateControlValues(TkScrollbar *scrollPtr);
TkScrollbar *
TkpCreateScrollbar(
Tk_Window tkwin)
Tk_Window tkwin)
{
MacScrollbar *scrollPtr = ckalloc(sizeof(MacScrollbar));
MacScrollbar *scrollPtr = (MacScrollbar *)ckalloc(sizeof(MacScrollbar));
scrollPtr->troughGC = None;
scrollPtr->copyGC = None;
scrollPtr->troughGC = NULL;
scrollPtr->copyGC = NULL;
scrollPtr->info = defaultInfo;
scrollPtr->buttonDown = false;
Tk_CreateEventHandler(tkwin,
ExposureMask |
StructureNotifyMask |
FocusChangeMask |
ButtonPressMask |
ButtonReleaseMask |
EnterWindowMask |
LeaveWindowMask |
VisibilityChangeMask,
ScrollbarEventProc, scrollPtr);
ExposureMask |
StructureNotifyMask |
FocusChangeMask |
ButtonPressMask |
ButtonReleaseMask |
EnterWindowMask |
LeaveWindowMask |
VisibilityChangeMask,
ScrollbarEventProc, scrollPtr);
return (TkScrollbar *) scrollPtr;
}
@@ -144,8 +148,8 @@ TkpCreateScrollbar(
* 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.
@@ -156,11 +160,93 @@ TkpCreateScrollbar(
*--------------------------------------------------------------
*/
#if MAC_OS_X_VERSION_MAX_ALLOWED > 1080
/*
* This stand-alone drawing function is used on macOS 10.9 and newer because
* the HIToolbox does not draw the scrollbar thumb at the expected size on
* those systems. The thumb is drawn too large, causing a mouse click on the
* thumb to be interpreted as a mouse click in the trough.
*/
static void drawMacScrollbar(
TkScrollbar *scrollPtr,
MacScrollbar *msPtr,
CGContextRef context)
{
MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin);
NSView *view = TkMacOSXDrawableView(macWin);
CGPathRef path;
CGPoint inner[2], outer[2], thumbOrigin;
CGSize thumbSize;
CGRect troughBounds = msPtr->info.bounds;
troughBounds.origin.y = [view bounds].size.height -
(troughBounds.origin.y + troughBounds.size.height);
if (scrollPtr->vertical) {
thumbOrigin.x = troughBounds.origin.x + MIN_GAP;
thumbOrigin.y = troughBounds.origin.y + scrollPtr->sliderFirst;
thumbSize.width = troughBounds.size.width - 2*MIN_GAP + 1;
thumbSize.height = scrollPtr->sliderLast - scrollPtr->sliderFirst;
inner[0] = troughBounds.origin;
inner[1] = CGPointMake(inner[0].x,
inner[0].y + troughBounds.size.height);
outer[0] = CGPointMake(inner[0].x + troughBounds.size.width - 1,
inner[0].y);
outer[1] = CGPointMake(outer[0].x, inner[1].y);
} else {
thumbOrigin.x = troughBounds.origin.x + scrollPtr->sliderFirst;
thumbOrigin.y = troughBounds.origin.y + MIN_GAP;
thumbSize.width = scrollPtr->sliderLast - scrollPtr->sliderFirst;
thumbSize.height = troughBounds.size.height - 2*MIN_GAP + 1;
inner[0] = troughBounds.origin;
inner[1] = CGPointMake(inner[0].x + troughBounds.size.width,
inner[0].y + 1);
outer[0] = CGPointMake(inner[0].x,
inner[0].y + troughBounds.size.height);
outer[1] = CGPointMake(inner[1].x, outer[0].y);
}
CGContextSetShouldAntialias(context, false);
CGContextSetGrayFillColor(context, 250.0 / 255, 1.0);
CGContextFillRect(context, troughBounds);
CGContextSetGrayStrokeColor(context, 232.0 / 255, 1.0);
CGContextStrokeLineSegments(context, inner, 2);
CGContextSetGrayStrokeColor(context, 238.0 / 255, 1.0);
CGContextStrokeLineSegments(context, outer, 2);
/*
* Do not display the thumb unless scrolling is possible, in accordance
* with macOS behavior.
*
* Native scrollbars and Ttk scrollbars are always 15 pixels wide, but we
* allow Tk scrollbars to have any width, even if it looks bad. To prevent
* sporadic assertion errors when drawing skinny thumbs we must make sure
* the radius is at most half the width.
*/
if (scrollPtr->firstFraction > 0.0 || scrollPtr->lastFraction < 1.0) {
CGRect thumbBounds = {thumbOrigin, thumbSize};
int width = scrollPtr->vertical ? thumbSize.width : thumbSize.height;
int radius = width >= 8 ? 4 : width >> 1;
path = CGPathCreateWithRoundedRect(thumbBounds, radius, radius, NULL);
CGContextBeginPath(context);
CGContextAddPath(context, path);
if (msPtr->info.trackInfo.scrollbar.pressState != 0) {
CGContextSetGrayFillColor(context, 133.0 / 255, 1.0);
} else {
CGContextSetGrayFillColor(context, 200.0 / 255, 1.0);
}
CGContextSetShouldAntialias(context, true);
CGContextFillPath(context);
CFRelease(path);
}
}
#endif
void
TkpDisplayScrollbar(
ClientData clientData) /* Information about window. */
ClientData clientData) /* Information about window. */
{
register TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
register TkScrollbar *scrollPtr = clientData;
MacScrollbar *msPtr = (MacScrollbar *) scrollPtr;
register Tk_Window tkwin = scrollPtr->tkwin;
TkWindow *winPtr = (TkWindow *) tkwin;
@@ -169,23 +255,35 @@ TkpDisplayScrollbar(
scrollPtr->flags &= ~REDRAW_PENDING;
if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
return;
return;
}
MacDrawable *macWin = (MacDrawable *) winPtr->window;
MacDrawable *macWin = (MacDrawable *) winPtr->window;
NSView *view = TkMacOSXDrawableView(macWin);
if (!view ||
macWin->flags & TK_DO_NOT_DRAW ||
!TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
return;
if ((view == NULL)
|| (macWin->flags & TK_DO_NOT_DRAW)
|| !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
return;
}
/*
* Transform NSView coordinates to CoreGraphics coordinates.
*/
CGFloat viewHeight = [view bounds].size.height;
CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
.ty = viewHeight};
CGAffineTransform t = {
.a = 1, .b = 0,
.c = 0, .d = -1,
.tx = 0, .ty = viewHeight
};
CGContextConcatCTM(dc.context, t);
/*Draw a 3D rectangle to provide a base for the native scrollbar.*/
/*
* Draw a 3D rectangle to provide a base for the native scrollbar.
*/
if (scrollPtr->highlightWidth != 0) {
GC fgGC, bgGC;
@@ -196,32 +294,46 @@ TkpDisplayScrollbar(
fgGC = bgGC;
}
TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth,
(Pixmap) macWin);
(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);
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);
scrollPtr->inset, scrollPtr->inset,
Tk_Width(tkwin) - 2*scrollPtr->inset,
Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT);
/*
* Update values and then draw the native scrollbar over the rectangle.
*/
/* Update values and then draw the native scrollbar over the rectangle.*/
UpdateControlValues(scrollPtr);
if (SNOW_LEOPARD_STYLE) {
HIThemeDrawTrack (&(msPtr->info), 0, dc.context, kHIThemeOrientationInverted);
HIThemeDrawTrack(&msPtr->info, 0, dc.context,
kHIThemeOrientationInverted);
} else if ([NSApp macMinorVersion] <= 8) {
HIThemeDrawTrack(&msPtr->info, 0, dc.context,
kHIThemeOrientationNormal);
} else {
HIThemeDrawTrack (&(msPtr->info), 0, dc.context, kHIThemeOrientationNormal);
#if MAC_OS_X_VERSION_MAX_ALLOWED > 1080
/*
* Switch back to NSView coordinates and draw a modern scrollbar.
*/
CGContextConcatCTM(dc.context, t);
drawMacScrollbar(scrollPtr, msPtr, dc.context);
#endif
}
TkMacOSXRestoreDrawingContext(&dc);
scrollPtr->flags &= ~REDRAW_PENDING;
}
/*
*----------------------------------------------------------------------
*
@@ -240,65 +352,63 @@ TkpDisplayScrollbar(
*----------------------------------------------------------------------
*/
extern void
TkpComputeScrollbarGeometry(
register TkScrollbar *scrollPtr)
/* Scrollbar whose geometry may have
* changed. */
/* Scrollbar whose geometry may have
* changed. */
{
/*
* The code below is borrowed from tkUnixScrlbr.c but has been adjusted to
* account for some differences between macOS and X11. The Unix scrollbar
* has an arrow button on each end. On macOS 10.6 (Snow Leopard) the
* scrollbars by default have both arrow buttons at the bottom or right.
* (There is a preferences setting to use the Unix layout, but we are not
* supporting that!) On more recent versions of macOS there are no arrow
* buttons at all. The case of no arrow buttons can be handled as a special
* case of having both buttons at the end, but where scrollPtr->arrowLength
* happens to be zero. To adjust for having both arrows at the same end we
* shift the scrollbar up by the arrowLength.
*/
/*
* The code below is borrowed from tkUnixScrlbr.c but has been adjusted to
* account for some differences between macOS and X11. The Unix scrollbar
* has an arrow button on each end. On macOS 10.6 (Snow Leopard) the
* scrollbars by default have both arrow buttons at the bottom or right.
* (There is a preferences setting to use the Unix layout, but we are not
* supporting that!) On more recent versions of macOS there are no arrow
* buttons at all. The case of no arrow buttons can be handled as a special
* case of having both buttons at the end, but where scrollPtr->arrowLength
* happens to be zero. To adjust for having both arrows at the same end we
* shift the scrollbar up by the arrowLength.
*/
int fieldLength;
if (scrollPtr->highlightWidth < 0) {
scrollPtr->highlightWidth = 0;
scrollPtr->highlightWidth = 0;
}
scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
if ([NSApp macMinorVersion] == 6) {
scrollPtr->arrowLength = scrollPtr->width;
scrollPtr->arrowLength = scrollPtr->width;
} else {
scrollPtr->arrowLength = 0;
scrollPtr->arrowLength = 0;
}
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 it has at least a minimal size and so there
* is a small gap on either end which can be used to scroll by one page.
*/
if (scrollPtr->sliderFirst > fieldLength - MIN_SLIDER_LENGTH) {
scrollPtr->sliderFirst = fieldLength - MIN_SLIDER_LENGTH;
if (scrollPtr->sliderFirst < MIN_GAP) {
scrollPtr->sliderFirst = MIN_GAP;
scrollPtr->sliderLast += MIN_GAP;
}
if (scrollPtr->sliderFirst < 0) {
scrollPtr->sliderFirst = 0;
if (scrollPtr->sliderLast > fieldLength - MIN_GAP) {
scrollPtr->sliderLast = fieldLength - MIN_GAP;
scrollPtr->sliderFirst -= MIN_GAP;
}
if (scrollPtr->sliderFirst > fieldLength - MIN_SLIDER_LENGTH) {
scrollPtr->sliderFirst = fieldLength - MIN_SLIDER_LENGTH;
}
if (scrollPtr->sliderLast < scrollPtr->sliderFirst + MIN_SLIDER_LENGTH) {
scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH;
}
if (scrollPtr->sliderLast > fieldLength) {
scrollPtr->sliderLast = fieldLength;
scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH;
}
scrollPtr->sliderFirst += -scrollPtr->arrowLength + scrollPtr->inset;
scrollPtr->sliderLast += scrollPtr->inset;
@@ -310,20 +420,20 @@ TkpComputeScrollbarGeometry(
* be redisplayed.
*/
if (scrollPtr->vertical) {
Tk_GeometryRequest(scrollPtr->tkwin,
scrollPtr->width + 2*scrollPtr->inset,
2*(scrollPtr->arrowLength + scrollPtr->borderWidth
+ scrollPtr->inset) + metrics.minThumbHeight);
if (scrollPtr->vertical) {
Tk_GeometryRequest(scrollPtr->tkwin,
scrollPtr->width + 2*scrollPtr->inset,
2*(scrollPtr->arrowLength + scrollPtr->borderWidth
+ scrollPtr->inset) + metrics.minThumbHeight);
} else {
Tk_GeometryRequest(scrollPtr->tkwin,
2*(scrollPtr->arrowLength + scrollPtr->borderWidth
+ scrollPtr->inset) + metrics.minThumbHeight,
scrollPtr->width + 2*scrollPtr->inset);
Tk_GeometryRequest(scrollPtr->tkwin,
2*(scrollPtr->arrowLength + scrollPtr->borderWidth
+ scrollPtr->inset) + metrics.minThumbHeight,
scrollPtr->width + 2*scrollPtr->inset);
}
Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset);
}
/*
*----------------------------------------------------------------------
*
@@ -342,9 +452,9 @@ TkpComputeScrollbarGeometry(
void
TkpDestroyScrollbar(
TkScrollbar *scrollPtr)
TkScrollbar *scrollPtr)
{
MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr;
MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
if (macScrollPtr->troughGC != None) {
Tk_FreeGC(scrollPtr->display, macScrollPtr->troughGC);
@@ -353,15 +463,15 @@ TkpDestroyScrollbar(
Tk_FreeGC(scrollPtr->display, macScrollPtr->copyGC);
}
}
/*
*----------------------------------------------------------------------
*
* TkpConfigureScrollbar --
*
* This procedure is called after the generic code has finished
* processing configuration options, in order to configure platform
* specific options. There are no such option on the Mac, however.
* This procedure is called after the generic code has finished processing
* configuration options, in order to configure platform specific options.
* There are no such option on the Mac, however.
*
* Results:
* None.
@@ -374,11 +484,11 @@ TkpDestroyScrollbar(
void
TkpConfigureScrollbar(
register TkScrollbar *scrollPtr)
register TkScrollbar *scrollPtr)
{
/* empty */
}
/*
*--------------------------------------------------------------
*
@@ -403,29 +513,28 @@ TkpScrollbarPosition(
/* Scrollbar widget record. */
int x, int y) /* Coordinates within scrollPtr's window. */
{
/*
* The code below is borrowed from tkUnixScrlbr.c and needs no adjustment
* since it does not involve the arrow buttons.
*/
/*
* The code below is borrowed from tkUnixScrlbr.c and needs no adjustment
* since it does not involve the arrow buttons.
*/
int length, width, tmp;
register const int inset = scrollPtr->inset;
if (scrollPtr->vertical) {
length = Tk_Height(scrollPtr->tkwin);
width = Tk_Width(scrollPtr->tkwin);
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);
tmp = x;
x = y;
y = tmp;
length = Tk_Width(scrollPtr->tkwin);
width = Tk_Height(scrollPtr->tkwin);
}
if (x < inset || x >= width - inset ||
y < inset || y >= length - inset) {
return OUTSIDE;
y < inset || y >= length - inset) {
return OUTSIDE;
}
/*
@@ -436,31 +545,34 @@ TkpScrollbarPosition(
*/
if (y < scrollPtr->sliderFirst + scrollPtr->arrowLength) {
return TOP_GAP;
}
if (y < scrollPtr->sliderLast) {
return SLIDER;
}
if (y < length - (2*scrollPtr->arrowLength + inset)) {
return BOTTOM_GAP;
}
/* On systems newer than 10.6 we have already returned. */
if (y < length - (scrollPtr->arrowLength + inset)) {
return TOP_ARROW;
}
return BOTTOM_ARROW;
}
return TOP_GAP;
}
if (y < scrollPtr->sliderLast) {
return SLIDER;
}
if (y < length - (2*scrollPtr->arrowLength + inset)) {
return BOTTOM_GAP;
}
/*
* On systems newer than 10.6 we have already returned.
*/
if (y < length - (scrollPtr->arrowLength + inset)) {
return TOP_ARROW;
}
return BOTTOM_ARROW;
}
/*
*--------------------------------------------------------------
*
* UpdateControlValues --
*
* This procedure updates the Macintosh scrollbar control to
* display the values defined by the Tk scrollbar. This is the
* key interface to the Mac-native scrollbar; the Unix bindings
* drive scrolling in the Tk window and all the Mac scrollbar has
* to do is redraw itself.
* This procedure updates the Macintosh scrollbar control to display the
* values defined by the Tk scrollbar. This is the key interface to the
* Mac-native scrollbar; the Unix bindings drive scrolling in the Tk
* window and all the Mac scrollbar has to do is redraw itself.
*
* Results:
* None.
@@ -473,20 +585,21 @@ TkpScrollbarPosition(
static void
UpdateControlValues(
TkScrollbar *scrollPtr) /* Scrollbar data struct. */
TkScrollbar *scrollPtr) /* Scrollbar data struct. */
{
MacScrollbar *msPtr = (MacScrollbar *)scrollPtr;
MacScrollbar *msPtr = (MacScrollbar *) scrollPtr;
Tk_Window tkwin = scrollPtr->tkwin;
MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin);
double dViewSize;
HIRect contrlRect;
HIRect contrlRect;
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));
Tk_Height(tkwin));
frame = NSInsetRect(frame, scrollPtr->inset, scrollPtr->inset);
frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
@@ -494,7 +607,7 @@ UpdateControlValues(
msPtr->info.bounds = contrlRect;
width = contrlRect.size.width;
height = contrlRect.size.height;
height = contrlRect.size.height - scrollPtr->arrowLength;
/*
* Ensure we set scrollbar control bounds only once all size adjustments
@@ -503,9 +616,9 @@ UpdateControlValues(
msPtr->info.bounds = contrlRect;
if (scrollPtr->vertical) {
msPtr->info.attributes &= ~kThemeTrackHorizontal;
msPtr->info.attributes &= ~kThemeTrackHorizontal;
} else {
msPtr->info.attributes |= kThemeTrackHorizontal;
msPtr->info.attributes |= kThemeTrackHorizontal;
}
/*
@@ -518,69 +631,71 @@ UpdateControlValues(
* the view area.
*/
double maximum = 100, factor;
factor = RangeToFactor(maximum);
dViewSize = (scrollPtr->lastFraction - scrollPtr->firstFraction)
* factor;
msPtr->info.max = MIN_SCROLLBAR_VALUE +
factor - dViewSize;
double factor = RangeToFactor(100.0);
dViewSize = (scrollPtr->lastFraction - scrollPtr->firstFraction) * factor;
msPtr->info.max = factor - dViewSize;
msPtr->info.trackInfo.scrollbar.viewsize = dViewSize;
if (scrollPtr->vertical) {
if (SNOW_LEOPARD_STYLE) {
msPtr->info.value = factor * scrollPtr->firstFraction;
} else {
msPtr->info.value = msPtr->info.max - factor * scrollPtr->firstFraction;
}
if (SNOW_LEOPARD_STYLE) {
msPtr->info.value = factor * scrollPtr->firstFraction;
} else {
msPtr->info.value = msPtr->info.max -
factor * scrollPtr->firstFraction;
}
} else {
msPtr->info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction;
msPtr->info.value = factor * scrollPtr->firstFraction;
}
if((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0)
|| height <= metrics.minHeight) {
if ((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0)
|| height <= metrics.minHeight) {
msPtr->info.enableState = kThemeTrackHideTrack;
} else {
msPtr->info.enableState = kThemeTrackActive;
msPtr->info.attributes = kThemeTrackShowThumb | kThemeTrackThumbRgnIsNotGhost;
msPtr->info.attributes =
kThemeTrackShowThumb | kThemeTrackThumbRgnIsNotGhost;
}
}
/*
*--------------------------------------------------------------
*
* ScrollbarEvent --
*
* This procedure is invoked in response to <ButtonPress>, <ButtonRelease>,
* <EnterNotify>, and <LeaveNotify> events. The Scrollbar appearance is
* modified for each event.
* This procedure is invoked in response to <ButtonPress>,
* <ButtonRelease>, <EnterNotify>, and <LeaveNotify> events. The
* Scrollbar appearance is modified for each event.
*
*--------------------------------------------------------------
*/
static int
ScrollbarEvent(TkScrollbar *scrollPtr, XEvent *eventPtr)
ScrollbarEvent(
TkScrollbar *scrollPtr,
XEvent *eventPtr)
{
MacScrollbar *msPtr = (MacScrollbar *)scrollPtr;
/* The pressState does not indicate whether the moused button was
* pressed at some location in the Scrollbar. Rather, it indicates
* that the scrollbar should appear as if it were pressed in that
* location. The standard Mac behavior is that once the button is
* pressed inside the Scrollbar the appearance should not change until
* the button is released, even if the mouse moves outside of the
* scrollbar. However, if the mouse lies over the scrollbar but the
* button is not pressed then the appearance should be the same as if
* the button had been pressed on the slider, i.e. kThemeThumbPressed.
* See the file Appearance.r, or HIToolbox.bridgesupport on 10.14.
MacScrollbar *msPtr = (MacScrollbar *) scrollPtr;
/*
* The pressState does not indicate whether the moused button was pressed
* at some location in the Scrollbar. Rather, it indicates that the
* scrollbar should appear as if it were pressed in that location. The
* standard Mac behavior is that once the button is pressed inside the
* Scrollbar the appearance should not change until the button is released,
* even if the mouse moves outside of the scrollbar. However, if the mouse
* lies over the scrollbar but the button is not pressed then the
* appearance should be the same as if the button had been pressed on the
* slider, i.e. kThemeThumbPressed. See the file Appearance.r, or
* HIToolbox.bridgesupport on 10.14.
*/
if (eventPtr->type == ButtonPress) {
msPtr->buttonDown = true;
UpdateControlValues(scrollPtr);
int where = TkpScrollbarPosition(scrollPtr,
eventPtr->xbutton.x,
eventPtr->xbutton.y);
switch(where) {
eventPtr->xbutton.x, eventPtr->xbutton.y);
switch (where) {
case OUTSIDE:
msPtr->info.trackInfo.scrollbar.pressState = 0;
break;
@@ -591,14 +706,21 @@ ScrollbarEvent(TkScrollbar *scrollPtr, XEvent *eventPtr)
msPtr->info.trackInfo.scrollbar.pressState = kThemeThumbPressed;
break;
case BOTTOM_GAP:
msPtr->info.trackInfo.scrollbar.pressState = kThemeBottomTrackPressed;
msPtr->info.trackInfo.scrollbar.pressState =
kThemeBottomTrackPressed;
break;
case TOP_ARROW:
/* This looks wrong and the docs say it is wrong but it works. */
msPtr->info.trackInfo.scrollbar.pressState = kThemeTopInsideArrowPressed;
/*
* This looks wrong and the docs say it is wrong but it works.
*/
msPtr->info.trackInfo.scrollbar.pressState =
kThemeTopInsideArrowPressed;
break;
case BOTTOM_ARROW:
msPtr->info.trackInfo.scrollbar.pressState = kThemeBottomOutsideArrowPressed;
msPtr->info.trackInfo.scrollbar.pressState =
kThemeBottomOutsideArrowPressed;
break;
}
}
@@ -620,11 +742,10 @@ ScrollbarEvent(TkScrollbar *scrollPtr, XEvent *eventPtr)
msPtr->info.trackInfo.scrollbar.pressState = 0;
}
}
TkScrollbarEventuallyRedraw(scrollPtr);
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
@@ -645,8 +766,8 @@ ScrollbarEvent(TkScrollbar *scrollPtr, XEvent *eventPtr)
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;
@@ -668,7 +789,7 @@ ScrollbarEventProc(
TkScrollbarEventProc(clientData, eventPtr);
}
}
/*
* Local Variables:
* mode: objc

View File

@@ -51,7 +51,7 @@ typedef struct RegisteredInterp {
* A registry of all interpreters for a display is kept in a property
* "InterpRegistry" on the root window of the display. It is organized as a
* series of zero or more concatenated strings (in no particular order), each
* of the form
* of the form:
* window space name '\0'
* where "window" is the hex id of the comm. window to use to talk to an
* interpreter named "name".
@@ -78,7 +78,7 @@ typedef struct NameRegistry {
* XFree; zero means use ckfree. */
} NameRegistry;
static int initialized = 0; /* A flag to denote if we have initialized
static int initialized = 0; /* A flag to denote if we have initialized
* yet. */
static RegisteredInterp *interpListPtr = NULL;
@@ -325,7 +325,7 @@ Tk_SendObjCmd(
int objc, /* Number of arguments */
Tcl_Obj *const objv[]) /* The arguments */
{
const char *const sendOptions[] = {"-async", "-displayof", "-", NULL};
const char *const sendOptions[] = {"-async", "-displayof", "--", NULL};
char *stringRep, *destName;
/*int async = 0;*/
int i, index, firstArg;

158
macosx/tkMacOSXServices.c Normal file
View File

@@ -0,0 +1,158 @@
/*
* tkMacOSXServices.c --
*\
* This file allows the integration of Tk and the Cocoa NSServices API.
*
* Copyright (c) 2010-2019 Kevin Walzer/WordTech Communications LLC.
* Copyright (c) 2019 Marc Culler.
* Copyright (c) 2010 Adrian Robert.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <tkInt.h>
#include <tkMacOSXInt.h>
/*
* Event proc which calls the PerformService procedure.
*/
static int
ServicesEventProc(
Tcl_Event *event,
int flags)
{
TkMainInfo *info = TkGetMainInfoList();
Tcl_GlobalEval(info->interp, "::tk::mac::PerformService");
return 1;
}
/*
* The Wish application can send the current selection in the Tk clipboard
* to other applications which accept messages of type NSString. The TkService
* object provides this service via its provideService method. (The method
* must be specified in the application's Info.plist file for this to work.)
*/
@interface TkService : NSObject {
}
+ (void) initialize;
- (void) provideService:(NSPasteboard *)pboard
userData:(NSString *)data
error:(NSString **)error;
- (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard
types:(NSArray *)types;
@end
/*
* Class methods.
*/
@implementation TkService
+ (void) initialize {
NSArray *sendTypes = [NSArray arrayWithObjects:@"NSStringPboardType",
@"NSPasteboardTypeString", nil];
[NSApp registerServicesMenuSendTypes:sendTypes returnTypes:sendTypes];
return;
}
/*
* Get the current Tk selection and copy it to the system pasteboard.
*/
- (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard
types:(NSArray *)types
{
NSArray *typesDeclared = nil;
NSString *pboardType = nil;
TkMainInfo *info = TkGetMainInfoList();
for (NSString *typeString in types) {
if ([typeString isEqualToString:@"NSStringPboardType"] ||
[typeString isEqualToString:@"NSPasteboardTypeString"]) {
typesDeclared = [NSArray arrayWithObject:typeString];
pboardType = typeString;
break;
}
}
if (!typesDeclared) {
return NO;
}
Tcl_Eval(info->interp, "selection get");
char *copystring = Tcl_GetString(Tcl_GetObjResult(info->interp));
NSString *writestring = [NSString stringWithUTF8String:copystring];
[pboard declareTypes:typesDeclared owner:nil];
return [pboard setString:writestring forType:pboardType];
}
/*
* This is the method that actually calls the Tk service; it must be specified
* in Info.plist.
*/
- (void)provideService:(NSPasteboard *)pboard
userData:(NSString *)data
error:(NSString **)error
{
NSString *pboardString = nil, *pboardType = nil;
NSArray *types = [pboard types];
Tcl_Event *event;
/*
* Get a string from the private pasteboard and copy it to the general
* pasteboard to make it available to other applications.
*/
for (NSString *typeString in types) {
if ([typeString isEqualToString:@"NSStringPboardType"] ||
[typeString isEqualToString:@"NSPasteboardTypeString"]) {
pboardString = [pboard stringForType:typeString];
pboardType = typeString;
break;
}
}
if (pboardString) {
NSPasteboard *generalpasteboard = [NSPasteboard generalPasteboard];
[generalpasteboard declareTypes:[NSArray arrayWithObjects:pboardType, nil]
owner:nil];
[generalpasteboard setString:pboardString forType:pboardType];
event = ckalloc(sizeof(Tcl_Event));
event->proc = ServicesEventProc;
Tcl_QueueEvent((Tcl_Event *)event, TCL_QUEUE_TAIL);
}
}
@end
/*
* Instantiate a TkService object and register it with the NSApplication.
* This is called exactly one time from TkpInit.
*/
int
TkMacOSXServices_Init(
Tcl_Interp *interp)
{
/*
* Initialize an instance of TkService and register it with the NSApp.
*/
TkService *service = [[TkService alloc] init];
[NSApp setServicesProvider:service];
return TCL_OK;
}
/*
* Local Variables:
* mode: objc
* c-basic-offset: 4
* fill-column: 79
* coding: utf-8
* End:
*/

View File

@@ -49,7 +49,7 @@ static void NotifyVisibility(TkWindow *winPtr, XEvent *eventPtr);
*----------------------------------------------------------------------
*/
void
int
XDestroyWindow(
Display *display, /* Display. */
Window window) /* Window. */
@@ -65,35 +65,41 @@ XDestroyWindow(
TkMacOSXSelDeadWindow(macWin->winPtr);
macWin->toplevel->referenceCount--;
if (!Tk_IsTopLevel(macWin->winPtr) ) {
if (!Tk_IsTopLevel(macWin->winPtr)) {
TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
if (macWin->winPtr->parentPtr != NULL) {
TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr->parentPtr);
}
if (macWin->visRgn) {
CFRelease(macWin->visRgn);
macWin->visRgn = NULL;
}
if (macWin->aboveVisRgn) {
CFRelease(macWin->aboveVisRgn);
macWin->aboveVisRgn = NULL;
}
if (macWin->drawRgn) {
CFRelease(macWin->drawRgn);
macWin->drawRgn = NULL;
}
if (macWin->toplevel->referenceCount == 0) {
ckfree(macWin->toplevel);
}
ckfree(macWin);
return;
return Success;
}
if (macWin->visRgn) {
CFRelease(macWin->visRgn);
macWin->visRgn = NULL;
}
if (macWin->aboveVisRgn) {
CFRelease(macWin->aboveVisRgn);
macWin->aboveVisRgn = NULL;
}
if (macWin->drawRgn) {
CFRelease(macWin->drawRgn);
macWin->drawRgn = NULL;
}
macWin->view = nil;
@@ -105,6 +111,7 @@ XDestroyWindow(
if (macWin->toplevel->referenceCount == 0) {
ckfree(macWin->toplevel);
}
return Success;
}
/*
@@ -124,12 +131,14 @@ XDestroyWindow(
*----------------------------------------------------------------------
*/
void
int
XMapWindow(
Display *display, /* Display. */
Window window) /* Window. */
{
MacDrawable *macWin = (MacDrawable *) window;
TkWindow *winPtr = macWin->winPtr;
NSWindow *win = TkMacOSXDrawableWindow(window);
XEvent event;
/*
@@ -145,33 +154,40 @@ XMapWindow(
}
display->request++;
macWin->winPtr->flags |= TK_MAPPED;
if (Tk_IsTopLevel(macWin->winPtr)) {
if (!Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *win = TkMacOSXDrawableWindow(window);
winPtr->flags |= TK_MAPPED;
if (Tk_IsTopLevel(winPtr)) {
if (!Tk_IsEmbedded(winPtr)) {
/*
* We want to activate Tk when a toplevel is mapped
* but we must not supply YES here. This is because
* during Tk initialization the root window is mapped
* before applicationDidFinishLaunching returns. Forcing
* the app to activate too early can make the menu bar
* unresponsive.
* We want to activate Tk when a toplevel is mapped but we must not
* supply YES here. This is because during Tk initialization the
* root window is mapped before applicationDidFinishLaunching
* returns. Forcing the app to activate too early can make the menu
* bar unresponsive.
*/
TkMacOSXApplyWindowAttributes(winPtr, win);
[win setExcludedFromWindowsMenu:NO];
[NSApp activateIgnoringOtherApps:NO];
if ( [win canBecomeKeyWindow] ) {
[[win contentView] setNeedsDisplay:YES];
if ([win canBecomeKeyWindow]) {
[win makeKeyAndOrderFront:NSApp];
} else {
[win orderFrontRegardless];
}
TkMacOSXApplyWindowAttributes(macWin->winPtr, win);
} else {
TkWindow *contWinPtr = TkpGetOtherWindow(winPtr);
/*
* Rebuild the container's clipping region and display
* the window.
*/
TkWindow *contWinPtr = TkpGetOtherWindow(macWin->winPtr);
TkMacOSXInvalClipRgns((Tk_Window)contWinPtr);
TkMacOSXInvalClipRgns((Tk_Window) contWinPtr);
TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
}
TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr);
TkMacOSXInvalClipRgns((Tk_Window) winPtr);
/*
* We only need to send the MapNotify event for toplevel windows.
@@ -184,16 +200,22 @@ XMapWindow(
event.xmap.window = window;
event.xmap.type = MapNotify;
event.xmap.event = window;
event.xmap.override_redirect = macWin->winPtr->atts.override_redirect;
event.xmap.override_redirect = winPtr->atts.override_redirect;
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
} else {
/*
* Rebuild the parent's clipping region and display the window.
*
* For non-toplevel windows, rebuild the parent's clipping region
* and redisplay the window.
*/
TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr->parentPtr);
TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
TkMacOSXInvalClipRgns((Tk_Window) winPtr->parentPtr);
}
if ([NSApp isDrawing]) {
[[win contentView] setNeedsRedisplay:YES];
} else {
[[win contentView] setNeedsDisplay:YES];
}
/*
@@ -204,14 +226,8 @@ XMapWindow(
event.xany.display = display;
event.xvisibility.type = VisibilityNotify;
event.xvisibility.state = VisibilityUnobscured;
NotifyVisibility(macWin->winPtr, &event);
/*
* Make sure that subwindows get displayed.
*/
GenerateConfigureNotify(macWin->winPtr, 1);
NotifyVisibility(winPtr, &event);
return Success;
}
/*
@@ -265,7 +281,7 @@ NotifyVisibility(
*----------------------------------------------------------------------
*/
void
int
XUnmapWindow(
Display *display, /* Display. */
Window window) /* Window. */
@@ -273,18 +289,14 @@ XUnmapWindow(
MacDrawable *macWin = (MacDrawable *) window;
TkWindow *winPtr = macWin->winPtr;
TkWindow *parentPtr = winPtr->parentPtr;
NSWindow *win = TkMacOSXDrawableWindow(window);
XEvent event;
display->request++;
if (Tk_IsTopLevel(winPtr)) {
if (!Tk_IsEmbedded(winPtr) &&
winPtr->wmInfoPtr->hints.initial_state!=IconicState) {
NSWindow *win = TkMacOSXDrawableWindow(window);
if ([win isVisible]) {
[[win parentWindow] removeChildWindow:win];
[win orderOut:NSApp];
}
[win orderOut:nil];
}
TkMacOSXInvalClipRgns((Tk_Window) winPtr);
@@ -302,20 +314,27 @@ XUnmapWindow(
event.xunmap.from_configure = false;
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
} else {
/*
* Rebuild the visRgn clip region for the parent so it will be allowed
* to draw in the space from which this subwindow was removed.
* to draw in the space from which this subwindow was removed and then
* redraw the window.
*/
if (parentPtr && parentPtr->privatePtr->visRgn) {
TkMacOSXInvalidateViewRegion(TkMacOSXDrawableView(parentPtr->privatePtr),
parentPtr->privatePtr->visRgn);
TkMacOSXInvalidateViewRegion(
TkMacOSXDrawableView(parentPtr->privatePtr),
parentPtr->privatePtr->visRgn);
}
TkMacOSXInvalClipRgns((Tk_Window) parentPtr);
TkMacOSXUpdateClipRgn(parentPtr);
}
winPtr->flags &= ~TK_MAPPED;
if ([NSApp isDrawing]) {
[[win contentView] setNeedsRedisplay:YES];
} else {
[[win contentView] setNeedsDisplay:YES];
}
return Success;
}
/*
@@ -335,7 +354,7 @@ XUnmapWindow(
*----------------------------------------------------------------------
*/
void
int
XResizeWindow(
Display *display, /* Display. */
Window window, /* Window. */
@@ -343,11 +362,14 @@ XResizeWindow(
unsigned int height)
{
MacDrawable *macWin = (MacDrawable *) window;
display->request++;
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
if (w) {
NSRect r = [w contentRectForFrameRect:[w frame]];
r.origin.y += r.size.height - height;
r.size.width = width;
r.size.height = height;
@@ -356,6 +378,7 @@ XResizeWindow(
} else {
MoveResizeWindow(macWin);
}
return Success;
}
/*
@@ -363,8 +386,8 @@ XResizeWindow(
*
* XMoveResizeWindow --
*
* Move or resize a given X window. See X windows documentation
* for further details.
* Move or resize a given X window. See X windows documentation for
* further details.
*
* Results:
* None.
@@ -375,7 +398,7 @@ XResizeWindow(
*----------------------------------------------------------------------
*/
void
int
XMoveResizeWindow(
Display *display, /* Display. */
Window window, /* Window. */
@@ -388,27 +411,30 @@ XMoveResizeWindow(
display->request++;
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
if (w) {
/* We explicitly convert everything to doubles so we don't get
if (w) {
/*
* We explicitly convert everything to doubles so we don't get
* surprised (again) by what happens when you do arithmetic with
* unsigned ints.
*/
CGFloat X = (CGFloat)x;
CGFloat Y = (CGFloat)y;
CGFloat Width = (CGFloat)width;
CGFloat Height = (CGFloat)height;
CGFloat XOff = (CGFloat)macWin->winPtr->wmInfoPtr->xInParent;
CGFloat YOff = (CGFloat)macWin->winPtr->wmInfoPtr->yInParent;
NSRect r = NSMakeRect(X + XOff,
tkMacOSXZeroScreenHeight - Y - YOff - Height,
Width, Height);
CGFloat X = (CGFloat) x;
CGFloat Y = (CGFloat) y;
CGFloat Width = (CGFloat) width;
CGFloat Height = (CGFloat) height;
CGFloat XOff = (CGFloat) macWin->winPtr->wmInfoPtr->xInParent;
CGFloat YOff = (CGFloat) macWin->winPtr->wmInfoPtr->yInParent;
NSRect r = NSMakeRect(
X + XOff, TkMacOSXZeroScreenHeight() - Y - YOff - Height,
Width, Height);
[w setFrame:[w frameRectForContentRect:r] display:YES];
}
} else {
MoveResizeWindow(macWin);
}
return Success;
}
/*
@@ -416,8 +442,7 @@ XMoveResizeWindow(
*
* XMoveWindow --
*
* Move a given X window. See X windows documentation for further
* details.
* Move a given X window. See X windows documentation for further details.
*
* Results:
* None.
@@ -428,7 +453,7 @@ XMoveResizeWindow(
*----------------------------------------------------------------------
*/
void
int
XMoveWindow(
Display *display, /* Display. */
Window window, /* Window. */
@@ -439,12 +464,15 @@ XMoveWindow(
display->request++;
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
if (w) {
[w setFrameTopLeftPoint:NSMakePoint(x, tkMacOSXZeroScreenHeight - y)];
[w setFrameTopLeftPoint: NSMakePoint(
x, TkMacOSXZeroScreenHeight() - y)];
}
} else {
MoveResizeWindow(macWin);
}
return Success;
}
/*
@@ -481,7 +509,6 @@ MoveResizeWindow(
if (contWinPtr) {
macParent = contWinPtr->privatePtr;
} else {
/*
* Here we should handle out of process embedding. At this point,
* we are assuming that the changes.x,y is not maintained, if you
@@ -490,7 +517,6 @@ MoveResizeWindow(
*/
}
} else {
/*
* TODO: update all xOff & yOffs
*/
@@ -571,7 +597,7 @@ GenerateConfigureNotify(
*----------------------------------------------------------------------
*/
void
int
XRaiseWindow(
Display *display, /* Display. */
Window window) /* Window. */
@@ -582,11 +608,11 @@ XRaiseWindow(
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
TkWmRestackToplevel(macWin->winPtr, Above, NULL);
} else {
/*
* TODO: this should generate damage
*/
}
return Success;
}
#if 0
@@ -617,7 +643,6 @@ XLowerWindow(
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
TkWmRestackToplevel(macWin->winPtr, Below, NULL);
} else {
/*
* TODO: this should generate damage
*/
@@ -643,7 +668,7 @@ XLowerWindow(
*----------------------------------------------------------------------
*/
void
int
XConfigureWindow(
Display *display, /* Display. */
Window w, /* Window. */
@@ -680,14 +705,17 @@ XConfigureWindow(
TkMacOSXInvalClipRgns((Tk_Window) winPtr->parentPtr);
TkMacOSXWinBounds(winPtr, &bounds);
r = NSMakeRect(bounds.left,
[view bounds].size.height - bounds.bottom,
bounds.right - bounds.left, bounds.bottom - bounds.top);
[view bounds].size.height - bounds.bottom,
bounds.right - bounds.left, bounds.bottom - bounds.top);
[view setNeedsDisplayInRect:r];
}
}
/* TkGenWMMoveRequestEvent(macWin->winPtr,
macWin->winPtr->changes.x, macWin->winPtr->changes.y); */
#if 0
TkGenWMMoveRequestEvent(macWin->winPtr,
macWin->winPtr->changes.x, macWin->winPtr->changes.y);
#endif
return Success;
}
/*
@@ -709,14 +737,14 @@ XConfigureWindow(
void
TkMacOSXSetDrawingEnabled(
TkWindow *winPtr,
int flag)
TkWindow *winPtr,
int flag)
{
TkWindow *childPtr;
MacDrawable *macWin = winPtr->privatePtr;
if (macWin) {
if (flag ) {
if (flag) {
macWin->flags &= ~TK_DO_NOT_DRAW;
} else {
macWin->flags |= TK_DO_NOT_DRAW;
@@ -724,8 +752,8 @@ TkMacOSXSetDrawingEnabled(
}
/*
* Set the flag for all children & their descendants, excluding
* Toplevels. (??? Do we need to exclude Toplevels?)
* Set the flag for all children & their descendants, excluding Toplevels.
* (??? Do we need to exclude Toplevels?)
*/
childPtr = winPtr->childList;
@@ -889,7 +917,6 @@ TkMacOSXUpdateClipRgn(
}
CFRelease(rgn);
} else {
/*
* An unmapped window has empty clip regions to prevent any
* (erroneous) drawing into it or its children from becoming
@@ -919,8 +946,8 @@ TkMacOSXUpdateClipRgn(
* TkMacOSXVisableClipRgn --
*
* This function returns the Macintosh clipping region for the given
* window. The caller is responsible for disposing of the returned
* region via TkDestroyRegion().
* window. The caller is responsible for disposing of the returned region
* via TkDestroyRegion().
*
* Results:
* The region.
@@ -938,7 +965,7 @@ TkMacOSXVisableClipRgn(
if (winPtr->privatePtr->flags & TK_CLIP_INVALID) {
TkMacOSXUpdateClipRgn(winPtr);
}
return (TkRegion)HIShapeCreateMutableCopy(winPtr->privatePtr->visRgn);
return (TkRegion) HIShapeCreateMutableCopy(winPtr->privatePtr->visRgn);
}
/*
@@ -958,7 +985,12 @@ TkMacOSXVisableClipRgn(
*/
static OSStatus
InvalViewRect(int msg, HIShapeRef rgn, const CGRect *rect, void *ref) {
InvalViewRect(
int msg,
HIShapeRef rgn,
const CGRect *rect,
void *ref)
{
static CGAffineTransform t;
NSView *view = ref;
@@ -1038,7 +1070,7 @@ TkMacOSXInvalidateWindow(
*----------------------------------------------------------------------
*/
NSWindow*
NSWindow *
TkMacOSXDrawableWindow(
Drawable drawable)
{
@@ -1056,6 +1088,7 @@ TkMacOSXDrawableWindow(
result = macWin->winPtr->wmInfoPtr->window;
} else if (macWin->toplevel && (macWin->toplevel->flags & TK_EMBEDDED)) {
TkWindow *contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr);
if (contWinPtr) {
result = TkMacOSXDrawableWindow((Drawable) contWinPtr->privatePtr);
}
@@ -1109,7 +1142,7 @@ TkMacOSXGetDrawablePort(
*----------------------------------------------------------------------
*/
NSView*
NSView *
TkMacOSXDrawableView(
MacDrawable *macWin)
{
@@ -1123,6 +1156,7 @@ TkMacOSXDrawableView(
result = macWin->toplevel->view;
} else {
TkWindow *contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr);
if (contWinPtr) {
result = TkMacOSXDrawableView(contWinPtr->privatePtr);
}
@@ -1150,7 +1184,6 @@ void *
TkMacOSXGetRootControl(
Drawable drawable)
{
/*
* will probably need to fix this up for embedding
*/
@@ -1267,7 +1300,8 @@ TkMacOSXWinBounds(
TkWindow *winPtr,
void *bounds)
{
Rect *b = (Rect *)bounds;
Rect *b = (Rect *) bounds;
b->left = winPtr->privatePtr->xOff;
b->top = winPtr->privatePtr->yOff;
b->right = b->left + winPtr->changes.width;
@@ -1310,7 +1344,7 @@ TkMacOSXWinCGBounds(
* UpdateOffsets --
*
* Updates the X & Y offsets of the given TkWindow from the TopLevel it is
* a decendant of.
* a descendant of.
*
* Results:
* None.
@@ -1331,7 +1365,6 @@ UpdateOffsets(
TkWindow *childPtr;
if (winPtr->privatePtr == NULL) {
/*
* We haven't called Tk_MakeWindowExist for this window yet. The offset
* information will be postponed and calulated at that time. (This will

View File

@@ -13,13 +13,19 @@
*/
#include "tkMacOSXPrivate.h"
#include "tkMacOSXConstants.h"
/*
* Forward declarations of procedures defined later in this file:
*/
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080
static int DebuggerObjCmd (ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
int objc, Tcl_Obj *const objv[]);
#endif
static int PressButtonObjCmd (ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
/*
*----------------------------------------------------------------------
@@ -46,8 +52,10 @@ TkplatformtestInit(
* Add commands for platform specific tests on MacOS here.
*/
Tcl_CreateObjCommand(interp, "debugger", DebuggerObjCmd,
(ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080
Tcl_CreateObjCommand(interp, "debugger", DebuggerObjCmd, NULL, NULL);
#endif
Tcl_CreateObjCommand(interp, "pressbutton", PressButtonObjCmd, NULL, NULL);
return TCL_OK;
}
@@ -57,7 +65,8 @@ TkplatformtestInit(
*
* DebuggerObjCmd --
*
* This procedure simply calls the low level debugger.
* This procedure simply calls the low level debugger, which was
* deprecated in OSX 10.8.
*
* Results:
* A standard Tcl result.
@@ -68,6 +77,7 @@ TkplatformtestInit(
*----------------------------------------------------------------------
*/
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080
static int
DebuggerObjCmd(
ClientData clientData, /* Not used. */
@@ -78,34 +88,136 @@ DebuggerObjCmd(
Debugger();
return TCL_OK;
}
#endif
/*
*----------------------------------------------------------------------
*
* TkTestSimulateDrawing --
*
* A test widget display procedure which records calls can use this to
* avoid duplicate calls which would occur due to fact that no valid
* graphics context is available to the idle task which is running the
* display proc. Note that no actual drawing to the screen will take
* place when this flag is set. This is just a wrapper for the NSApp
* property.
* TkTestLogDisplay --
*
* The test image display procedure calls this to determine whether it
* should write a log message recording that it has being run. On OSX
* 10.14 and later, only calls to the display procedure which occur inside
* of the drawRect method should be logged, since those are the only ones
* which actually draw anything. On earlier systems the opposite is true.
* The calls from within the drawRect method are redundant, since the
* first time the display procedure is run it will do the drawing and that
* first call will usually not occur inside of drawRect.
*
* Results:
* Calls to low level drawing routines will return without actually
* drawing anything to the screen.
* On OSX 10.14 and later, returns true if and only if called from
* within [NSView drawRect]. On earlier systems returns false if
* and only if called from with [NSView drawRect].
*
* Side effects:
* None
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE void
TkTestSimulateDrawing(Bool yesno) {
[NSApp setSimulateDrawing:yesno];
MODULE_SCOPE Bool
TkTestLogDisplay(void) {
if ([NSApp macMinorVersion] >= 14) {
return [NSApp isDrawing];
} else {
return ![NSApp isDrawing];
}
}
/*
*----------------------------------------------------------------------
*
* PressButtonObjCmd --
*
* This Tcl command simulates a button press at a specific screen
* location. It injects NSEvents into the NSApplication event queue,
* as opposed to adding events to the Tcl queue as event generate
* would do. One application is for testing the grab command.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
static int
PressButtonObjCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
int x, y, i, value, wNum;
CGPoint pt;
NSPoint loc;
NSEvent *motion, *press, *release;
NSArray *screens = [NSScreen screens];
CGFloat ScreenHeight = 0;
enum {X=1, Y};
if (screens && [screens count]) {
ScreenHeight = [[screens objectAtIndex:0] frame].size.height;
}
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "x y");
return TCL_ERROR;
}
for (i = 1; i < objc; i++) {
if (Tcl_GetIntFromObj(interp,objv[i],&value) != TCL_OK) {
return TCL_ERROR;
}
switch (i) {
case X:
x = value;
break;
case Y:
y = value;
break;
default:
break;
}
}
pt.x = loc.x = x;
pt.y = y;
loc.y = ScreenHeight - y;
wNum = 0;
CGWarpMouseCursorPosition(pt);
motion = [NSEvent mouseEventWithType:NSMouseMoved
location:loc
modifierFlags:0
timestamp:GetCurrentEventTime()
windowNumber:wNum
context:nil
eventNumber:0
clickCount:1
pressure:0.0];
[NSApp postEvent:motion atStart:NO];
press = [NSEvent mouseEventWithType:NSLeftMouseDown
location:loc
modifierFlags:0
timestamp:GetCurrentEventTime()
windowNumber:wNum
context:nil
eventNumber:1
clickCount:1
pressure:0.0];
[NSApp postEvent:press atStart:NO];
release = [NSEvent mouseEventWithType:NSLeftMouseUp
location:loc
modifierFlags:0
timestamp:GetCurrentEventTime()
windowNumber:wNum
context:nil
eventNumber:2
clickCount:1
pressure:0.0];
[NSApp postEvent:release atStart:NO];
return TCL_OK;
}
/*

View File

@@ -31,7 +31,7 @@
*/
static int GenerateUpdates(HIShapeRef updateRgn,
CGRect *updateBounds, TkWindow *winPtr);
CGRect *updateBounds, TkWindow *winPtr);
static int GenerateActivateEvents(TkWindow *winPtr,
int activeFlag);
static void DoWindowActivate(ClientData clientData);
@@ -68,8 +68,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
BOOL movedOnly = [[notification name]
isEqualToString:NSWindowDidMoveNotification];
isEqualToString:NSWindowDidMoveNotification];
NSWindow *w = [notification object];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
@@ -79,8 +78,8 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
int x, y, width = -1, height = -1, flags = 0;
x = bounds.origin.x;
y = tkMacOSXZeroScreenHeight - (bounds.origin.y + bounds.size.height);
if (winPtr->changes.x != x || winPtr->changes.y != y){
y = TkMacOSXZeroScreenHeight() - (bounds.origin.y + bounds.size.height);
if (winPtr->changes.x != x || winPtr->changes.y != y) {
flags |= TK_LOCATION_CHANGED;
} else {
x = y = -1;
@@ -92,15 +91,16 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
flags |= TK_SIZE_CHANGED;
}
if (Tcl_GetServiceMode() != TCL_SERVICE_NONE) {
/*
* Propagate geometry changes immediately.
*/
flags |= TK_MACOSX_HANDLE_EVENT_IMMEDIATELY;
}
TkGenWMConfigureEvent((Tk_Window) winPtr, x, y, width, height, flags);
}
}
- (void) windowExpanded: (NSNotification *) notification
@@ -136,6 +136,46 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
}
}
- (NSRect)windowWillUseStandardFrame:(NSWindow *)window
defaultFrame:(NSRect)newFrame
{
/*
* This method needs to be implemented in order for [NSWindow isZoomed] to
* give the correct answer. But it suffices to always validate every
* request.
*/
return newFrame;
}
- (NSSize)window:(NSWindow *)window
willUseFullScreenContentSize:(NSSize)proposedSize
{
/*
* We don't need to change the proposed size, but we do need to implement
* this method. Otherwise the full screen window will be sized to the
* screen's visibleFrame, leaving black bands at the top and bottom.
*/
return proposedSize;
}
- (void) windowEnteredFullScreen: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
[(TKWindow *)[notification object] tkLayoutChanged];
}
- (void) windowExitedFullScreen: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
[(TKWindow *)[notification object] tkLayoutChanged];
}
- (void) windowCollapsed: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
@@ -158,21 +198,16 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
if (winPtr) {
TkGenWMDestroyEvent((Tk_Window) winPtr);
if (_windowWithMouse == w) {
_windowWithMouse = nil;
[w release];
}
}
/*
* If necessary, TkGenWMDestroyEvent() handles [close]ing the window,
* so can always return NO from -windowShouldClose: for a Tk window.
* If necessary, TkGenWMDestroyEvent() handles [close]ing the window, so
* can always return NO from -windowShouldClose: for a Tk window.
*/
return (winPtr ? NO : YES);
}
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
- (void) windowDragStart: (NSNotification *) notification
@@ -213,7 +248,6 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
}
}
#endif /* TK_MAC_DEBUG_NOTIFICATIONS */
- (void) _setupWindowNotifications
@@ -222,12 +256,19 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
#define observe(n, s) \
[nc addObserver:self selector:@selector(s) name:(n) object:nil]
observe(NSWindowDidBecomeKeyNotification, windowActivation:);
observe(NSWindowDidResignKeyNotification, windowActivation:);
observe(NSWindowDidMoveNotification, windowBoundsChanged:);
observe(NSWindowDidResizeNotification, windowBoundsChanged:);
observe(NSWindowDidDeminiaturizeNotification, windowExpanded:);
observe(NSWindowDidMiniaturizeNotification, windowCollapsed:);
#if !(MAC_OS_X_VERSION_MAX_ALLOWED < 1070)
observe(NSWindowDidEnterFullScreenNotification, windowEnteredFullScreen:);
observe(NSWindowDidExitFullScreenNotification, windowExitedFullScreen:);
#endif
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
observe(NSWindowWillMoveNotification, windowDragStart:);
observe(NSWindowWillStartLiveResizeNotification, windowLiveResize:);
@@ -251,6 +292,22 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
[NSApp tkCheckPasteboard];
/*
* When the application is activated with Command-Tab it will create a
* zombie window for every Tk window which has been withdrawn. So iterate
* through the list of windows and order out any withdrawn window.
*/
for (NSWindow *win in [NSApp windows]) {
TkWindow *winPtr = TkMacOSXGetTkWindow(win);
if (!winPtr || !winPtr->wmInfoPtr) {
continue;
}
if (winPtr->wmInfoPtr->hints.initial_state == WithdrawnState) {
[win orderOut:nil];
}
}
}
- (void) applicationDeactivate: (NSNotification *) notification
@@ -260,6 +317,20 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
#endif
}
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender
hasVisibleWindows:(BOOL)flag
{
/*
* Allowing the default response means that withdrawn windows will get
* displayed on the screen with unresponsive title buttons. We don't
* really want that. Besides, we can write our own code to handle this
* with ::tk::mac::ReopenApplication. So we just say NO.
*/
return NO;
}
- (void) applicationShowHide: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
@@ -299,11 +370,11 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
*
* TkpAppIsDrawing --
*
* A widget display procedure can call this to determine whether it
* is being run inside of the drawRect method. This is needed for
* some tests, especially of the Text widget, which record data in
* a global Tcl variable and assume that display procedures will be
* run in a predictable sequence as Tcl idle tasks.
* A widget display procedure can call this to determine whether it is
* being run inside of the drawRect method. This is needed for some tests,
* especially of the Text widget, which record data in a global Tcl
* variable and assume that display procedures will be run in a
* predictable sequence as Tcl idle tasks.
*
* Results:
* True only while running the drawRect method of a TKContentView;
@@ -313,11 +384,11 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE Bool
TkpAppIsDrawing(void) {
return [NSApp isDrawing];
}
/*
*----------------------------------------------------------------------
@@ -443,7 +514,9 @@ GenerateActivateEvents(
int activeFlag)
{
TkGenerateActivateEvents(winPtr, activeFlag);
TkMacOSXGenerateFocusEvent(winPtr, activeFlag);
if (activeFlag || ![NSApp isActive]) {
TkMacOSXGenerateFocusEvent(winPtr, activeFlag);
}
return true;
}
@@ -600,17 +673,14 @@ TkGenWMConfigureEvent(
if (flags & TK_LOCATION_CHANGED) {
wmPtr->x = x;
wmPtr->y = y;
wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
}
if ((flags & TK_SIZE_CHANGED) && !(wmPtr->flags & WM_SYNC_PENDING) &&
((width != Tk_Width(tkwin)) || (height != Tk_Height(tkwin)))) {
if ((wmPtr->width == -1) && (width == winPtr->reqWidth)) {
/*
* Don't set external width, since the user didn't change it
* from what the widgets asked for.
*/
} else if (wmPtr->gridWin != NULL) {
wmPtr->width = wmPtr->reqGridWidth
+ (width - winPtr->reqWidth)/wmPtr->widthInc;
@@ -622,12 +692,10 @@ TkGenWMConfigureEvent(
}
if ((wmPtr->height == -1) && (height == winPtr->reqHeight)) {
/*
* Don't set external height, since the user didn't change it
* from what the widgets asked for.
*/
} else if (wmPtr->gridWin != NULL) {
wmPtr->height = wmPtr->reqGridHeight
+ (height - winPtr->reqHeight)/wmPtr->heightInc;
@@ -800,7 +868,10 @@ Tk_MacOSXIsAppInFront(void)
*
*/
/*Restrict event processing to Expose events.*/
/*
* Restrict event processing to Expose events.
*/
static Tk_RestrictAction
ExposeRestrictProc(
ClientData arg,
@@ -810,7 +881,10 @@ ExposeRestrictProc(
? TK_PROCESS_EVENT : TK_DEFER_EVENT);
}
/*Restrict event processing to ConfigureNotify events.*/
/*
* Restrict event processing to ConfigureNotify events.
*/
static Tk_RestrictAction
ConfigureRestrictProc(
ClientData arg,
@@ -819,6 +893,30 @@ ConfigureRestrictProc(
return (eventPtr->type==ConfigureNotify ? TK_PROCESS_EVENT : TK_DEFER_EVENT);
}
/*
* If a window gets mapped inside the drawRect method, this will be run as an
* idle task, after drawRect returns, to clean up the mess.
*/
static void
RedisplayView(
ClientData clientdata)
{
NSView *view = (NSView *) clientdata;
/*
* Make sure that we are not trying to displaying a view that no longer
* exists.
*/
for (NSWindow *w in [NSApp orderedWindows]) {
if ([w contentView] == view) {
[view setNeedsDisplay:YES];
break;
}
}
}
@implementation TKContentView(TKWindowEvent)
- (void) drawRect: (NSRect) rect
@@ -832,17 +930,15 @@ ConfigureRestrictProc(
Tk_PathName(winPtr));
#endif
if ([NSApp simulateDrawing]) {
return;
}
/*
* We do not allow recursive calls to drawRect, but we only log
* them on OSX > 10.13, where they should never happen.
* We do not allow recursive calls to drawRect, but we only log them on OSX
* > 10.13, where they should never happen.
*/
if ([NSApp isDrawing] && [NSApp macMinorVersion] > 13) {
TKLog(@"WARNING: a recursive call to drawRect was aborted.");
if ([NSApp isDrawing]) {
if ([NSApp macMinorVersion] > 13) {
TKLog(@"WARNING: a recursive call to drawRect was aborted.");
}
return;
}
@@ -867,6 +963,11 @@ ConfigureRestrictProc(
CFRelease(drawShape);
[NSApp setIsDrawing: NO];
if ([self needsRedisplay]) {
[self setNeedsRedisplay:NO];
Tcl_DoWhenIdle(RedisplayView, self);
}
#ifdef TK_MAC_DEBUG_DRAWING
fprintf(stderr, "drawRect: done.\n");
#endif
@@ -878,22 +979,22 @@ ConfigureRestrictProc(
NSWindow *w = [self window];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
Tk_Window tkwin = (Tk_Window) winPtr;
if (![self inLiveResize] &&
[w respondsToSelector: @selector (tkLayoutChanged)]) {
[(TKWindow *)w tkLayoutChanged];
}
if (winPtr) {
/* On OSX versions below 10.14 setFrame calls drawRect.
* On 10.14 it does its own drawing.
*/
if ([NSApp macMinorVersion] > 13) {
[NSApp setIsDrawing:YES];
}
unsigned int width = (unsigned int)newsize.width;
unsigned int height=(unsigned int)newsize.height;
ClientData oldArg;
Tk_RestrictProc *oldProc;
/*
* This can be called from outside the Tk event loop.
* Since it calls Tcl_DoOneEvent, we need to make sure we
* don't clobber the AutoreleasePool set up by the caller.
* This can be called from outside the Tk event loop. Since it calls
* Tcl_DoOneEvent, we need to make sure we don't clobber the
* AutoreleasePool set up by the caller.
*/
[NSApp _lockAutoreleasePool];
@@ -909,7 +1010,7 @@ ConfigureRestrictProc(
*/
TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height,
TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY);
TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY);
oldProc = Tk_RestrictEvents(ConfigureRestrictProc, NULL, &oldArg);
Tk_RestrictEvents(oldProc, oldArg, &oldArg);
@@ -933,7 +1034,7 @@ ConfigureRestrictProc(
/*
* Finally, unlock the main autoreleasePool.
*/
[NSApp _unlockAutoreleasePool];
}
}
@@ -997,16 +1098,15 @@ ConfigureRestrictProc(
}
/*
* This method is called when a user changes between light and dark mode.
* The implementation here generates a Tk virtual event which can be bound
* to a function that redraws the window in an appropriate style.
* This method is called when a user changes between light and dark mode. The
* implementation here generates a Tk virtual event which can be bound to a
* function that redraws the window in an appropriate style.
*/
- (void) viewDidChangeEffectiveAppearance
{
XVirtualEvent event;
int x, y;
NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
NSWindow *w = [self window];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
Tk_Window tkwin = (Tk_Window) winPtr;
@@ -1027,21 +1127,17 @@ ConfigureRestrictProc(
&event.x_root, &event.y_root, &x, &y, &event.state);
Tk_TopCoordsToWindow(tkwin, x, y, &event.x, &event.y);
event.same_screen = true;
if (osxMode == nil) {
event.name = Tk_GetUid("LightAqua");
Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
return;
}
if ([osxMode isEqual:@"Dark"]) {
if (TkMacOSXInDarkMode(tkwin)) {
event.name = Tk_GetUid("DarkAqua");
Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
return;
} else {
event.name = Tk_GetUid("LightAqua");
}
Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
}
/*
* This is no-op on 10.7 and up because Apple has removed this widget,
* but we are leaving it 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
@@ -1090,6 +1186,11 @@ ConfigureRestrictProc(
return YES;
}
/*
* This keyDown method does nothing, which is a huge improvement over the
* default keyDown method which beeps every time a key is pressed.
*/
- (void) keyDown: (NSEvent *) theEvent
{
#ifdef TK_MAC_DEBUG_EVENTS
@@ -1097,6 +1198,23 @@ ConfigureRestrictProc(
#endif
}
/*
* When the services menu is opened this is called for each Responder in
* the Responder chain until a service provider is found. The TkContentView
* should be the first (and generally only) Responder in the chain. We
* return the TkServices object that was created in TkpInit.
*/
- (id)validRequestorForSendType:(NSString *)sendType
returnType:(NSString *)returnType
{
if ([sendType isEqualToString:@"NSStringPboardType"] ||
[sendType isEqualToString:@"NSPasteboardTypeString"]) {
return [NSApp servicesProvider];
}
return [super validRequestorForSendType:sendType returnType:returnType];
}
@end
/*

File diff suppressed because it is too large Load Diff

View File

@@ -36,6 +36,17 @@ typedef struct ProtocolHandler {
* THE LAST FIELD OF THE STRUCTURE. */
} ProtocolHandler;
/* The following data structure is used in the TkWmInfo to maintain a list of all of the
* transient windows belonging to a given master.
*/
typedef struct Transient {
TkWindow *winPtr;
int flags;
struct Transient *nextPtr;
} Transient;
#define WITHDRAWN_BY_MASTER 0x1
/*
* A data structure of the following type holds window-manager-related
@@ -54,7 +65,7 @@ typedef struct TkWmInfo {
Tk_Uid titleUid; /* Title to display in window caption. If NULL,
* use name of widget. */
char *iconName; /* Name to display in icon. */
Window master; /* Master window for TRANSIENT_FOR property, or
Tk_Window master; /* Master window for TRANSIENT_FOR property, or
* None. */
XWMHints hints; /* Various pieces of information for window
* manager. */
@@ -62,14 +73,13 @@ typedef struct TkWmInfo {
* (corresponds to hints.window_group).
* Malloc-ed. Note: this field doesn't get
* updated if leader is destroyed. */
char *masterWindowName; /* Path name of window specified as master in
* "wm transient" command, or NULL. Malloc-ed.
* Note: this field doesn't get updated if
* masterWindowName is destroyed. */
Tk_Window icon; /* Window to use as icon for this window, or
* NULL. */
Tk_Window iconFor; /* Window for which this window is icon, or
* NULL if this isn't an icon for anyone. */
Transient *transientPtr; /* First item in a list of all transient windows
* belonging to this window, or NULL if there
* are no transients. */
/*
* Information used to construct an XSizeHints structure for the window

View File

@@ -33,9 +33,6 @@
#define ROOT_ID 10
CGFloat tkMacOSXZeroScreenHeight = 0;
CGFloat tkMacOSXZeroScreenTop = 0;
/*
* Declarations of static variables used in this file.
*/
@@ -90,13 +87,9 @@ TkMacOSXDisplayChanged(
nsScreens = [NSScreen screens];
if (nsScreens && [nsScreens count]) {
NSScreen *s = [nsScreens objectAtIndex:0];
NSRect bounds = [s frame], visible = [s visibleFrame];
NSRect bounds = [s frame];
NSRect maxBounds = NSZeroRect;
tkMacOSXZeroScreenHeight = bounds.size.height;
tkMacOSXZeroScreenTop = tkMacOSXZeroScreenHeight -
(visible.origin.y + visible.size.height);
screen->root_depth = NSBitsPerPixelFromDepth([s depth]);
screen->width = bounds.size.width;
screen->height = bounds.size.height;
@@ -110,6 +103,67 @@ TkMacOSXDisplayChanged(
}
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXZeroScreenHeight --
*
* Replacement for the tkMacOSXZeroScreenHeight variable to avoid
* caching values from NSScreen (fixes bug aea00be199).
*
* Results:
* Returns the height of screen 0 (the screen assigned the menu bar
* in System Preferences), or 0.0 if getting [NSScreen screens] fails.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
CGFloat
TkMacOSXZeroScreenHeight()
{
NSArray *nsScreens = [NSScreen screens];
if (nsScreens && [nsScreens count]) {
NSScreen *s = [nsScreens objectAtIndex:0];
NSRect bounds = [s frame];
return bounds.size.height;
}
return 0.0;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXZeroScreenTop --
*
* Replacement for the tkMacOSXZeroScreenTop variable to avoid
* caching values from visibleFrame.
*
* Results:
* Returns how far below the top of screen 0 to draw
* (i.e. the height of the menu bar if it is always shown),
* or 0.0 if getting [NSScreen screens] fails.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
CGFloat
TkMacOSXZeroScreenTop()
{
NSArray *nsScreens = [NSScreen screens];
if (nsScreens && [nsScreens count]) {
NSScreen *s = [nsScreens objectAtIndex:0];
NSRect bounds = [s frame], visible = [s visibleFrame];
return bounds.size.height - (visible.origin.y + visible.size.height);
}
return 0.0;
}
/*
*----------------------------------------------------------------------
*
@@ -178,7 +232,7 @@ TkpOpenDisplay(
{
int major, minor, patch;
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101000
Gestalt(gestaltSystemVersionMajor, (SInt32*)&major);
Gestalt(gestaltSystemVersionMinor, (SInt32*)&minor);
Gestalt(gestaltSystemVersionBugFix, (SInt32*)&patch);
@@ -202,7 +256,7 @@ TkpOpenDisplay(
screen->root_visual = ckalloc(sizeof(Visual));
screen->root_visual->visualid = 0;
screen->root_visual->class = TrueColor;
screen->root_visual->c_class = TrueColor;
screen->root_visual->red_mask = 0x00FF0000;
screen->root_visual->green_mask = 0x0000FF00;
screen->root_visual->blue_mask = 0x000000FF;
@@ -225,6 +279,12 @@ TkpOpenDisplay(
bzero(gMacDisplay, sizeof(TkDisplay));
gMacDisplay->display = display;
[pool drain];
/*
* Key map info must be available immediately, because of "send event".
*/
TkpInitKeymapInfo(gMacDisplay);
return gMacDisplay;
}
@@ -429,7 +489,7 @@ XGetGeometry(
return 1;
}
void
int
XChangeProperty(
Display* display,
Window w,
@@ -441,15 +501,17 @@ XChangeProperty(
int nelements)
{
Debugger();
return Success;
}
void
int
XSelectInput(
Display* display,
Window w,
long event_mask)
{
Debugger();
return Success;
}
int
@@ -508,11 +570,12 @@ XSendEvent(
return 0;
}
void
int
XClearWindow(
Display* display,
Window w)
{
return Success;
}
/*
@@ -524,6 +587,7 @@ XDrawPoint(
int x,
int y)
{
return Success;
}
int
@@ -535,6 +599,7 @@ XDrawPoints(
int npoints,
int mode)
{
return Success;
}
*/
@@ -553,7 +618,7 @@ XWarpPointer(
return Success;
}
void
int
XQueryColor(
Display* display,
Colormap colormap,
@@ -572,9 +637,10 @@ XQueryColor(
d->blue = (b << 8) | b;
d->flags = DoRed|DoGreen|DoBlue;
d->pad = 0;
return Success;
}
void
int
XQueryColors(
Display* display,
Colormap colormap,
@@ -597,6 +663,7 @@ XQueryColors(
d->flags = DoRed|DoGreen|DoBlue;
d->pad = 0;
}
return Success;
}
int
@@ -635,15 +702,16 @@ XGetWindowProperty(
return 0;
}
void
int
XRefreshKeyboardMapping(
XMappingEvent *x)
{
/* used by tkXEvent.c */
Debugger();
return Success;
}
void
int
XSetIconName(
Display* display,
Window w,
@@ -653,9 +721,10 @@ XSetIconName(
* This is a no-op, no icon name for Macs.
*/
display->request++;
return Success;
}
void
int
XForceScreenSaver(
Display* display,
int mode)
@@ -667,6 +736,7 @@ XForceScreenSaver(
*/
display->request++;
return Success;
}
void
@@ -680,7 +750,7 @@ Tk_FreeXId(
int
XSync(
Display *display,
Bool flag)
Bool discard)
{
TkMacOSXFlushWindows();
display->request++;
@@ -770,62 +840,69 @@ TkGetServerInfo(
*----------------------------------------------------------------------
*/
void
int
XChangeWindowAttributes(
Display *display,
Window w,
unsigned long value_mask,
XSetWindowAttributes *attributes)
{
return Success;
}
void
int
XSetWindowBackground(
Display *display,
Window window,
unsigned long value)
{
return Success;
}
void
int
XSetWindowBackgroundPixmap(
Display *display,
Window w,
Pixmap background_pixmap)
{
return Success;
}
void
int
XSetWindowBorder(
Display *display,
Window w,
unsigned long border_pixel)
{
return Success;
}
void
int
XSetWindowBorderPixmap(
Display *display,
Window w,
Pixmap border_pixmap)
{
return Success;
}
void
int
XSetWindowBorderWidth(
Display *display,
Window w,
unsigned int width)
{
return Success;
}
void
int
XSetWindowColormap(
Display *display,
Window w,
Colormap colormap)
{
Debugger();
return Success;
}
Status
@@ -848,12 +925,73 @@ XSetWMClientMachine(
}
XIC
XCreateIC(void)
XCreateIC(XIM xim, ...)
{
Debugger();
return (XIC) 0;
}
#undef XVisualIDFromVisual
VisualID
XVisualIDFromVisual(
Visual *visual)
{
return visual->visualid;
}
#undef XSynchronize
XAfterFunction
XSynchronize(
Display *display,
Bool onoff)
{
display->request++;
return NULL;
}
#undef XUngrabServer
int
XUngrabServer(
Display *display)
{
return 0;
}
#undef XNoOp
int
XNoOp(
Display *display)
{
display->request++;
return 0;
}
#undef XGrabServer
int
XGrabServer(
Display *display)
{
return 0;
}
#undef XFree
int
XFree(
void *data)
{
if ((data) != NULL) {
ckfree(data);
}
return 0;
}
#undef XFlush
int
XFlush(
Display *display)
{
return 0;
}
/*
*----------------------------------------------------------------------
*

File diff suppressed because it is too large Load Diff