Import Tk 8.6.8

This commit is contained in:
Cheryl Sabella
2018-02-22 14:31:15 -05:00
parent b1c28856bb
commit 8e57feeeb9
193 changed files with 6172 additions and 4033 deletions

View File

@@ -1,13 +1,13 @@
Tcl/Tk Mac OS X README
Tcl/Tk macOS README
----------------------
This is the README file for the Mac OS X/Darwin version of Tcl/Tk.
This is the README file for the macOS/Darwin version of Tcl/Tk.
1. Where to go for support
--------------------------
- The tcl-mac mailing list on sourceforge is the best place to ask questions
specific to Tcl & Tk on Mac OS X:
specific to Tcl & Tk on macOS:
http://lists.sourceforge.net/lists/listinfo/tcl-mac
(this page also has a link to searchable archives of the list, please check them
before asking on the list, many questions have already been answered).
@@ -15,26 +15,26 @@ before asking on the list, many questions have already been answered).
- For general Tcl/Tk questions, the newsgroup comp.lang.tcl is your best bet:
http://groups.google.com/group/comp.lang.tcl/
- The Tcl'ers Wiki also has many pages dealing with Tcl & Tk on Mac OS X, see
- The Tcl'ers Wiki also has many pages dealing with Tcl & Tk on macOS, see
http://wiki.tcl.tk/_/ref?N=3753
http://wiki.tcl.tk/_/ref?N=8361
- Please report bugs with Tk on Mac OS X to the tracker:
- Please report bugs with Tk on macOS to the tracker:
http://core.tcl.tk/tk/reportlist
2. Using Tcl/Tk on Mac OS X
2. Using Tcl/Tk on macOS
---------------------------
- There are two versions of Tk available on Mac OS X: TkAqua using the native
- 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 Mac OS X).
available as an optional or default install on recent macOS).
TkAqua and TkX11 can be distinguished at runtime via [tk windowingsystem].
- At a minimum, Mac OS X 10.3 is required to run Tcl and TkX11.
TkAqua requires Mac OS X 10.5 or later (starting with the Cocoa-based Tk 8.5.7).
- At a minimum, macOS 10.3 is required to run Tcl and TkX11.
TkAqua requires macOS 10.6 or later.
- Unless weak-linking is used, Tcl/Tk built on Mac OS X 10.x will not run on
- Unless weak-linking is used, Tcl/Tk built on macOS 10.x will not run on
10.y with y < x; on the other hand Tcl/Tk built on 10.y will always run on 10.x
with y <= x (but without any of the fixes and optimizations that would be
available in a binary built on 10.x).
@@ -62,8 +62,7 @@ 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), and prior to Mac OS X 10.5, only bundles can be
[unload]ed.
native filesystem required).
- The 'deploy' target of macosx/GNUmakefile installs the html manpages into the
standard documentation location in the Tcl/Tk frameworks:
@@ -163,7 +162,7 @@ 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 Mac OS X-specific toplevel window class and attributes. Note that
get and set macOS-specific toplevel window class and attributes. Note that
the window class and many attributes have to be set before the window is first
mapped for the change to have any effect.
The command has the following syntax:
@@ -179,76 +178,42 @@ Window attribute names:
verticalZoom, closeBox, collapseBox, toolbarButton, sideTitlebar,
noTitleBar, unifiedTitleAndToolbar, metal, hud, noShadow, doesNotCycle,
noActivates, hideOnSuspend, inWindowMenu, ignoreClicks, doesNotHide,
canJoinAllSpaces, moveToActiveSpace, nonActivating, black, dark, light,
gray, red, green, blue, cyan, yellow, magenta, orange, purple,
brown, clear, opacity
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).
The color window attributes (black, dark, red, etc.) and the "opacity" allow one to set the background and opacity of a textured ("metal") window. This allows a Tk window to implement a window without the dividing line between the titlebar and the rest of the window, or the "unified toolbar" effect, which is increasingly standard in Mac applications. An example:
toplevel .f
tk::unsupported::MacWindowStyle style .f document {metal light opaque closeBox collapseBox resizable standardDocument }
pack [label .f.f -bg #ababab -text "This is a textured window\nwith opacity and a gray background\nsimilar to other Mac applications"] -fill both -expand yes
The color attributes correspond to system-defined NSColor constants (e.g., red is [NSColor redColor]. The "light" and "dark" attributes correspond to lightGrayColor and darkGrayColor, respectively (because of the way the attributes are parsed, using "lightgray" and "darkgray" would cause a conflict with the core "gray" attribute).
Below are the corresponding hex and/or Tk-defined colors that can be used from Tk widgets to match the NSColor-based attributes:
black #000000
dark #545454
light #ababab
white #ffffff
gray #7f7f7f
red #ff0000
green #00ff00
blue #0000ff
cyan #00ffff
yellow #ffff00
magenta #ff00ff
orange #ff8000
purple #800080
brown #996633
clear systemTransparent
- The Cocoa-based TkAqua can be distinguished from the older Carbon-based
version via the [winfo server .] command, example output on Mac OS X 10.5.7:
Cocoa-based: CG409.3 Apple AppKit GC 949.46 Mac OS X 1057
Carbon-based: QD10R30 Apple 1057
- If you want to use Remote Debugging with Xcode, you need to set the
If you want to use Remote Debugging with Xcode, you need to set the
environment variable XCNOSTDIN to 1 in the Executable editor for Wish. That will
cause us to force closing stdin & stdout. Otherwise, given how Xcode launches
Wish remotely, they will be left open and then Wish & gdb will fight for stdin.
3. Building Tcl/Tk on Mac OS X
3. Building Tcl/Tk on macOS
------------------------------
- At least Mac OS X 10.3 is required to build Tcl and TkX11, and Mac OS X 10.5
is required to build TkAqua.
Apple's Xcode Developer Tools need to be installed (only the most recent version
matching your OS release is supported), the Xcode installer is available on Mac
OS X install media or may be present in /Applications/Installers on Macs that
came with OS X preinstalled. The most recent version can always be downloaded
from the ADC website http://connect.apple.com (free ADC membership required).
- At least macOS 10.3 is required to build Tcl and TkX11, and macOS 10.6
is required to build TkAqua. The XCode application provides everything
needed to build Tk, but it is not necessary to install the full XCode.
It suffices to install the Command Line Tools package, which can be done
by running the command:
xcode-selecct --install
- Tcl/Tk are most easily built as Mac OS X frameworks via GNUmakefile in
- Tcl/Tk are most easily built as macOS frameworks via GNUmakefile in
tcl/macosx and tk/macosx (see below for details), but can also be built with the
standard unix configure and make buildsystem in tcl/unix resp. tk/unix as on any
other unix platform (indeed, the GNUmakefiles are just wrappers around the unix
buildsystem).
The Mac OS X specific configure flags are --enable-aqua, --enable-framework and
The macOS specific configure flags are --enable-aqua, --enable-framework and
--disable-corefoundation (which disables CF and notably reverts to the standard
select based notifier). Note that --enable-aqua is incompatible with
--disable-corefoundation (for both Tcl and Tk configure).
- It is also possible to build with the Xcode IDE via the projects in
tk/macosx, take care to use the project matching your DevTools and OS version:
- It was once possible to build with the Xcode IDE via the projects in
tk/macosx, but this has not been tested recently. Take care to use the
project matching your DevTools and OS version:
Tk.xcode: for Xcode 3.1 on 10.5
Tk.xcodeproj: for Xcode 3.2 on 10.6
These have the following targets:
@@ -292,7 +257,7 @@ 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 Mac OS X 10.4 and Xcode 2.4 (or Xcode 2.2 if -arch x86_64 is
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
@@ -303,9 +268,9 @@ 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.4
export MACOSX_DEPLOYMENT_TARGET=10.6
This requires at least gcc 3.1; with gcc 4 or later, set/add to CFLAGS instead:
export CFLAGS="-mmacosx-version-min=10.4"
export CFLAGS="-mmacosx-version-min=10.6"
Support for weak-linking was added with 8.4.14/8.5a5.
Detailed Instructions for building with macosx/GNUmakefile
@@ -389,21 +354,29 @@ 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. About the event loop in Tk for Mac OSX
-----------------------------------------
4. Details regarding the macOS port of Tk.
-------------------------------------------
The main program in a typical OSX application looks like this (see *)
4.1 About the event loop
~~~~~~~~~~~~~~~~~~~~~~~~
The main program in a typical OSX application looks like this (see
https://developer.apple.com/library/mac/documentation/Cocoa/\
Reference/ApplicationKit/Classes/NSApplication_Class)
void NSApplicationMain(int argc, char *argv[]) {
[NSApplication sharedApplication];
[NSBundle loadNibNamed:@"myMain" owner:NSApp];
[NSApp run];
}
Here NSApp is a standard global variable, initialized by the OS, which
points to an object in a subclass of NSApplication (called
TKApplication in the case of the macOS port of Tk).
The run method implements the event loop for the application. There
are three key steps in the run method. First it calls
[NSApp finishLaunching], which creates the bouncing application icon
and does other mysterious things. Second it creates an
The [NSApp run] method implements the event loop for a typical Mac
application. There are three key steps in the run method. First it
calls [NSApp finishLaunching], which creates the bouncing application
icon and does other mysterious things. Second it creates an
NSAutoreleasePool. Third, it starts an event loop which drains the
NSAutoreleasePool every time the queue is empty, and replaces the
drained pool with a new one. This third step is essential to
@@ -411,41 +384,180 @@ preventing memory leaks, since the internal methods of Appkit objects
all assume that an autorelease pool is in scope and will be drained
when the event processing cycle ends.
Mac OSX Tk does not call the [NSApp run] method at all. Instead it
uses the event loop built in to Tk. So we must take care to replicate
the important features of the method ourselves. Here is how this
works in outline.
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.
We add a private NSAUtoreleasePool* property to our subclass of
NSApplication. (The subclass is called TKApplication but can be
referenced with the global variable NSApp). The TkpInit
function calls [NSApp _setup] which initializes this property by
creating an NSAutoreleasePool. A bit later on, TkpInit calls
[NSAPP _setupEventLoop] which in turn calls the
[NSApp finishLaunching] method.
The Tcl event loop simply consists of repeated calls to TclDoOneEvent.
Each call to TclDoOneEvent begins by collecting all pending events from
an "event source", converting them to Tcl events and adding them
to the Tcl event queue. For macOS, the event source is the NSApp
object, which maintains an event queue even though its run method
will never be called to process them. The NSApp provides methods for
inspecting the queue and removing events from it as well as the
[NSApp sendevent] which sends an event to all of the application's
NSWindows which can then send it to subwindows, etc.
The event collection process consists of first calling a platform
specific SetupProc and then a platform specific CheckProc. In
the macOS port, these are named TkMacOSXEventsSetupProc and
TkMacOSXEventsCheckProc.
It is important to understand that the Apple window manager does not
have the concept of an expose event. Their replacement for an expose
event is to have the window manager call the [NSView drawRect] method
in any situation where an expose event for that NSView would be
generated in X11. The [NSView drawRect] method is a no-op which is
expected to be overridden by any application. In the case of Tcl, the
replacement [NSView drawRect] method creates a Tcl expose event
for each dirty rectangle of the NSView, and then adds the expose
event to the Tcl queue.
4.2 Autorelease pools
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order to carry out the job of managing autorelease pools, which
would normally be handled by the [NSApp run] method, a private
NSAUtoreleasePool* property is added to the TkApplication subclass of
NSApplication. The TkpInit function calls [NSApp _setup] which
initializes this property by creating an NSAutoreleasePool prior to
calling [NSApp finishLaunching]. This mimics the behavior of the
[NSApp run] method, which calls [NSApp finishLaunching] just before
starting the event loop.
Each time that Tcl processes an event in its queue, it calls a
platform specific function which, in the case of Mac OSX, is named
TkMacOSXEventsCheckProc. In the unix implementations of Tk, including
the Mac OSX version, this function collects events from an "event
source", and transfers them to the Tcl event queue. In Mac OSX the
event source is the NSApplication event queue. Each NSEvent is
converted to a Tcl event which is added to the Tcl event queue. The
NSEvent is also passed to [NSApp sendevent], which sends the event on
to the application's NSWindows, which send it to their NSViews, etc.
Since the CheckProc function gets called for every Tk event, it is an
appropriate place to drain the main NSAutoreleasePool and replace it
with a new pool. This is done by calling the method
[NSApp _resetAutoreleasePool], where _resetAutoreleasePool is a method
which we define for the subclass TKApplication.
with a new pool. This is done by calling the method [NSApp
_resetAutoreleasePool], where _resetAutoreleasePool is a method which
we define for the subclass. Unfortunately, by itself this is not
sufficient for safe memory managememt because, as was made painfully
evident with the release of OS X 10.13, it is possible for calls to
TclDoOneEvent, and hence to CheckProc, to be nested. Draining the
autorelease pool in a nested call leads to crashes as objects in use
by the outer call can get freed by the inner call and then reused later.
One particular situation where this happens is when a modal dialogue
gets posted by a Tk Application. To address this, the NSApp object
also implements a semaphore to prevent draining the autorelease pool
in nested calls to CheckProc.
One minor caveat is that there are several steps of the Tk
initialization which precede the call to TkpInit. Notably, the font
package is initialized first. Since there is no NSAUtoreleasePool in
scope prior to calling TkpInit, the functions called in these
preliminary stages need to create and drain their own
One additional minor caveat for developers is that there are several
steps of the Tk initialization which precede the call to TkpInit.
Notably, the font package is initialized first. Since there is no
NSAUtoreleasePool in scope prior to calling TkpInit, the functions
called in these preliminary stages need to create and drain their own
NSAutoreleasePools whenever they call methods of Appkit objects
(e.g. NSFont).
* https://developer.apple.com/library/mac/documentation/Cocoa/\
Reference/ApplicationKit/Classes/NSApplication_Class
4.3 Clipping regions and "ghost windows"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Another unusual aspect of the macOS port is its use of clipping
regions. It was part of Daniel Steffen's original design that the
TkWindowPrivate struct maintains three HIShapeRef regions, named
visRgn, aboveVisRgn and drawRgn. These regions are used as clipping
masks whenever drawing into an NSView. The visRgn is the bounding box
of the window with a rectangle removed for each subwindow and for each
sibling window at a higher stacking level. The drawRgn is the
intersection of the visRgn with the clipping rectangle of the
window. (Normally, the clipping rectangle is the same as the bounding
rectangle, but drawing can be clipped to a smaller rectangle by
calling TkpClipDrawableToRect.) The aboveVisRgn is the intersection of
the window's bounding rectangle with the bounding rectangle of the
parent window. Much of the code in tkMacOSXSubindows.c is devoted to
rebuilding these clipping regions whenever something changes in the
layout of the windows. This turns out to be a tricky thing to do and
it is extremely prone to errors which can be difficult to trace.
It is not entirely clear what the original reason for using these
clipping regions was. But one benefit is that if they are correctly
maintained then it allows windows to be drawn in any order. You do
not have to draw them in the order of the window hierarchy. Each
window can draw its entire rectangle through its own mask and never
have to worry about drawing in the wrong place. It is likely that
the need for using clipping regions arose because, as Apple explicitly
states in the documentation for [NSView subviews],
"The order of the subviews may be considered as being
back-to-front, but this does not imply invalidation and drawing
behavior."
In the early versions of the macOS port, buttons were implemented as
subviews of class TkButton. This probably exacerbated the likelihood
that Tk windows would need to be drawn in arbitrary order.
The most obvious side effect caused by not maintaining the clipping
regions is the appearance of so-called "ghost windows". A common
situation where these may arise is when a window containing buttons
is being scrolled. A user may see two images of the same button on
the screen, one in the pre-scroll location and one in the post-scroll
location.
To see how these 'ghost windows' can arise, think about what happens if
the clipping regions are not maintained correctly. A window might
have a rectangle missing from its clipping region because that
rectangle is the bounding rectangle for a subwindow, say a button.
The parent should not draw in the missing rectangle since doing so
would trash the button. The button is responsible for drawing
there. Now imagine that the button gets moved, say by a scroll, but
the missing rectangle in the parent's clipping region does not get
moved correctly, or it gets moved later on, after the parent has
redrawn itself. The parent would still not be allowed to draw in the
old rectangle, so the user would continue to see the image of the
button in its old location, as well as another image in the new
location. This is a prototypical example of a "ghost window".
Anytime you see a "ghost window", you should suspect problems with the
updates to the clipping region visRgn. It is natural to look for
timing issues, race conditions, or other "event loop problems". But
in fact, the whole design of the code is to make those timing issues
irrelevant. As long as the clipping regions are correctly maintained
the timing does not matter. And if they are not correctly maintained
then you will see "ghost windows".
It is worth including a detailed description of one specific place
where the failure to correctly maintain clipping regions caused "ghost
window" artifacts that plagued the macOS port for years. These
occurred when scrolling a Text widget which contained embedded
subwindows. It involved some specific differences between the
low-level behavior of Apple's window manager versus those of the other
platforms, and the fix ultimately required changes in the generic Tk
implementation (documented in the comments in the DisplayText
function).
The Text widget attempts to improve perfomance when scrolling by
minimizing the number of text lines which need to be redisplayed. It
does this by calling the platform-specific TkScrollWindow function
which uses a low-level routine to map one rectangle of the window to
another. The TkScrollWindow function returns a damage region which is
then used by the Text widget's DisplayText function to determine which
text lines need to be redrawn. On the unix and win platforms, this
damage region includes bounding rectangles for all embedded windows
inside the Text widget. The way that this works is system dependent.
On unix, the low level scrolling is done by XCopyRegion, which
generates a GraphicsExpose event for each embedded window. These
GraphicsExposed events are processsed within TkScrollWindow, using a
special handler which adds the bounding rectangle of each subwindow to
the damage region. On the win platform the damage region is built by
the low level function ScrollWindowEx, and it also includes bounding
rectangles for all embedded windows. This is possible because on X11
and Windows every Tk widget is also known to the window manager as a
window. The situation is different on macOS. The underlying object
for a top level window on macOS is the NSView. However, Apple
explicitly warns in its documentation that performance degradation
occurs when an NSView has more than about 100 subviews. A Text widget
with thousands of lines of text could easily contain more than 100
embedded windows. In fact, while the original Cocoa port of Tk did
use the NSButton object, which is derived from NSView, as the basis
for its Tk Buttons, that was changed in order to improve performance.
Moreover, the low level routine used for scrolling on macOS, namely
[NSView scrollrect:by], does not provide any damage information. So
TkScrollWindow needs to work differently on macOS. Since it would be
inefficient to iterate through all embedded windows in a Text widget,
looking for those which meet the scrolling area, the damage region
constructed by TkScrollWindow contains only the difference between the
source and destination rectangles for the scrolling. The embedded
windows are redrawn within the DisplayText function by some
conditional code which is only used for macOS.

View File

@@ -1212,7 +1212,6 @@
F966BC9508F27A3D005CB29B /* buildall.vc.bat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = buildall.vc.bat; sourceTree = "<group>"; };
F966BC9608F27A3E005CB29B /* configure */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = configure; sourceTree = "<group>"; };
F966BC9708F27A3E005CB29B /* configure.in */ = {isa = PBXFileReference; explicitFileType = text.script.sh; fileEncoding = 4; path = configure.in; sourceTree = "<group>"; };
F966BC9808F27A3E005CB29B /* makefile.bc */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = makefile.bc; sourceTree = "<group>"; };
F966BC9908F27A3E005CB29B /* Makefile.in */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = Makefile.in; sourceTree = "<group>"; };
F966BC9A08F27A3E005CB29B /* makefile.vc */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = makefile.vc; sourceTree = "<group>"; };
F966BC9B08F27A3E005CB29B /* mkd.bat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mkd.bat; sourceTree = "<group>"; };
@@ -1984,10 +1983,8 @@
F96D447008F272BA004A47F5 /* aclocal.m4 */ = {isa = PBXFileReference; explicitFileType = text.script.sh; fileEncoding = 4; path = aclocal.m4; sourceTree = "<group>"; };
F96D447108F272BA004A47F5 /* buildall.vc.bat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = buildall.vc.bat; sourceTree = "<group>"; };
F96D447208F272BA004A47F5 /* cat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cat.c; sourceTree = "<group>"; };
F96D447308F272BA004A47F5 /* coffbase.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = coffbase.txt; sourceTree = "<group>"; };
F96D447408F272BA004A47F5 /* configure */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = configure; sourceTree = "<group>"; };
F96D447508F272BA004A47F5 /* configure.in */ = {isa = PBXFileReference; explicitFileType = text.script.sh; fileEncoding = 4; path = configure.in; sourceTree = "<group>"; };
F96D447608F272BA004A47F5 /* makefile.bc */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = makefile.bc; sourceTree = "<group>"; };
F96D447708F272BA004A47F5 /* Makefile.in */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = Makefile.in; sourceTree = "<group>"; };
F96D447808F272BA004A47F5 /* makefile.vc */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = makefile.vc; sourceTree = "<group>"; };
F96D447908F272BA004A47F5 /* nmakehlp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nmakehlp.c; sourceTree = "<group>"; };
@@ -2791,7 +2788,6 @@
F966BC9508F27A3D005CB29B /* buildall.vc.bat */,
F966BC9608F27A3E005CB29B /* configure */,
F966BC9708F27A3E005CB29B /* configure.in */,
F966BC9808F27A3E005CB29B /* makefile.bc */,
F966BC9908F27A3E005CB29B /* Makefile.in */,
F966BC9A08F27A3E005CB29B /* makefile.vc */,
F966BC9B08F27A3E005CB29B /* mkd.bat */,
@@ -3819,10 +3815,8 @@
F96D447008F272BA004A47F5 /* aclocal.m4 */,
F96D447108F272BA004A47F5 /* buildall.vc.bat */,
F96D447208F272BA004A47F5 /* cat.c */,
F96D447308F272BA004A47F5 /* coffbase.txt */,
F96D447408F272BA004A47F5 /* configure */,
F96D447508F272BA004A47F5 /* configure.in */,
F96D447608F272BA004A47F5 /* makefile.bc */,
F96D447708F272BA004A47F5 /* Makefile.in */,
F96D447808F272BA004A47F5 /* makefile.vc */,
F96D447908F272BA004A47F5 /* nmakehlp.c */,

View File

@@ -1212,7 +1212,6 @@
F966BC9508F27A3D005CB29B /* buildall.vc.bat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = buildall.vc.bat; sourceTree = "<group>"; };
F966BC9608F27A3E005CB29B /* configure */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = configure; sourceTree = "<group>"; };
F966BC9708F27A3E005CB29B /* configure.in */ = {isa = PBXFileReference; explicitFileType = text.script.sh; fileEncoding = 4; path = configure.in; sourceTree = "<group>"; };
F966BC9808F27A3E005CB29B /* makefile.bc */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = makefile.bc; sourceTree = "<group>"; };
F966BC9908F27A3E005CB29B /* Makefile.in */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = Makefile.in; sourceTree = "<group>"; };
F966BC9A08F27A3E005CB29B /* makefile.vc */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = makefile.vc; sourceTree = "<group>"; };
F966BC9B08F27A3E005CB29B /* mkd.bat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mkd.bat; sourceTree = "<group>"; };
@@ -1984,10 +1983,8 @@
F96D447008F272BA004A47F5 /* aclocal.m4 */ = {isa = PBXFileReference; explicitFileType = text.script.sh; fileEncoding = 4; path = aclocal.m4; sourceTree = "<group>"; };
F96D447108F272BA004A47F5 /* buildall.vc.bat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = buildall.vc.bat; sourceTree = "<group>"; };
F96D447208F272BA004A47F5 /* cat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cat.c; sourceTree = "<group>"; };
F96D447308F272BA004A47F5 /* coffbase.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = coffbase.txt; sourceTree = "<group>"; };
F96D447408F272BA004A47F5 /* configure */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = configure; sourceTree = "<group>"; };
F96D447508F272BA004A47F5 /* configure.in */ = {isa = PBXFileReference; explicitFileType = text.script.sh; fileEncoding = 4; path = configure.in; sourceTree = "<group>"; };
F96D447608F272BA004A47F5 /* makefile.bc */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = makefile.bc; sourceTree = "<group>"; };
F96D447708F272BA004A47F5 /* Makefile.in */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = Makefile.in; sourceTree = "<group>"; };
F96D447808F272BA004A47F5 /* makefile.vc */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = makefile.vc; sourceTree = "<group>"; };
F96D447908F272BA004A47F5 /* nmakehlp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nmakehlp.c; sourceTree = "<group>"; };
@@ -2791,7 +2788,6 @@
F966BC9508F27A3D005CB29B /* buildall.vc.bat */,
F966BC9608F27A3E005CB29B /* configure */,
F966BC9708F27A3E005CB29B /* configure.in */,
F966BC9808F27A3E005CB29B /* makefile.bc */,
F966BC9908F27A3E005CB29B /* Makefile.in */,
F966BC9A08F27A3E005CB29B /* makefile.vc */,
F966BC9B08F27A3E005CB29B /* mkd.bat */,
@@ -3819,10 +3815,8 @@
F96D447008F272BA004A47F5 /* aclocal.m4 */,
F96D447108F272BA004A47F5 /* buildall.vc.bat */,
F96D447208F272BA004A47F5 /* cat.c */,
F96D447308F272BA004A47F5 /* coffbase.txt */,
F96D447408F272BA004A47F5 /* configure */,
F96D447508F272BA004A47F5 /* configure.in */,
F96D447608F272BA004A47F5 /* makefile.bc */,
F96D447708F272BA004A47F5 /* Makefile.in */,
F96D447808F272BA004A47F5 /* makefile.vc */,
F96D447908F272BA004A47F5 /* nmakehlp.c */,

View File

@@ -69,7 +69,7 @@
<key>CFBundleVersion</key>
<string>@TK_VERSION@@TK_PATCH_LEVEL@</string>
<key>LSMinimumSystemVersion</key>
<string>10.5.0</string>
<string>10.6.0</string>
<key>LSRequiresCarbon</key>
<true/>
<key>NSAppleScriptEnabled</key>

64
macosx/configure vendored Normal file → Executable file
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=".6"
TK_PATCH_LEVEL=".8"
VERSION=${TK_VERSION}
LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv"
@@ -2376,8 +2376,9 @@ $as_echo "$as_me: WARNING: --with-tcl argument should refer to directory contain
for i in `ls -d ${libdir} 2>/dev/null` \
`ls -d ${exec_prefix}/lib 2>/dev/null` \
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
; do
@@ -4706,8 +4707,10 @@ fi
PLAT_OBJS=""
PLAT_SRCS=""
LDAIX_SRC=""
if test x"${SHLIB_VERSION}" = x; then :
SHLIB_VERSION="1.0"
if test "x${SHLIB_VERSION}" = x; then :
SHLIB_VERSION=".1.0"
else
SHLIB_VERSION=".${SHLIB_VERSION}"
fi
case $system in
AIX-*)
@@ -5364,46 +5367,25 @@ fi
OpenBSD-*)
arch=`arch -s`
case "$arch" in
vax)
# Equivalent using configure option --disable-load
# Step 4 will set the necessary variables
DL_OBJS=""
SHLIB_LD_LIBS=""
LDFLAGS=""
alpha|sparc64)
SHLIB_CFLAGS="-fPIC"
;;
*)
case "$arch" in
alpha|sparc|sparc64)
SHLIB_CFLAGS="-fPIC"
;;
*)
SHLIB_CFLAGS="-fpic"
;;
esac
SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
SHLIB_SUFFIX=".so"
DL_OBJS="tclLoadDl.o"
DL_LIBS=""
if test $doRpath = yes; then :
SHLIB_CFLAGS="-fpic"
;;
esac
SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
SHLIB_SUFFIX=".so"
DL_OBJS="tclLoadDl.o"
DL_LIBS=""
if test $doRpath = yes; then :
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
fi
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}'
LDFLAGS="-Wl,-export-dynamic"
;;
esac
case "$arch" in
vax)
CFLAGS_OPTIMIZE="-O1"
;;
sh)
CFLAGS_OPTIMIZE="-O0"
;;
*)
CFLAGS_OPTIMIZE="-O2"
;;
esac
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}'
LDFLAGS="-Wl,-export-dynamic"
CFLAGS_OPTIMIZE="-O2"
if test "${TCL_THREADS}" = "1"; then :
# On OpenBSD: Compile with -pthread
@@ -5938,7 +5920,7 @@ fi
# requires an extra version number at the end of .so file names.
# So, the library has to have a name like libtcl75.so.1.0
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}'
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}'
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
TCL_LIB_VERSIONS_OK=nodots
;;

View File

@@ -12,7 +12,7 @@
*/
#include "tkMacOSXPrivate.h"
#include "tkMacOSXConstants.h"
/*
* This structure holds information about native bitmaps.
*/
@@ -298,7 +298,7 @@ TkpGetNativeAppBitmap(
string = [NSString stringWithUTF8String:name];
image = [NSImage imageNamed:string];
if (!image) {
NSURL *url = [NSURL URLWithString:string];
NSURL *url = [NSURL fileURLWithPath:string];
if (url) {
image = [[[NSImage alloc] initWithContentsOfURL:url]
autorelease];

View File

@@ -364,7 +364,8 @@ TkpComputeButtonGeometry(
height = butPtr->height > 0 ? butPtr->height : height;
} else { /* Text only */
width = txtWidth + butPtr->indicatorSpace;
/*Add four pixels of padding to width for text-only buttons to improve appearance.*/
width = txtWidth + butPtr->indicatorSpace + 4;
height = txtHeight;
if (butPtr->width > 0) {
width = butPtr->width * charWidth;

View File

@@ -266,13 +266,9 @@ GetThemeColor(
break;
}
// this attempts to find something roughly fitting for any display
// *c = CGColorCreateGenericRGB(rgba[0], rgba[1], rgba[2], rgba[3]);
// may be off for non-main display but in most cases better than prev
static CGColorSpaceRef deviceRGBSpace = NULL;
if (!deviceRGBSpace) {
deviceRGBSpace = CGDisplayCopyColorSpace(CGMainDisplayID());
deviceRGBSpace = CGColorSpaceCreateDeviceRGB();
}
*c = CGColorCreate(deviceRGBSpace, rgba );
}

View File

@@ -325,11 +325,6 @@
#define DEF_MENU_SELECT_COLOR "systemMenuActive"
#define DEF_MENU_SELECT_MONO BLACK
#define DEF_MENU_TAKE_FOCUS "0"
/*
* FIXME: Turn the default back to 1 when we make tearoff menus work again.
*/
#define DEF_MENU_TEAROFF "0"
#define DEF_MENU_TEAROFF_CMD ((char *) NULL)
#define DEF_MENU_TITLE ""

View File

@@ -6,6 +6,7 @@
* Copyright (c) 1996-1997 Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
* Copyright (c) 2017 Christian Gollwitzer.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -13,6 +14,7 @@
#include "tkMacOSXPrivate.h"
#include "tkFileFilter.h"
#include "tkMacOSXConstants.h"
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
#define modalOK NSOKButton
@@ -24,6 +26,27 @@
#define modalOther -1
#define modalError -2
/*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
} filepanelFilterInfo;
filepanelFilterInfo filterInfo;
NSOpenPanel *openpanel;
NSSavePanel *savepanel;
static const char *const colorOptionStrings[] = {
"-initialcolor", "-parent", "-title", NULL
@@ -146,18 +169,16 @@ static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = {
* Construct a file URL from directory and filename. Either may
* be nil. If both are nil, returns nil.
*/
#if MAC_OS_X_VERSION_MIN_REQUIRED > 1050
static NSURL *getFileURL(NSString *directory, NSString *filename) {
NSURL *url = nil;
if (directory) {
url = [NSURL fileURLWithPath:directory];
url = [NSURL fileURLWithPath:directory isDirectory:YES];
}
if (filename) {
url = [NSURL URLWithString:filename relativeToURL:url];
}
return url;
}
#endif
#pragma mark TKApplication(TKDialog)
@@ -172,7 +193,7 @@ static NSURL *getFileURL(NSString *directory, NSString *filename) {
{
FilePanelCallbackInfo *callbackInfo = contextInfo;
if (returnCode == NSFileHandlingPanelOKButton) {
if (returnCode == modalOK) {
Tcl_Obj *resultObj;
if (callbackInfo->multiple) {
@@ -200,7 +221,7 @@ static NSURL *getFileURL(NSString *directory, NSString *filename) {
} else {
Tcl_SetObjResult(callbackInfo->interp, resultObj);
}
} else if (returnCode == NSFileHandlingPanelCancelButton) {
} else if (returnCode == modalCancel) {
Tcl_ResetResult(callbackInfo->interp);
}
if (panel == [NSApp modalWindow]) {
@@ -212,6 +233,7 @@ static NSURL *getFileURL(NSString *directory, NSString *filename) {
}
}
- (void) tkAlertDidEnd: (NSAlert *) alert returnCode: (NSInteger) returnCode
contextInfo: (void *) contextInfo
{
@@ -247,6 +269,42 @@ static NSURL *getFileURL(NSString *directory, NSString *filename) {
ckfree(callbackInfo);
}
}
- (void)selectFormat:(id)sender {
NSPopUpButton *button = (NSPopUpButton *)sender;
filterInfo.fileTypeIndex = [button indexOfSelectedItem];
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 */
[openpanel setAllowedFileTypes:nil];
} else {
NSMutableArray *allowedtypes = [filterInfo.fileTypeExtensions objectAtIndex:filterInfo.fileTypeIndex];
[openpanel setAllowedFileTypes:allowedtypes];
[openpanel setAllowsOtherFileTypes:NO];
}
filterInfo.userHasSelectedFilter = true;
}
- (void)saveFormat:(id)sender {
NSPopUpButton *button = (NSPopUpButton *)sender;
filterInfo.fileTypeIndex = [button indexOfSelectedItem];
if ([[filterInfo.fileTypeAllowsAll objectAtIndex:filterInfo.fileTypeIndex] boolValue]) {
[savepanel setAllowsOtherFileTypes:YES];
[savepanel setAllowedFileTypes:nil];
} else {
NSMutableArray *allowedtypes = [filterInfo.fileTypeExtensions objectAtIndex:filterInfo.fileTypeIndex];
[savepanel setAllowedFileTypes:allowedtypes];
[savepanel setAllowsOtherFileTypes:NO];
}
filterInfo.userHasSelectedFilter = true;
}
@end
#pragma mark -
@@ -339,7 +397,7 @@ Tk_ChooseColorObjCmd(
returnCode = [NSApp runModalForWindow:colorPanel];
if (returnCode == modalOK) {
color = [[colorPanel color] colorUsingColorSpace:
[NSColorSpace genericRGBColorSpace]];
[NSColorSpace deviceRGBColorSpace]];
numberOfComponents = [color numberOfComponents];
}
if (color && numberOfComponents >= 3 && numberOfComponents <= 4) {
@@ -360,6 +418,120 @@ Tk_ChooseColorObjCmd(
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) {
if (!fileTypesPtr) {
filterInfo.doFileTypes = false;
return TCL_OK;
}
FileFilterList fl;
TkInitFileFilters(&fl);
if (TkGetFileFilters(interp, &fl, fileTypesPtr, 0) != TCL_OK) {
TkFreeFileFilters(&fl);
return TCL_ERROR;
}
filterInfo.doFileTypes = (fl.filters != NULL);
filterInfo.fileTypeIndex = 0;
filterInfo.fileTypeExtensions = [NSMutableArray array];
filterInfo.fileTypeNames = [NSMutableArray array];
filterInfo.fileTypeLabels = [NSMutableArray array];
filterInfo.fileTypeAllowsAll = [NSMutableArray array];
filterInfo.allowedExtensions = [NSMutableArray array];
filterInfo.allowedExtensionsAllowAll = NO;
if (filterInfo.doFileTypes) {
for (FileFilter *filterPtr = fl.filters; filterPtr;
filterPtr = filterPtr->next) {
NSString * name = [[NSString alloc] initWithUTF8String: filterPtr -> name];
[filterInfo.fileTypeNames addObject:name];
[name release];
NSMutableArray * clauseextensions = [NSMutableArray array];
NSMutableArray * displayextensions = [NSMutableArray array];
bool allowsAll = NO;
for (FileFilterClause *clausePtr = filterPtr->clauses; clausePtr;
clausePtr = clausePtr->next) {
for (GlobPattern *globPtr = clausePtr->patterns; globPtr;
globPtr = globPtr->next) {
const char *str = globPtr->pattern;
while (*str && (*str == '*' || *str == '.')) {
str++;
}
if (*str) {
NSString *extension = [[NSString alloc] initWithUTF8String:str];
if (![filterInfo.allowedExtensions containsObject:extension]) {
[filterInfo.allowedExtensions addObject:extension];
}
[clauseextensions addObject:extension];
[displayextensions addObject:[@"." stringByAppendingString:extension]];
[extension release];
} else {
// it is the all pattern (*, .* or *.*)
allowsAll = YES;
filterInfo.allowedExtensionsAllowAll = YES;
[displayextensions addObject:@"*"];
}
}
}
[filterInfo.fileTypeExtensions addObject:clauseextensions];
[filterInfo.fileTypeAllowsAll addObject:[NSNumber numberWithBool:allowsAll]];
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 */
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);
/* 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];
if (index != NSNotFound) {
filterInfo.fileTypeIndex = index;
filterInfo.preselectFilter = true;
}
}
}
}
TkFreeFileFilters(&fl);
return TCL_OK;
}
bool filterCompatible(NSString *extension, int filterIndex) {
NSMutableArray *allowedExtensions = [filterInfo.fileTypeExtensions objectAtIndex: filterIndex];
/* If this contains the all pattern, accept any extension */
if ([[filterInfo.fileTypeAllowsAll objectAtIndex:filterIndex] boolValue]) {
return true;
}
return [allowedExtensions containsObject: extension];
}
/*
*----------------------------------------------------------------------
@@ -388,19 +560,16 @@ Tk_GetOpenFileObjCmd(
char *str;
int i, result = TCL_ERROR, haveParentOption = 0;
int index, len, multiple = 0;
FileFilterList fl;
Tcl_Obj *cmdObj = NULL, *typeVariablePtr = NULL;
Tcl_Obj *cmdObj = NULL, *typeVariablePtr = NULL, *fileTypesPtr = NULL;
FilePanelCallbackInfo callbackInfoStruct;
FilePanelCallbackInfo *callbackInfo = &callbackInfoStruct;
NSString *directory = nil, *filename = nil;
NSString *message, *title, *type;
NSString *message = nil, *title = nil;
NSWindow *parent;
NSMutableArray *fileTypes = nil;
NSOpenPanel *panel = [NSOpenPanel openPanel];
openpanel = [NSOpenPanel openPanel];
NSInteger modalReturnCode = modalError;
BOOL parentIsKey = NO;
TkInitFileFilters(&fl);
for (i = 1; i < objc; i += 2) {
if (Tcl_GetIndexFromObjStruct(interp, objv[i], openOptionStrings,
sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
@@ -416,9 +585,7 @@ Tk_GetOpenFileObjCmd(
case OPEN_DEFAULT:
break;
case OPEN_FILETYPES:
if (TkGetFileFilters(interp, &fl, objv[i + 1], 0) != TCL_OK) {
goto end;
}
fileTypesPtr = objv[i + 1];
break;
case OPEN_INITDIR:
str = Tcl_GetStringFromObj(objv[i + 1], &len);
@@ -437,8 +604,6 @@ Tk_GetOpenFileObjCmd(
case OPEN_MESSAGE:
message = [[NSString alloc] initWithUTF8String:
Tcl_GetString(objv[i + 1])];
[panel setMessage:message];
[message release];
break;
case OPEN_MULTIPLE:
if (Tcl_GetBooleanFromObj(interp, objv[i + 1],
@@ -457,8 +622,6 @@ Tk_GetOpenFileObjCmd(
case OPEN_TITLE:
title = [[NSString alloc] initWithUTF8String:
Tcl_GetString(objv[i + 1])];
[panel setTitle:title];
[title release];
break;
case OPEN_TYPEVARIABLE:
typeVariablePtr = objv[i + 1];
@@ -468,40 +631,76 @@ Tk_GetOpenFileObjCmd(
break;
}
}
[panel setAllowsMultipleSelection:multiple];
if (fl.filters) {
fileTypes = [NSMutableArray array];
for (FileFilter *filterPtr = fl.filters; filterPtr;
filterPtr = filterPtr->next) {
for (FileFilterClause *clausePtr = filterPtr->clauses; clausePtr;
clausePtr = clausePtr->next) {
for (GlobPattern *globPtr = clausePtr->patterns; globPtr;
globPtr = globPtr->next) {
str = globPtr->pattern;
while (*str && (*str == '*' || *str == '.')) {
str++;
}
if (*str) {
type = [[NSString alloc] initWithUTF8String:str];
if (![fileTypes containsObject:type]) {
[fileTypes addObject:type];
}
[type release];
}
}
for (MacFileType *mfPtr = clausePtr->macTypes; mfPtr;
mfPtr = mfPtr->next) {
if (mfPtr->type) {
type = NSFileTypeForHFSTypeCode(mfPtr->type);
if (![fileTypes containsObject:type]) {
[fileTypes addObject:type];
}
}
}
}
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*/
if (message) {
NSString *fullmessage = [[NSString alloc] initWithFormat:@"%@\n%@",title,message];
[message release];
[title release];
message = fullmessage;
} else {
message = title;
}
}
[panel setAllowedFileTypes:fileTypes];
if (message) {
[openpanel setMessage:message];
[message release];
}
[openpanel setAllowsMultipleSelection:multiple];
if (parseFileFilters(interp, fileTypesPtr, typeVariablePtr) != TCL_OK) {
goto end;
}
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)];
[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 */
[popupButton selectItemAtIndex:filterInfo.fileTypeIndex];
/* on OSX > 10.11, the optons 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 */
[openpanel setAllowsOtherFileTypes:YES];
}
if (cmdObj) {
callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo));
if (Tcl_IsShared(cmdObj)) {
@@ -509,59 +708,95 @@ Tk_GetOpenFileObjCmd(
}
Tcl_IncrRefCount(cmdObj);
}
callbackInfo->cmdObj = cmdObj;
callbackInfo->interp = interp;
callbackInfo->multiple = multiple;
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
if (haveParentOption && parent && ![parent attachedSheet]) {
parentIsKey = [parent isKeyWindow];
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
[panel beginSheetForDirectory:directory
file:filename
types:fileTypes
modalForWindow:parent
modalDelegate:NSApp
didEndSelector:
@selector(tkFilePanelDidEnd:returnCode:contextInfo:)
contextInfo:callbackInfo];
#else
[panel setAllowedFileTypes:fileTypes];
[panel setDirectoryURL:getFileURL(directory, filename)];
[panel beginSheetModalForWindow:parent
parentIsKey = [parent isKeyWindow];
if (directory || filename ) {
NSURL * fileURL = getFileURL(directory, filename);
[openpanel setDirectoryURL:fileURL];
}
[openpanel beginSheetModalForWindow:parent
completionHandler:^(NSInteger returnCode)
{ [NSApp tkFilePanelDidEnd:panel
{ [NSApp tkFilePanelDidEnd:openpanel
returnCode:returnCode
contextInfo:callbackInfo ]; } ];
#endif
modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:panel];
modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:openpanel];
} else {
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
modalReturnCode = [panel runModalForDirectory:directory
file:filename];
#else
[panel setDirectoryURL:getFileURL(directory, filename)];
modalReturnCode = [panel runModal];
#endif
[NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode
if (directory || filename ) {
NSURL * fileURL = getFileURL(directory, filename);
[openpanel setDirectoryURL:fileURL];
}
modalReturnCode = [openpanel runModal];
[NSApp tkFilePanelDidEnd:openpanel returnCode:modalReturnCode
contextInfo:callbackInfo];
}
result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR;
if (parentIsKey) {
[parent makeKeyWindow];
}
if (typeVariablePtr && result == TCL_OK) {
/*
* The -typevariable option is not really supported.
*/
Tcl_SetVar2(interp, Tcl_GetString(typeVariablePtr), NULL,
"", TCL_GLOBAL_ONLY);
if ((typeVariablePtr && (modalReturnCode == NSOKButton)) &&
filterInfo.doFileTypes) {
/*
* The -typevariable must be set to the selected file type, if the dialog was not cancelled
*/
NSInteger 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 */
NSURL *selectedFile;
if (multiple) {
// 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];
if (filterInfo.preselectFilter &&
filterCompatible(extension, filterInfo.fileTypeIndex)) {
selectedFilterIndex = filterInfo.fileTypeIndex; // The preselection from the typevariable
selectedFilter = [filterInfo.fileTypeNames objectAtIndex:selectedFilterIndex];
} else {
// scan the list
int i;
for (i = 0; i < [filterInfo.fileTypeNames count]; i++) {
if (filterCompatible(extension, i)) {
selectedFilterIndex = i;
break;
}
}
if (i == selectedFilterIndex) {
selectedFilter = [filterInfo.fileTypeNames objectAtIndex:selectedFilterIndex];
} else {
selectedFilter = @"";
}
}
}
Tcl_ObjSetVar2(interp, typeVariablePtr, NULL,
Tcl_NewStringObj([selectedFilter UTF8String], -1), TCL_GLOBAL_ONLY);
}
end:
TkFreeFileFilters(&fl);
return result;
}
/*
*----------------------------------------------------------------------
@@ -591,19 +826,16 @@ Tk_GetSaveFileObjCmd(
int i, result = TCL_ERROR, haveParentOption = 0;
int confirmOverwrite = 1;
int index, len;
FileFilterList fl;
Tcl_Obj *cmdObj = NULL;
Tcl_Obj *cmdObj = NULL, *typeVariablePtr = NULL, *fileTypesPtr = NULL;
FilePanelCallbackInfo callbackInfoStruct;
FilePanelCallbackInfo *callbackInfo = &callbackInfoStruct;
NSString *directory = nil, *filename = nil, *defaultType = nil;
NSString *message, *title, *type;
NSString *message = nil, *title = nil;
NSWindow *parent;
NSMutableArray *fileTypes = nil;
NSSavePanel *panel = [NSSavePanel savePanel];
savepanel = [NSSavePanel savePanel];
NSInteger modalReturnCode = modalError;
BOOL parentIsKey = NO;
TkInitFileFilters(&fl);
for (i = 1; i < objc; i += 2) {
if (Tcl_GetIndexFromObjStruct(interp, objv[i], saveOptionStrings,
sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
@@ -616,96 +848,127 @@ Tk_GetSaveFileObjCmd(
goto end;
}
switch (index) {
case SAVE_DEFAULT:
str = Tcl_GetStringFromObj(objv[i + 1], &len);
while (*str && (*str == '*' || *str == '.')) {
str++;
}
if (*str) {
defaultType = [[[NSString alloc] initWithUTF8String:str]
autorelease];
}
break;
case SAVE_FILETYPES:
if (TkGetFileFilters(interp, &fl, objv[i + 1], 0) != TCL_OK) {
goto end;
}
break;
case SAVE_INITDIR:
str = Tcl_GetStringFromObj(objv[i + 1], &len);
if (len) {
directory = [[[NSString alloc] initWithUTF8String:str]
autorelease];
}
break;
case SAVE_INITFILE:
str = Tcl_GetStringFromObj(objv[i + 1], &len);
if (len) {
filename = [[[NSString alloc] initWithUTF8String:str]
autorelease];
}
break;
case SAVE_MESSAGE:
message = [[NSString alloc] initWithUTF8String:
Tcl_GetString(objv[i + 1])];
[panel setMessage:message];
[message release];
break;
case SAVE_PARENT:
str = Tcl_GetStringFromObj(objv[i + 1], &len);
tkwin = Tk_NameToWindow(interp, str, tkwin);
if (!tkwin) {
goto end;
}
haveParentOption = 1;
break;
case SAVE_TITLE:
title = [[NSString alloc] initWithUTF8String:
Tcl_GetString(objv[i + 1])];
[panel setTitle:title];
[title release];
break;
case SAVE_TYPEVARIABLE:
break;
case SAVE_COMMAND:
cmdObj = objv[i+1];
break;
case SAVE_CONFIRMOW:
if (Tcl_GetBooleanFromObj(interp, objv[i + 1],
&confirmOverwrite) != TCL_OK) {
goto end;
}
break;
}
}
if (fl.filters || defaultType) {
fileTypes = [NSMutableArray array];
[fileTypes addObject:defaultType ? defaultType : (id)kUTTypeContent];
for (FileFilter *filterPtr = fl.filters; filterPtr;
filterPtr = filterPtr->next) {
for (FileFilterClause *clausePtr = filterPtr->clauses; clausePtr;
clausePtr = clausePtr->next) {
for (GlobPattern *globPtr = clausePtr->patterns; globPtr;
globPtr = globPtr->next) {
str = globPtr->pattern;
while (*str && (*str == '*' || *str == '.')) {
str++;
}
if (*str) {
type = [[NSString alloc] initWithUTF8String:str];
if (![fileTypes containsObject:type]) {
[fileTypes addObject:type];
}
[type release];
}
case SAVE_DEFAULT:
str = Tcl_GetStringFromObj(objv[i + 1], &len);
while (*str && (*str == '*' || *str == '.')) {
str++;
}
if (*str) {
defaultType = [[[NSString alloc] initWithUTF8String:str]
autorelease];
}
break;
case SAVE_FILETYPES:
fileTypesPtr = objv[i + 1];
break;
case SAVE_INITDIR:
str = Tcl_GetStringFromObj(objv[i + 1], &len);
if (len) {
directory = [[[NSString alloc] initWithUTF8String:str]
autorelease];
}
break;
case SAVE_INITFILE:
str = Tcl_GetStringFromObj(objv[i + 1], &len);
if (len) {
filename = [[[NSString alloc] initWithUTF8String:str]
autorelease];
[savepanel setNameFieldStringValue:filename];
}
break;
case SAVE_MESSAGE:
message = [[NSString alloc] initWithUTF8String:
Tcl_GetString(objv[i + 1])];
break;
case SAVE_PARENT:
str = Tcl_GetStringFromObj(objv[i + 1], &len);
tkwin = Tk_NameToWindow(interp, str, tkwin);
if (!tkwin) {
goto end;
}
haveParentOption = 1;
break;
case SAVE_TITLE:
title = [[NSString alloc] initWithUTF8String:
Tcl_GetString(objv[i + 1])];
break;
case SAVE_TYPEVARIABLE:
typeVariablePtr = objv[i + 1];
break;
case SAVE_COMMAND:
cmdObj = objv[i+1];
break;
case SAVE_CONFIRMOW:
if (Tcl_GetBooleanFromObj(interp, objv[i + 1],
&confirmOverwrite) != TCL_OK) {
goto end;
}
break;
}
}
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*/
if (haveParentOption) {
if (message) {
NSString *fullmessage = [[NSString alloc] initWithFormat:@"%@\n%@",title,message];
[message release];
[title release];
message = fullmessage;
} else {
message = title;
}
}
[panel setAllowedFileTypes:fileTypes];
[panel setAllowsOtherFileTypes:YES];
}
[panel setCanSelectHiddenExtension:YES];
[panel setExtensionHidden:NO];
if (message) {
[savepanel setMessage:message];
[message release];
}
if (parseFileFilters(interp, fileTypesPtr, typeVariablePtr) != TCL_OK) {
goto end;
}
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)];
[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];
[popupButton addItemsWithTitles:filterInfo.fileTypeLabels];
[popupButton selectItemAtIndex:filterInfo.fileTypeIndex];
[popupButton setAction:@selector(saveFormat:)];
[accessoryView addSubview:label];
[accessoryView addSubview:popupButton];
[savepanel setAccessoryView:accessoryView];
[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 */
NSMutableArray *AllowedFileTypes = [NSMutableArray array];
[AllowedFileTypes addObject:defaultType];
[savepanel setAllowedFileTypes:AllowedFileTypes];
[savepanel setAllowsOtherFileTypes:YES];
}
[savepanel setCanSelectHiddenExtension:YES];
[savepanel setExtensionHidden:NO];
if (cmdObj) {
callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo));
if (Tcl_IsShared(cmdObj)) {
@@ -716,42 +979,55 @@ Tk_GetSaveFileObjCmd(
callbackInfo->cmdObj = cmdObj;
callbackInfo->interp = interp;
callbackInfo->multiple = 0;
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
if (haveParentOption && parent && ![parent attachedSheet]) {
parentIsKey = [parent isKeyWindow];
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
[panel beginSheetForDirectory:directory
file:filename
modalForWindow:parent
modalDelegate:NSApp
didEndSelector:
@selector(tkFilePanelDidEnd:returnCode:contextInfo:)
contextInfo:callbackInfo];
#else
[panel setDirectoryURL:getFileURL(directory, filename)];
[panel beginSheetModalForWindow:parent
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:panel
{ [NSApp tkFilePanelDidEnd:savepanel
returnCode:returnCode
contextInfo:callbackInfo ]; } ];
#endif
modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:panel];
modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:savepanel];
} else {
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
modalReturnCode = [panel runModalForDirectory:directory file:filename];
#else
[panel setDirectoryURL:getFileURL(directory, filename)];
modalReturnCode = [panel runModal];
#endif
[NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode
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];
}
result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR;
if (parentIsKey) {
[parent makeKeyWindow];
}
if ((typeVariablePtr && (modalReturnCode == NSOKButton)) && filterInfo.doFileTypes) {
/*
* 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);
}
end:
TkFreeFileFilters(&fl);
return result;
}
@@ -787,7 +1063,7 @@ Tk_ChooseDirectoryObjCmd(
Tcl_Obj *cmdObj = NULL;
FilePanelCallbackInfo callbackInfoStruct;
FilePanelCallbackInfo *callbackInfo = &callbackInfoStruct;
NSString *directory = nil, *filename = nil;
NSString *directory = nil;
NSString *message, *title;
NSWindow *parent;
NSOpenPanel *panel = [NSOpenPanel openPanel];
@@ -858,32 +1134,23 @@ Tk_ChooseDirectoryObjCmd(
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*/
if (!directory) {
directory = @"/";
}
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
if (haveParentOption && parent && ![parent attachedSheet]) {
parentIsKey = [parent isKeyWindow];
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
[panel beginSheetForDirectory:directory
file:filename
modalForWindow:parent
modalDelegate:NSApp
didEndSelector: @selector(tkFilePanelDidEnd:returnCode:contextInfo:)
contextInfo:callbackInfo];
#else
[panel setDirectoryURL:getFileURL(directory, filename)];
parentIsKey = [parent isKeyWindow];
[panel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]];
[panel beginSheetModalForWindow:parent
completionHandler:^(NSInteger returnCode)
{ [NSApp tkFilePanelDidEnd:panel
returnCode:returnCode
contextInfo:callbackInfo ]; } ];
#endif
modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:panel];
} else {
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
modalReturnCode = [panel runModalForDirectory:directory file:nil];
#else
[panel setDirectoryURL:getFileURL(directory, filename)];
[panel setDirectoryURL:[NSURL fileURLWithPath:directory isDirectory:YES]];
modalReturnCode = [panel runModal];
#endif
[NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode
contextInfo:callbackInfo];
}

View File

@@ -16,7 +16,6 @@
#include "tkMacOSXPrivate.h"
#include "tkMacOSXDebug.h"
#include "xbytes.h"
#include "tkButton.h"
/*
@@ -45,12 +44,6 @@ static int useThemedFrame = 0;
*/
static void ClipToGC(Drawable d, GC gc, HIShapeRef *clipRgnPtr);
static CGImageRef CreateCGImageWithXImage(XImage *ximage);
static CGContextRef GetCGContextForDrawable(Drawable d);
static void DrawCGImage(Drawable d, GC gc, CGContextRef context, CGImageRef image,
unsigned long imageForeground, unsigned long imageBackground,
CGRect imageBounds, CGRect srcBounds, CGRect dstBounds);
/*
*----------------------------------------------------------------------
@@ -108,13 +101,14 @@ TkMacOSXInitCGDrawing(
/*
*----------------------------------------------------------------------
*
* BitmapRepFromDrawableRect
* TkMacOSXBitmapRepFromDrawableRect
*
* Extract bitmap data from a MacOSX drawable as an NSBitmapImageRep.
*
* Results:
* Returns an autoreleased NSBitmapRep representing the image of the given
* rectangle of the given drawable.
* Returns an NSBitmapRep representing the image of the given
* rectangle of the given drawable. This object is retained.
* The caller is responsible for releasing it.
*
* NOTE: The x,y coordinates should be relative to a coordinate system with
* origin at the top left, as used by XImage and CGImage, not bottom
@@ -126,7 +120,7 @@ TkMacOSXInitCGDrawing(
*----------------------------------------------------------------------
*/
NSBitmapImageRep*
BitmapRepFromDrawableRect(
TkMacOSXBitmapRepFromDrawableRect(
Drawable drawable,
int x,
int y,
@@ -140,15 +134,14 @@ BitmapRepFromDrawableRect(
NSView *view=NULL;
if ( mac_drawable->flags & TK_IS_PIXMAP ) {
/*
This means that the MacDrawable is functioning as a Tk Pixmap, so its view
field is NULL.
* This means that the MacDrawable is functioning as a
* Tk Pixmap, so its view field is NULL.
*/
cg_context = GetCGContextForDrawable(drawable);
cg_context = TkMacOSXGetCGContextForDrawable(drawable);
CGRect image_rect = CGRectMake(x, y, width, height);
cg_image = CGBitmapContextCreateImage( (CGContextRef) cg_context);
sub_cg_image = CGImageCreateWithImageInRect(cg_image, image_rect);
if ( sub_cg_image ) {
/*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/
bitmap_rep = [NSBitmapImageRep alloc];
[bitmap_rep initWithCGImage:sub_cg_image];
}
@@ -156,14 +149,15 @@ BitmapRepFromDrawableRect(
CGImageRelease(cg_image);
}
} else if ( (view = TkMacOSXDrawableView(mac_drawable)) ) {
/* convert top-left coordinates to NSView coordinates */
/*
* Convert Tk top-left to NSView bottom-left coordinates.
*/
int view_height = [view bounds].size.height;
NSRect view_rect = NSMakeRect(x + mac_drawable->xOff,
view_height - height - y - mac_drawable->yOff,
width,height);
view_height - height - y - mac_drawable->yOff,
width, height);
if ( [view lockFocusIfCanDraw] ) {
/*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/
bitmap_rep = [NSBitmapImageRep alloc];
bitmap_rep = [bitmap_rep initWithFocusedViewRect:view_rect];
[view unlockFocus];
@@ -230,7 +224,7 @@ XCopyArea(
if (srcDraw->flags & TK_IS_PIXMAP) {
img = TkMacOSXCreateCGImageWithDrawable(src);
}else if (TkMacOSXDrawableWindow(src)) {
bitmap_rep = BitmapRepFromDrawableRect(src, src_x, src_y, width, height);
bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(src, src_x, src_y, width, height);
if ( bitmap_rep ) {
img = [bitmap_rep CGImage];
}
@@ -239,7 +233,7 @@ XCopyArea(
}
if (img) {
DrawCGImage(dst, gc, dc.context, img, gc->foreground, gc->background,
TkMacOSXDrawCGImage(dst, gc, dc.context, img, gc->foreground, gc->background,
CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height),
CGRectMake(src_x, src_y, width, height),
CGRectMake(dest_x, dest_y, width, height));
@@ -339,7 +333,7 @@ XCopyPlane(
CGImageRelease(submask);
CGImageRelease(subimage);
} else {
DrawCGImage(dst, gc, dc.context, img, gc->foreground, imageBackground,
TkMacOSXDrawCGImage(dst, gc, dc.context, img, gc->foreground, imageBackground,
CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height),
CGRectMake(src_x, src_y, width, height),
CGRectMake(dest_x, dest_y, width, height));
@@ -357,158 +351,6 @@ XCopyPlane(
}
}
/*
*----------------------------------------------------------------------
*
* TkPutImage --
*
* Copies a subimage from an in-memory image to a rectangle of
* of the specified drawable.
*
* Results:
* None.
*
* Side effects:
* Draws the image on the specified drawable.
*
*----------------------------------------------------------------------
*/
int
TkPutImage(
unsigned long *colors, /* Unused on Macintosh. */
int ncolors, /* Unused on Macintosh. */
Display* display, /* Display. */
Drawable d, /* Drawable to place image on. */
GC gc, /* GC to use. */
XImage* image, /* Image to place. */
int src_x, /* Source X & Y. */
int src_y,
int dest_x, /* Destination X & Y. */
int dest_y,
unsigned int width, /* Same width & height for both */
unsigned int height) /* distination and source. */
{
TkMacOSXDrawingContext dc;
display->request++;
if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
return BadDrawable;
}
if (dc.context) {
CGImageRef img = CreateCGImageWithXImage(image);
if (img) {
/* If the XImage has big pixels, rescale the source dimensions.*/
int pp = image->pixelpower;
DrawCGImage(d, gc, dc.context, img, gc->foreground, gc->background,
CGRectMake(0, 0, image->width<<pp, image->height<<pp),
CGRectMake(src_x<<pp, src_y<<pp, width<<pp, height<<pp),
CGRectMake(dest_x, dest_y, width, height));
CFRelease(img);
} else {
TkMacOSXDbgMsg("Invalid source drawable");
}
} else {
TkMacOSXDbgMsg("Invalid destination drawable");
}
TkMacOSXRestoreDrawingContext(&dc);
return Success;
}
/*
*----------------------------------------------------------------------
*
* CreateCGImageWithXImage --
*
* Create CGImage from XImage, copying the image data.
*
* Results:
* CGImage, release after use.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void ReleaseData(void *info, const void *data, size_t size) {
ckfree(info);
}
CGImageRef
CreateCGImageWithXImage(
XImage *image)
{
CGImageRef img = NULL;
size_t bitsPerComponent, bitsPerPixel;
size_t len = image->bytes_per_line * image->height;
const CGFloat *decode = NULL;
CGBitmapInfo bitmapInfo;
CGDataProviderRef provider = NULL;
char *data = NULL;
CGDataProviderReleaseDataCallback releaseData = ReleaseData;
if (image->bits_per_pixel == 1) {
/*
* BW image
*/
/* Reverses the sense of the bits */
static const CGFloat decodeWB[2] = {1, 0};
decode = decodeWB;
bitsPerComponent = 1;
bitsPerPixel = 1;
if (image->bitmap_bit_order != MSBFirst) {
char *srcPtr = image->data + image->xoffset;
char *endPtr = srcPtr + len;
char *destPtr = (data = ckalloc(len));
while (srcPtr < endPtr) {
*destPtr++ = xBitReverseTable[(unsigned char)(*(srcPtr++))];
}
} else {
data = memcpy(ckalloc(len), image->data + image->xoffset, len);
}
if (data) {
provider = CGDataProviderCreateWithData(data, data, len, releaseData);
}
if (provider) {
img = CGImageMaskCreate(image->width, image->height, bitsPerComponent,
bitsPerPixel, image->bytes_per_line, provider, decode, 0);
}
} else if (image->format == ZPixmap && image->bits_per_pixel == 32) {
/*
* Color image
*/
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
bitsPerComponent = 8;
bitsPerPixel = 32;
bitmapInfo = (image->byte_order == MSBFirst ?
kCGBitmapByteOrder32Big : kCGBitmapByteOrder32Little) |
kCGImageAlphaNoneSkipFirst;
data = memcpy(ckalloc(len), image->data + image->xoffset, len);
if (data) {
provider = CGDataProviderCreateWithData(data, data, len, releaseData);
}
if (provider) {
img = CGImageCreate(image->width, image->height, bitsPerComponent,
bitsPerPixel, image->bytes_per_line, colorspace, bitmapInfo,
provider, decode, 0, kCGRenderingIntentDefault);
CFRelease(provider);
}
if (colorspace) {
CFRelease(colorspace);
}
} else {
TkMacOSXDbgMsg("Unsupported image type");
}
return img;
}
/*
*----------------------------------------------------------------------
*
@@ -530,7 +372,7 @@ TkMacOSXCreateCGImageWithDrawable(
Drawable drawable)
{
CGImageRef img = NULL;
CGContextRef context = GetCGContextForDrawable(drawable);
CGContextRef context = TkMacOSXGetCGContextForDrawable(drawable);
if (context) {
img = CGBitmapContextCreateImage(context);
@@ -598,8 +440,10 @@ TkMacOSXGetNSImageWithTkImage(
int height)
{
Pixmap pixmap = Tk_GetPixmap(display, None, width, height, 0);
MacDrawable *macDraw = (MacDrawable *) pixmap;
NSImage *nsImage;
macDraw->flags |= TK_USE_XIMAGE_ALPHA;
Tk_RedrawImage(image, 0, 0, width, height, pixmap, 0, 0);
nsImage = CreateNSImageWithPixmap(pixmap, width, height);
Tk_FreePixmap(display, pixmap);
@@ -649,7 +493,7 @@ TkMacOSXGetNSImageWithBitmap(
/*
*----------------------------------------------------------------------
*
* GetCGContextForDrawable --
* TkMacOSXGetCGContextForDrawable --
*
* Get CGContext for given Drawable, creating one if necessary.
*
@@ -663,10 +507,10 @@ TkMacOSXGetNSImageWithBitmap(
*/
CGContextRef
GetCGContextForDrawable(
Drawable d)
TkMacOSXGetCGContextForDrawable(
Drawable drawable)
{
MacDrawable *macDraw = (MacDrawable *) d;
MacDrawable *macDraw = (MacDrawable *) drawable;
if (macDraw && (macDraw->flags & TK_IS_PIXMAP) && !macDraw->context) {
const size_t bitsPerComponent = 8;
@@ -685,7 +529,7 @@ GetCGContextForDrawable(
bitsPerPixel = 8;
bitmapInfo = (CGBitmapInfo)kCGImageAlphaOnly;
} else {
colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
colorspace = CGColorSpaceCreateDeviceRGB();
bitsPerPixel = 32;
bitmapInfo |= kCGImageAlphaPremultipliedFirst;
}
@@ -711,7 +555,7 @@ GetCGContextForDrawable(
/*
*----------------------------------------------------------------------
*
* DrawCGImage --
* TkMacOSXDrawCGImage --
*
* Draw CG image into drawable.
*
@@ -725,7 +569,7 @@ GetCGContextForDrawable(
*/
void
DrawCGImage(
TkMacOSXDrawCGImage(
Drawable d,
GC gc,
CGContextRef context,
@@ -858,6 +702,16 @@ XDrawLines(
CGContextAddLineToPoint(dc.context, prevx, prevy);
}
}
/*
* In the case of closed polylines, the first and last points
* are the same. We want miter or bevel join be rendered also
* at this point, this needs telling CoreGraphics that the
* path is closed.
*/
if ((points[0].x == points[npoints-1].x) &&
(points[0].y == points[npoints-1].y)) {
CGContextClosePath(dc.context);
}
CGContextStrokePath(dc.context);
}
TkMacOSXRestoreDrawingContext(&dc);
@@ -880,7 +734,7 @@ XDrawLines(
*----------------------------------------------------------------------
*/
void
int
XDrawSegments(
Display *display,
Drawable d,
@@ -894,7 +748,7 @@ XDrawSegments(
display->request++;
if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
return;
return BadDrawable;
}
if (dc.context) {
double o = (lw % 2) ? .5 : 0;
@@ -911,6 +765,7 @@ XDrawSegments(
}
}
TkMacOSXRestoreDrawingContext(&dc);
return Success;
}
/*
@@ -1475,7 +1330,7 @@ XMaxRequestSize(
* a damage region.
*
* Results:
* Returns 0 if the scroll genereated no additional damage.
* Returns 0 if the scroll generated no additional damage.
* Otherwise, sets the region that needs to be repainted after
* scrolling and returns 1.
*
@@ -1505,8 +1360,7 @@ TkScrollWindow(
if ( view ) {
/* Get the scroll area in NSView coordinates (origin at bottom left). */
bounds = [view bounds];
scrollSrc = NSMakeRect(
macDraw->xOff + x,
scrollSrc = NSMakeRect(macDraw->xOff + x,
bounds.size.height - height - (macDraw->yOff + y),
width, height);
scrollDst = NSOffsetRect(scrollSrc, dx, -dy);
@@ -1516,7 +1370,6 @@ TkScrollWindow(
scrollSrc = NSIntersectionRect(scrollSrc, visRect);
scrollDst = NSIntersectionRect(scrollDst, visRect);
if ( !NSIsEmptyRect(scrollSrc) && !NSIsEmptyRect(scrollDst) ) {
/*
* Mark the difference between source and destination as damaged.
* This region is described in NSView coordinates (y=0 at the bottom)
@@ -1526,19 +1379,13 @@ TkScrollWindow(
srcRect = CGRectMake(x, y, width, height);
dstRect = CGRectOffset(srcRect, dx, dy);
/* Expand the rectangles slightly to avoid degeneracies. */
srcRect.origin.y -= 1;
srcRect.size.height += 2;
dstRect.origin.y += 1;
dstRect.size.height -= 2;
/* Compute the damage. */
dmgRgn = HIShapeCreateMutableWithRect(&srcRect);
extraRgn = HIShapeCreateWithRect(&dstRect);
ChkErr(HIShapeDifference, dmgRgn, extraRgn, (HIMutableShapeRef) dmgRgn);
result = HIShapeIsEmpty(dmgRgn) ? 0 : 1;
/* Convert to Tk coordinates. */
/* Convert to Tk coordinates, offset by the window origin. */
TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn);
if (extraRgn) {
CFRelease(extraRgn);
@@ -1546,33 +1393,6 @@ TkScrollWindow(
/* Scroll the rectangle. */
[view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)];
/* Shift the Tk children which meet the source rectangle. */
TkWindow *winPtr = (TkWindow *)tkwin;
TkWindow *childPtr;
CGRect childBounds;
for (childPtr = winPtr->childList; childPtr != NULL; childPtr = childPtr->nextPtr) {
if (Tk_IsMapped(childPtr) && !Tk_IsTopLevel(childPtr)) {
TkMacOSXWinCGBounds(childPtr, &childBounds);
if (CGRectIntersectsRect(srcRect, childBounds)) {
MacDrawable *macChild = childPtr->privatePtr;
if (macChild) {
macChild->yOff += dy;
macChild->xOff += dx;
childPtr->changes.y = macChild->yOff;
childPtr->changes.x = macChild->xOff;
}
}
}
}
/* Queue up Expose events for the damage region. */
int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
[view generateExposeEvents:dmgRgn childrenOnly:1];
Tcl_SetServiceMode(oldMode);
/* Belt and suspenders: make the AppKit request a redraw
when it gets control again. */
}
} else {
dmgRgn = HIShapeCreateEmpty();
@@ -1649,7 +1469,7 @@ TkMacOSXSetupDrawingContext(
goto end;
}
if (useCG) {
dc.context = GetCGContextForDrawable(d);
dc.context = TkMacOSXGetCGContextForDrawable(d);
}
if (!dc.context || !(macDraw->flags & TK_IS_PIXMAP)) {
isWin = (TkMacOSXDrawableWindow(d) != nil);
@@ -1694,13 +1514,13 @@ TkMacOSXSetupDrawingContext(
CGContextSetTextDrawingMode(dc.context, kCGTextFill);
CGContextConcatCTM(dc.context, t);
if (dc.clipRgn) {
#ifdef TK_MAC_DEBUG_DRAWING
#ifdef TK_MAC_DEBUG_DRAWING
CGContextSaveGState(dc.context);
ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context);
CGContextSetRGBFillColor(dc.context, 1.0, 0.0, 0.0, 0.1);
CGContextEOFillPath(dc.context);
CGContextRestoreGState(dc.context);
#endif /* TK_MAC_DEBUG_DRAWING */
#endif /* TK_MAC_DEBUG_DRAWING */
CGRect r;
if (!HIShapeIsRectangular(dc.clipRgn) || !CGRectContainsRect(
*HIShapeGetBounds(dc.clipRgn, &r),

View File

@@ -193,7 +193,7 @@ TkpMakeWindow(
int
TkpScanWindowId(
Tcl_Interp *interp,
CONST char * string,
const char * string,
Window *idPtr)
{
int code;
@@ -799,6 +799,13 @@ ContainerEventProc(
Container *containerPtr;
Tk_ErrorHandler errHandler;
if (!firstContainerPtr) {
/*
* When the interpreter is being dismantled this can be nil.
*/
return;
}
/*
* Ignore any X protocol errors that happen in this procedure (almost any
* operation could fail, for example, if the embedded application has

View File

@@ -14,6 +14,7 @@
#include "tkMacOSXPrivate.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXDebug.h"
#include "tkMacOSXConstants.h"
#pragma mark TKApplication(TKEvent)
@@ -88,7 +89,6 @@ enum {
}
case NSCursorUpdate:
break;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
case NSEventTypeGesture:
case NSEventTypeMagnify:
case NSEventTypeRotate:
@@ -96,7 +96,6 @@ enum {
case NSEventTypeBeginGesture:
case NSEventTypeEndGesture:
break;
#endif
#endif
default:

View File

@@ -515,7 +515,7 @@ TkpGetFontFromAttributes(
/* Set of attributes to match. */
{
MacFont *fontPtr;
int points = TkFontGetPoints(tkwin, faPtr->size);
int points = (int)(TkFontGetPoints(tkwin, faPtr->size) + 0.5);
NSFontTraitMask traits = GetNSFontTraitsFromTkFontAttributes(faPtr);
NSInteger weight = (faPtr->weight == TK_FW_BOLD ? 9 : 5);
NSFont *nsFont;
@@ -672,14 +672,14 @@ void
TkpGetFontAttrsForChar(
Tk_Window tkwin, /* Window on the font's display */
Tk_Font tkfont, /* Font to query */
Tcl_UniChar c, /* Character of interest */
int c, /* Character of interest */
TkFontAttributes* faPtr) /* Output: Font attributes */
{
MacFont *fontPtr = (MacFont *) tkfont;
NSFont *nsFont = fontPtr->nsFont;
*faPtr = fontPtr->font.fa;
if (nsFont && ![[nsFont coveredCharacterSet] characterIsMember:c]) {
UTF16Char ch = c;
UTF16Char ch = (UTF16Char) c;
nsFont = [nsFont bestMatchingFontForCharacters:&ch
length:1 attributes:nil actualCoveredLength:NULL];
@@ -870,7 +870,7 @@ TkpMeasureCharsInContext(
if (index <= start && !(flags & TK_WHOLE_WORDS)) {
index = CTTypesetterSuggestClusterBreak(typesetter, start, maxWidth);
}
cs = (index < len || (flags & TK_WHOLE_WORDS)) ?
cs = (index <= len && (flags & TK_WHOLE_WORDS)) ?
whitespaceCharacterSet : lineendingCharacterSet;
while (index > start &&
[cs characterIsMember:[string characterAtIndex:(index - 1)]]) {

View File

@@ -36,7 +36,7 @@ typedef struct KillEvent {
static void tkMacOSXProcessFiles(NSAppleEventDescriptor* event,
NSAppleEventDescriptor* replyEvent,
Tcl_Interp *interp,
char* procedure);
const char* procedure);
static int MissedAnyParameters(const AppleEvent *theEvent);
static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
@@ -277,7 +277,7 @@ tkMacOSXProcessFiles(
NSAppleEventDescriptor* event,
NSAppleEventDescriptor* replyEvent,
Tcl_Interp *interp,
char* procedure)
const char* procedure)
{
Tcl_Encoding utf8 = Tcl_GetEncoding(NULL, "utf-8");
const AEDesc *fileSpecDesc = nil;

View File

@@ -7,6 +7,7 @@
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
* Copyright (c) 2017 Marc Culler
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -32,22 +33,11 @@ long tkMacOSXMacOSXVersion = 0;
#pragma mark TKApplication(TKInit)
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#define NSTextInputContextKeyboardSelectionDidChangeNotification @"NSTextInputContextKeyboardSelectionDidChangeNotification"
static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
[[NSNotificationCenter defaultCenter] postNotificationName:NSTextInputContextKeyboardSelectionDidChangeNotification object:nil userInfo:nil];
}
#endif
@interface TKApplication(TKKeyboard)
- (void) keyboardChanged: (NSNotification *) notification;
@end
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
#define TKApplication_NSApplicationDelegate <NSApplicationDelegate>
#else
#define TKApplication_NSApplicationDelegate
#endif
@interface TKApplication(TKWindowEvent) TKApplication_NSApplicationDelegate
- (void) _setupWindowNotifications;
@end
@@ -57,17 +47,35 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
@end
@implementation TKApplication
@synthesize poolProtected = _poolProtected;
@synthesize poolLock = _poolLock;
@end
/*
* #define this to see a message on stderr whenever _resetAutoreleasePool is
* called while the pool is locked.
*/
#undef DEBUG_LOCK
@implementation TKApplication(TKInit)
- (void) _resetAutoreleasePool
{
if(![self poolProtected]) {
if([self poolLock] == 0) {
[_mainPool drain];
_mainPool = [NSAutoreleasePool new];
} else {
#ifdef DEBUG_LOCK
fprintf(stderr, "Pool is locked with count %d!!!!\n", [self poolLock]);
#endif
}
}
- (void) _lockAutoreleasePool
{
[self setPoolLock:[self poolLock] + 1];
}
- (void) _unlockAutoreleasePool
{
[self setPoolLock:[self poolLock] - 1];
}
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
- (void) _postedNotification: (NSNotification *) notification
{
@@ -87,33 +95,89 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
observe(NSApplicationDidChangeScreenParametersNotification, displayChanged:);
observe(NSTextInputContextKeyboardSelectionDidChangeNotification, keyboardChanged:);
#undef observe
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), NULL, &keyboardChanged, kTISNotifySelectedKeyboardInputSourceChanged, NULL, CFNotificationSuspensionBehaviorCoalesce);
#endif
}
- (void) _setupEventLoop
-(void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
[self finishLaunching];
[self setWindowsNeedUpdate:YES];
[pool drain];
}
- (void) _setup: (Tcl_Interp *) interp
{
_eventInterp = interp;
_mainPool = [NSAutoreleasePool new];
[NSApp setPoolProtected:NO];
_defaultMainMenu = nil;
[self _setupMenus];
[self setDelegate:self];
/*
* Initialize notifications.
*/
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_postedNotification:) name:nil object:nil];
#endif
[self _setupWindowNotifications];
[self _setupApplicationNotifications];
/*
* Construct the menu bar.
*/
_defaultMainMenu = nil;
[self _setupMenus];
/*
* Initialize event processing.
*/
TkMacOSXInitAppleEvents(_eventInterp);
/*
* Initialize the graphics context.
*/
TkMacOSXUseAntialiasedText(_eventInterp, -1);
TkMacOSXInitCGDrawing(_eventInterp, TRUE, 0);
}
-(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.
*/
[NSApp activateIgnoringOtherApps: YES];
}
- (void) _setup: (Tcl_Interp *) interp
{
/*
* Remember our interpreter.
*/
_eventInterp = interp;
/*
* Install the global autoreleasePool.
*/
_mainPool = [NSAutoreleasePool new];
[NSApp setPoolLock:0];
/*
* Be our own delegate.
*/
[self setDelegate:self];
/*
* Make sure we are allowed to open windows.
*/
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
/*
* 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) {
NSString *path = [NSApp tkFrameworkImagePath:@"Tk.icns"];
if (path) {
NSImage *image = [[NSImage alloc] initWithContentsOfFile:path];
if (image) {
[NSApp setApplicationIconImage:image];
[image release];
}
}
}
}
- (NSString *) tkFrameworkImagePath: (NSString *) image
@@ -160,38 +224,6 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
#pragma mark -
/*
*----------------------------------------------------------------------
*
* DoWindowActivate --
*
* Idle handler that sets the application icon to the generic Tk icon.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
SetApplicationIcon(
ClientData clientData)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSString *path = [NSApp tkFrameworkImagePath:@"Tk.icns"];
if (path) {
NSImage *image = [[NSImage alloc] initWithContentsOfFile:path];
if (image) {
[NSApp setApplicationIconImage:image];
[image release];
}
}
[pool drain];
}
/*
*----------------------------------------------------------------------
*
@@ -223,9 +255,6 @@ TkpInit(
*/
if (!initialized) {
int bundledExecutable = 0;
CFBundleRef bundleRef;
CFURLRef bundleUrl = NULL;
struct utsname name;
struct stat st;
@@ -235,8 +264,8 @@ TkpInit(
* Initialize/check OS version variable for runtime checks.
*/
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
# error Mac OS X 10.5 required
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
# error Mac OS X 10.6 required
#endif
if (!uname(&name)) {
@@ -263,88 +292,12 @@ TkpInit(
if (Tcl_MacOSXOpenVersionedBundleResources(interp,
"com.tcltk.tklibrary", TK_FRAMEWORK_VERSION, 0, PATH_MAX,
tkLibPath) != TCL_OK) {
# if 0 /* This is not really an error. Wish still runs fine. */
TkMacOSXDbgMsg("Tcl_MacOSXOpenVersionedBundleResources failed");
# endif
}
#endif
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
[[NSUserDefaults standardUserDefaults] registerDefaults:
[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],
@"_NSCanWrapButtonTitles",
[NSNumber numberWithInt:-1],
@"NSStringDrawingTypesetterBehavior",
nil]];
[TKApplication sharedApplication];
[pool drain];
[NSApp _setup:interp];
}
/* Check whether we are a bundled executable: */
bundleRef = CFBundleGetMainBundle();
if (bundleRef) {
bundleUrl = CFBundleCopyBundleURL(bundleRef);
}
if (bundleUrl) {
/*
* A bundled executable is two levels down from its main bundle
* directory (e.g. Wish.app/Contents/MacOS/Wish), whereas an
* unbundled executable's main bundle directory is just the
* directory containing the executable. So to check whether we are
* bundled, we delete the last three path components of the
* executable's url and compare the resulting url with the main
* bundle url.
*/
int j = 3;
CFURLRef url = CFBundleCopyExecutableURL(bundleRef);
while (url && j--) {
CFURLRef parent =
CFURLCreateCopyDeletingLastPathComponent(NULL, url);
CFRelease(url);
url = parent;
}
if (url) {
bundledExecutable = CFEqual(bundleUrl, url);
CFRelease(url);
}
CFRelease(bundleUrl);
}
if (!bundledExecutable) {
/*
* If we are loaded into an executable that is not a bundled
* application, the window server does not let us come to the
* foreground. For such an executable, notify the window server
* that we are now a full GUI application.
*/
OSStatus err = procNotFound;
ProcessSerialNumber psn = { 0, kCurrentProcess };
err = ChkErr(TransformProcessType, &psn,
kProcessTransformToForegroundApplication);
/*
* Set application icon to generic Tk icon, do it at idle time
* instead of now to ensure tk_library is setup.
*/
Tcl_DoWhenIdle(SetApplicationIcon, NULL);
}
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
[NSApp _setupEventLoop];
TkMacOSXInitAppleEvents(interp);
TkMacOSXUseAntialiasedText(interp, -1);
TkMacOSXInitCGDrawing(interp, TRUE, 0);
[pool drain];
}
/*
* FIXME: Close stdin & stdout for remote debugging otherwise we will
* fight with gdb for stdin & stdout
@@ -355,6 +308,24 @@ TkpInit(
close(1);
}
/*
* Instantiate our NSApplication object. This needs to be
* done before we check whether to open a console window.
*/
NSAutoreleasePool *pool = [NSAutoreleasePool new];
[[NSUserDefaults standardUserDefaults] registerDefaults:
[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],
@"_NSCanWrapButtonTitles",
[NSNumber numberWithInt:-1],
@"NSStringDrawingTypesetterBehavior",
nil]];
[TKApplication sharedApplication];
[pool drain];
[NSApp _setup:interp];
[NSApp finishLaunching];
/*
* 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
@@ -387,6 +358,7 @@ TkpInit(
return TCL_ERROR;
}
}
}
Tk_MacOSXSetupTkNotifier();

View File

@@ -87,6 +87,7 @@ typedef struct TkWindowPrivate MacDrawable;
#define TK_IS_PIXMAP 0x20
#define TK_IS_BW_PIXMAP 0x40
#define TK_DO_NOT_DRAW 0x80
#define TK_USE_XIMAGE_ALPHA 0x100
/*
* I am reserving TK_EMBEDDED = 0x100 in the MacDrawable flags
* This is defined in tk.h. We need to duplicate the TK_EMBEDDED flag in the

View File

@@ -15,6 +15,7 @@
#include "tkMacOSXPrivate.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXConstants.h"
/*
#ifdef TK_MAC_DEBUG

View File

@@ -13,7 +13,7 @@
#include "tkMacOSXPrivate.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXConstants.h"
/*
* A couple of simple definitions to make code a bit more self-explaining.
*
@@ -96,6 +96,24 @@ static KeyInfo virtualkeyArray[] = {
{0, 0}
};
#define NUM_MOD_KEYCODES 14
static KeyCode modKeyArray[NUM_MOD_KEYCODES] = {
XK_Shift_L,
XK_Shift_R,
XK_Control_L,
XK_Control_R,
XK_Caps_Lock,
XK_Shift_Lock,
XK_Meta_L,
XK_Meta_R,
XK_Alt_L,
XK_Alt_R,
XK_Super_L,
XK_Super_R,
XK_Hyper_L,
XK_Hyper_R,
};
static int initialized = 0;
static Tcl_HashTable keycodeTable; /* keyArray hashed by keycode value. */
static Tcl_HashTable vkeyTable; /* virtualkeyArray hashed by virtual
@@ -457,7 +475,6 @@ XGetModifierMapping(
* MacOSX doesn't use the key codes for the modifiers for anything, and we
* don't generate them either. So there is no modifier map.
*/
modmap = ckalloc(sizeof(XModifierKeymap));
modmap->max_keypermod = 0;
modmap->modifiermap = NULL;
@@ -548,7 +565,6 @@ XKeysymToMacKeycode(
KeySym keysym)
{
KeyInfo *kPtr;
if (keysym <= LATIN1_MAX) {
/*
* Handle keysyms in the Latin-1 range where keysym and Unicode
@@ -579,6 +595,17 @@ XKeysymToMacKeycode(
}
}
/*
* Modifier keycodes only come from generated events. No translation
* is needed.
*/
for (int i=0; i < NUM_MOD_KEYCODES; i++) {
if (keysym == modKeyArray[i]) {
return keysym;
}
}
/*
* For other keysyms (not Latin-1 and not special keys), we'd need a
* generic keysym-to-unicode table. We don't have that, so we give up here.
@@ -661,6 +688,13 @@ TkpSetKeycodeAndState(
{
if (keysym == NoSymbol) {
eventPtr->xkey.keycode = 0;
} else if ( modKeyArray[0] <= keysym &&
keysym <= modKeyArray[NUM_MOD_KEYCODES - 1]) {
/*
* Keysyms for pure modifiers only arise in generated events.
* We should just copy them to the keycode.
*/
eventPtr->xkey.keycode = keysym;
} else {
Display *display = Tk_Display(tkwin);
int macKeycode = XKeysymToMacKeycode(display, keysym);
@@ -668,7 +702,6 @@ TkpSetKeycodeAndState(
/*
* See also XKeysymToKeycode.
*/
if ((keysym >= XK_F1) && (keysym <= XK_F35)) {
eventPtr->xkey.keycode = 0x0010;
} else {
@@ -734,7 +767,6 @@ TkpGetKeySym(
*/
if (eventPtr->xany.send_event == -1) {
int modifier = eventPtr->xkey.keycode & NSDeviceIndependentModifierFlagsMask;
if (modifier == NSCommandKeyMask) {
@@ -891,18 +923,20 @@ TkpInitKeymapInfo(
#endif
/*
* MacOSX doesn't use the keycodes for the modifiers for anything, and we
* don't generate them either (the keycodes actually given in the simulated
* modifier events are bogus). So there is no modifier map. If we ever want
* to simulate real modifier keycodes, the list will be constant in the
* Carbon implementation.
* MacOSX doesn't create a key event when a modifier key is pressed or
* released. However, it is possible to generate key events for
* modifier keys, and this is done in the tests. So we construct an array
* containing the keycodes of the standard modifier keys from static data.
*/
if (dispPtr->modKeyCodes != NULL) {
ckfree(dispPtr->modKeyCodes);
}
dispPtr->numModKeyCodes = 0;
dispPtr->modKeyCodes = NULL;
dispPtr->numModKeyCodes = NUM_MOD_KEYCODES;
dispPtr->modKeyCodes = (KeyCode *)ckalloc(NUM_MOD_KEYCODES * sizeof(KeyCode));
for (int i = 0; i < NUM_MOD_KEYCODES; i++) {
dispPtr->modKeyCodes[i] = modKeyArray[i];
}
}
/*

View File

@@ -19,6 +19,7 @@
#include "tkFont.h"
#include "tkMacOSXWm.h"
#include "tkMacOSXDebug.h"
#include "tkMacOSXConstants.h"
/*
#ifdef TK_MAC_DEBUG
@@ -116,11 +117,7 @@ static int ModifierCharWidth(Tk_Font tkfont);
- (void) insertItem: (NSMenuItem *) newItem atTkIndex: (NSInteger) index;
@end
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
#define TKMenu_NSMenuDelegate <NSMenuDelegate>
#else
#define TKMenu_NSMenuDelegate
#endif
@interface TKMenu(TKMenuDelegate) TKMenu_NSMenuDelegate
@end
@@ -773,8 +770,15 @@ TkpPostMenu(
Drawable d = Tk_WindowId(root);
NSView *rootview = TkMacOSXGetRootControl(d);
NSWindow *win = [rootview window];
int result;
inPostMenu = 1;
result = TkPreprocessMenu(menuPtr);
if (result != TCL_OK) {
inPostMenu = 0;
return result;
}
int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
NSView *view = [win contentView];

View File

@@ -13,6 +13,7 @@
#include "tkMacOSXPrivate.h"
#include "tkMenu.h"
#include "tkMacOSXConstants.h"
static void GenerateEditEvent(const char *name);
static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);

View File

@@ -15,6 +15,7 @@
#include "tkMacOSXWm.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXDebug.h"
#include "tkMacOSXConstants.h"
typedef struct {
unsigned int state;

View File

@@ -15,8 +15,8 @@
#include "tkMacOSXPrivate.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXConstants.h"
#include <tclInt.h>
#include <pthread.h>
#import <objc/objc-auto.h>
/* This is not used for anything at the moment. */
@@ -140,7 +140,7 @@ Tk_MacOSXSetupTkNotifier(void)
*/
if (CFRunLoopGetMain() == CFRunLoopGetCurrent()) {
if (!pthread_main_np()) {
if (![NSThread isMainThread]) {
/*
* Panic if main runloop is not on the main application thread.
*/
@@ -150,7 +150,7 @@ Tk_MacOSXSetupTkNotifier(void)
}
Tcl_CreateEventSource(TkMacOSXEventsSetupProc,
TkMacOSXEventsCheckProc,
GetMainEventQueue());
NULL);
TkCreateExitHandler(TkMacOSXNotifyExitHandler, NULL);
Tcl_SetServiceMode(TCL_SERVICE_ALL);
TclMacOSXNotifierAddRunLoopMode(NSEventTrackingRunLoopMode);
@@ -184,7 +184,7 @@ TkMacOSXNotifyExitHandler(
Tcl_DeleteEventSource(TkMacOSXEventsSetupProc,
TkMacOSXEventsCheckProc,
GetMainEventQueue());
NULL);
tsdPtr->initialized = 0;
}
@@ -216,9 +216,10 @@ TkMacOSXEventsSetupProc(
int flags)
{
NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode];
/* runloopMode will be nil if we are in the 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]
@@ -256,29 +257,28 @@ TkMacOSXEventsCheckProc(
int flags)
{
NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode];
/* runloopMode will be nil if we are in the 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
* 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 {
[NSApp _resetAutoreleasePool];
modalSession = TkMacOSXGetModalSession();
testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(modalSession)
dequeue:NO];
/* We must not steal any events during LiveResize. */
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
if (testEvent && [[testEvent window] inLiveResize]) {
break;
}
#else
if (testEvent && [[[testEvent window] contentView] inLiveResize]) {
break;
}
#endif
currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(modalSession)
@@ -303,6 +303,8 @@ TkMacOSXEventsCheckProc(
break;
}
} while (1);
/* Now we can unlock the pool. */
[NSApp _unlockAutoreleasePool];
}
}

View File

@@ -53,7 +53,6 @@
#include <X11/Xatom.h>
#include <X11/Xfuncproto.h>
#include <X11/Xutil.h>
#include "tkIntXlibDecls.h"
/*
* The following macro defines the type of the mask arguments to

View File

@@ -59,27 +59,6 @@
if (0) {
#define tk_else_mac_os_x_no(...) \
} else { __VA_ARGS__
/* Private mapping macros defined according to Mac OS X version requirements */
/* 10.5 Leopard */
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
#define tk_if_mac_os_x_min_10_5 tk_if_mac_os_x_yes
#define tk_else_mac_os_x_min_10_5 tk_else_mac_os_x_yes
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
#define tk_if_mac_os_x_10_5 tk_if_mac_os_x_yes
#define tk_else_mac_os_x_10_5 tk_else_mac_os_x_yes
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
#else /* MAC_OS_X_VERSION_MIN_REQUIRED */
#define tk_if_mac_os_x_min_10_5 tk_if_mac_os_x_chk
#define tk_else_mac_os_x_min_10_5 tk_else_mac_os_x_chk
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
#define tk_if_mac_os_x_10_5 tk_if_mac_os_x_chk
#define tk_else_mac_os_x_10_5 tk_else_mac_os_x_chk
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
#endif /* MAC_OS_X_VERSION_MIN_REQUIRED */
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
#define tk_if_mac_os_x_10_5 tk_if_mac_os_x_no
#define tk_else_mac_os_x_10_5 tk_else_mac_os_x_no
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
/*
* Macros for DEBUG_ASSERT_MESSAGE et al from Debugging.h.
@@ -209,8 +188,14 @@ MODULE_SCOPE WindowClass TkMacOSXWindowClass(TkWindow *winPtr);
MODULE_SCOPE int TkMacOSXIsWindowZoomed(TkWindow *winPtr);
MODULE_SCOPE int TkGenerateButtonEventForXPointer(Window window);
MODULE_SCOPE EventModifiers TkMacOSXModifierState(void);
MODULE_SCOPE NSBitmapImageRep* BitmapRepFromDrawableRect(Drawable drawable,
MODULE_SCOPE NSBitmapImageRep* TkMacOSXBitmapRepFromDrawableRect(Drawable drawable,
int x, int y, unsigned int width, unsigned int height);
MODULE_SCOPE CGImageRef TkMacOSXCreateCGImageWithXImage(XImage *image,
int use_ximage_alpha);
MODULE_SCOPE void TkMacOSXDrawCGImage(Drawable d, GC gc, CGContextRef context,
CGImageRef image, unsigned long imageForeground,
unsigned long imageBackground, CGRect imageBounds,
CGRect srcBounds, CGRect dstBounds);
MODULE_SCOPE int TkMacOSXSetupDrawingContext(Drawable d, GC gc,
int useCG, TkMacOSXDrawingContext *dcPtr);
MODULE_SCOPE void TkMacOSXRestoreDrawingContext(
@@ -228,6 +213,7 @@ MODULE_SCOPE void TkMacOSXWinCGBounds(TkWindow *winPtr, CGRect *bounds);
MODULE_SCOPE HIShapeRef TkMacOSXGetClipRgn(Drawable drawable);
MODULE_SCOPE void TkMacOSXInvalidateViewRegion(NSView *view,
HIShapeRef rgn);
MODULE_SCOPE CGContextRef TkMacOSXGetCGContextForDrawable(Drawable drawable);
MODULE_SCOPE CGImageRef TkMacOSXCreateCGImageWithDrawable(Drawable drawable);
MODULE_SCOPE NSImage* TkMacOSXGetNSImageWithTkImage(Display *display,
Tk_Image image, int width, int height);
@@ -278,14 +264,17 @@ VISIBILITY_HIDDEN
NSAutoreleasePool *_mainPool;
#ifdef __i386__
/* The Objective C runtime used on i386 requires this. */
BOOL _poolProtected;
int _poolLock;
#endif
}
@property BOOL poolProtected;
@property int poolLock;
@end
@interface TKApplication(TKInit)
- (NSString *)tkFrameworkImagePath:(NSString*)image;
- (void)_resetAutoreleasePool;
- (void)_lockAutoreleasePool;
- (void)_unlockAutoreleasePool;
@end
@interface TKApplication(TKEvent)
- (NSEvent *)tkProcessEvent:(NSEvent *)theEvent;
@@ -341,7 +330,6 @@ VISIBILITY_HIDDEN
@interface TKContentView(TKWindowEvent)
- (void) drawRect: (NSRect) rect;
- (void) generateExposeEvents: (HIShapeRef) shape;
- (void) generateExposeEvents: (HIShapeRef) shape childrenOnly: (int) childrenOnly;
- (void) viewDidEndLiveResize;
- (void) tkToolbarButton: (id) sender;
- (BOOL) isOpaque;

View File

@@ -171,7 +171,10 @@ TkpDisplayScale(
Tcl_Preserve((ClientData) scalePtr);
if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) {
Tcl_Preserve((ClientData) interp);
sprintf(string, scalePtr->format, scalePtr->value);
if (snprintf(string, TCL_DOUBLE_SPACE, scalePtr->format,
scalePtr->value) < 0) {
string[TCL_DOUBLE_SPACE - 1] = '\0';
}
Tcl_DStringInit(&buf);
Tcl_DStringAppend(&buf, scalePtr->command, -1);
Tcl_DStringAppend(&buf, " ", -1);

View File

@@ -19,6 +19,13 @@
#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
/*Borrowed from ttkMacOSXTheme.c to provide appropriate scaling of scrollbar values.*/
#ifdef __LP64__
#define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum))
@@ -60,16 +67,14 @@ typedef struct ScrollbarMetrics {
} ScrollbarMetrics;
static ScrollbarMetrics metrics[2] = {
{15, 54, 26, 14, 14, NSRegularControlSize}, /* kThemeScrollBarMedium */
{11, 40, 20, 10, 10, NSSmallControlSize}, /* kThemeScrollBarSmall */
{15, 54, 26, 14, 14, kControlSizeNormal}, /* kThemeScrollBarMedium */
{11, 40, 20, 10, 10, kControlSizeSmall}, /* kThemeScrollBarSmall */
};
HIThemeTrackDrawInfo info = {
.version = 0,
.min = 0.0,
.max = 100.0,
.attributes = kThemeTrackShowThumb,
.kind = kThemeScrollBarMedium,
};
@@ -107,7 +112,7 @@ TkpCreateScrollbar(
scrollPtr->troughGC = None;
scrollPtr->copyGC = None;
Tk_CreateEventHandler(tkwin,ExposureMask|StructureNotifyMask|FocusChangeMask|ButtonPressMask|VisibilityChangeMask, ScrollbarEventProc, scrollPtr);
Tk_CreateEventHandler(tkwin,ExposureMask|StructureNotifyMask|FocusChangeMask|ButtonPressMask|ButtonReleaseMask|EnterWindowMask|LeaveWindowMask|VisibilityChangeMask, ScrollbarEventProc, scrollPtr);
return (TkScrollbar *) scrollPtr;
}
@@ -212,7 +217,8 @@ TkpDisplayScrollbar(
*----------------------------------------------------------------------
*/
extern void
extern void
TkpComputeScrollbarGeometry(
register TkScrollbar *scrollPtr)
/* Scrollbar whose geometry may have
@@ -259,14 +265,12 @@ TkpComputeScrollbarGeometry(
if (scrollPtr->sliderLast > fieldLength) {
scrollPtr->sliderLast = fieldLength;
}
if (!(MOUNTAIN_LION_STYLE)) {
scrollPtr->sliderFirst += scrollPtr->inset +
metrics[variant].topArrowHeight;
scrollPtr->sliderLast += scrollPtr->inset +
metrics[variant].bottomArrowHeight;
}
/*
* Register the desired geometry for the window (leave enough space
scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset;
scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset;
/* Register the desired geometry for the window (leave enough space
* for the two arrows plus a minimum-size slider, plus border around
* the whole window, if any). Then arrange for the window to be
* redisplayed.
@@ -281,6 +285,9 @@ TkpComputeScrollbarGeometry(
}
/*
*----------------------------------------------------------------------
*
@@ -376,21 +383,22 @@ TkpScrollbarPosition(
register const int arrowSize = scrollPtr->arrowLength + inset;
if (scrollPtr->vertical) {
length = Tk_Height(scrollPtr->tkwin);
fieldlength = length - 2 * arrowSize;
width = Tk_Width(scrollPtr->tkwin);
length = Tk_Height(scrollPtr->tkwin);
fieldlength = length - 2 * arrowSize;
width = Tk_Width(scrollPtr->tkwin);
} else {
tmp = x;
x = y;
y = tmp;
length = Tk_Width(scrollPtr->tkwin);
fieldlength = length - 2 * arrowSize;
width = Tk_Height(scrollPtr->tkwin);
tmp = x;
x = y;
y = tmp;
length = Tk_Width(scrollPtr->tkwin);
fieldlength = length - 2 * arrowSize;
width = Tk_Height(scrollPtr->tkwin);
}
fieldlength = fieldlength < 0 ? 0 : fieldlength;
if (x<inset || x>=width-inset || y<inset || y>=length-inset) {
return OUTSIDE;
return OUTSIDE;
}
/*
@@ -399,18 +407,19 @@ TkpScrollbarPosition(
*/
if (y < scrollPtr->sliderFirst) {
return TOP_GAP;
return TOP_GAP;
}
if (y < scrollPtr->sliderLast) {
return SLIDER;
return SLIDER;
}
if (y < fieldlength){
return BOTTOM_GAP;
return BOTTOM_GAP;
}
if (y < fieldlength + arrowSize) {
return TOP_ARROW;
return TOP_ARROW;
}
return BOTTOM_ARROW;
}
/*
@@ -458,7 +467,7 @@ UpdateControlValues(
width = contrlRect.size.width;
height = contrlRect.size.height;
variant = contrlRect.size.width < metrics[0].width ? 1 : 0;
variant = contrlRect.size.width < metrics[0].width ? 1 : 0;
/*
* Ensure we set scrollbar control bounds only once all size adjustments
@@ -514,8 +523,8 @@ UpdateControlValues(
*
* ScrollbarPress --
*
* This procedure is invoked in response to <ButtonPress> events.
* Enters a modal loop to handle scrollbar interactions.
* This procedure is invoked in response to <ButtonPress>, <ButtonRelease>,
* <EnterNotify>, and <LeaveNotify> events. Scrollbar appearance is modified.
*
*--------------------------------------------------------------
*/
@@ -526,6 +535,13 @@ ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr)
if (eventPtr->type == ButtonPress) {
UpdateControlValues(scrollPtr);
info.trackInfo.scrollbar.pressState = 1;
}
if (eventPtr->type == EnterNotify) {
info.trackInfo.scrollbar.pressState = 1;
}
if (eventPtr->type == ButtonRelease || eventPtr->type == LeaveNotify) {
info.trackInfo.scrollbar.pressState = 0;
}
return TCL_OK;
}
@@ -566,6 +582,9 @@ ScrollbarEventProc(
TkScrollbarEventuallyRedraw(scrollPtr);
break;
case ButtonPress:
case ButtonRelease:
case EnterNotify:
case LeaveNotify:
ScrollbarPress(clientData, eventPtr);
break;
default:

View File

@@ -149,11 +149,27 @@ XMapWindow(
if (Tk_IsTopLevel(macWin->winPtr)) {
if (!Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *win = TkMacOSXDrawableWindow(window);
[NSApp activateIgnoringOtherApps:YES];
/*
* 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.
*/
[NSApp activateIgnoringOtherApps:NO];
if ( [win canBecomeKeyWindow] ) {
[win makeKeyAndOrderFront:NSApp];
}
TkMacOSXApplyWindowAttributes(macWin->winPtr, win);
} else {
/*
* Rebuild the container's clipping region and display
* the window.
*/
TkWindow *contWinPtr = TkpGetOtherWindow(macWin->winPtr);
TkMacOSXInvalClipRgns((Tk_Window)contWinPtr);
TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
}
TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr);
@@ -172,7 +188,8 @@ XMapWindow(
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
} else {
/*
* Generate damage for that area of the window.
* Rebuild the parent's clipping region and display the window.
*
*/
TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr->parentPtr);
@@ -247,13 +264,14 @@ XUnmapWindow(
Window window) /* Window. */
{
MacDrawable *macWin = (MacDrawable *) window;
TkWindow *winPtr = macWin->winPtr;
TkWindow *parentPtr = winPtr->parentPtr;
XEvent event;
display->request++;
macWin->winPtr->flags &= ~TK_MAPPED;
if (Tk_IsTopLevel(macWin->winPtr)) {
if (!Tk_IsEmbedded(macWin->winPtr) &&
macWin->winPtr->wmInfoPtr->hints.initial_state!=IconicState) {
if (Tk_IsTopLevel(winPtr)) {
if (!Tk_IsEmbedded(winPtr) &&
winPtr->wmInfoPtr->hints.initial_state!=IconicState) {
NSWindow *win = TkMacOSXDrawableWindow(window);
if ([win isVisible]) {
@@ -261,7 +279,7 @@ XUnmapWindow(
[win orderOut:NSApp];
}
}
TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr);
TkMacOSXInvalClipRgns((Tk_Window) winPtr);
/*
* We only need to send the UnmapNotify event for toplevel windows.
@@ -278,12 +296,17 @@ XUnmapWindow(
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
} else {
/*
* Generate damage for that area of the window.
* Rebuild the visRgn clip region for the parent so it will be allowed
* to draw in the space from which this subwindow was removed.
*/
TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr->parentPtr);
if (parentPtr && parentPtr->privatePtr->visRgn) {
TkMacOSXInvalidateViewRegion(TkMacOSXDrawableView(parentPtr->privatePtr),
parentPtr->privatePtr->visRgn);
}
TkMacOSXInvalClipRgns((Tk_Window) parentPtr);
TkMacOSXUpdateClipRgn(parentPtr);
}
winPtr->flags &= ~TK_MAPPED;
}
/*
@@ -365,7 +388,7 @@ XMoveResizeWindow(
CGFloat Y = (CGFloat)y;
CGFloat Width = (CGFloat)width;
CGFloat Height = (CGFloat)height;
CGFloat XOff = (CGFloat)macWin->winPtr->wmInfoPtr->xInParent;
CGFloat XOff = (CGFloat)macWin->winPtr->wmInfoPtr->xInParent;
CGFloat YOff = (CGFloat)macWin->winPtr->wmInfoPtr->yInParent;
NSRect r = NSMakeRect(X + XOff,
tkMacOSXZeroScreenHeight - Y - YOff - Height,
@@ -769,8 +792,8 @@ TkMacOSXUpdateClipRgn(
*/
if (!Tk_IsTopLevel(winPtr)) {
TkMacOSXUpdateClipRgn(winPtr->parentPtr);
if (winPtr->parentPtr) {
TkMacOSXUpdateClipRgn(winPtr->parentPtr);
ChkErr(HIShapeIntersect,
winPtr->parentPtr->privatePtr->aboveVisRgn,
rgn, rgn);

View File

@@ -17,6 +17,7 @@
#include "tkMacOSXWm.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXDebug.h"
#include "tkMacOSXConstants.h"
/*
#ifdef TK_MAC_DEBUG
@@ -41,14 +42,8 @@ static void DoWindowActivate(ClientData clientData);
extern NSString *NSWindowWillOrderOnScreenNotification;
extern NSString *NSWindowDidOrderOnScreenNotification;
extern NSString *NSWindowDidOrderOffScreenNotification;
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#define NSWindowWillStartLiveResizeNotification @"NSWindowWillStartLiveResizeNotification"
#define NSWindowDidEndLiveResizeNotification @"NSWindowDidEndLiveResizeNotification"
#endif
#endif
extern BOOL opaqueTag;
@implementation TKApplication(TKWindowEvent)
@@ -362,12 +357,12 @@ GenerateUpdates(
event.xexpose.width = damageBounds.size.width;
event.xexpose.height = damageBounds.size.height;
event.xexpose.count = 0;
Tk_HandleEvent(&event);
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
#ifdef TK_MAC_DEBUG_DRAWING
#ifdef TK_MAC_DEBUG_DRAWING
NSLog(@"Expose %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x,
event.xexpose.y, event.xexpose.width, event.xexpose.height);
#endif
#endif
/*
* Generate updates for the children of this window
@@ -749,17 +744,7 @@ TkWmProtocolEventProc(
int
Tk_MacOSXIsAppInFront(void)
{
Boolean isFrontProcess = true;
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
ProcessSerialNumber frontPsn, ourPsn = {0, kCurrentProcess};
if (noErr == GetFrontProcess(&frontPsn)){
SameProcess(&frontPsn, &ourPsn, &isFrontProcess);
}
#else
isFrontProcess = [NSRunningApplication currentApplication].active;
#endif
return (isFrontProcess == true);
return ([NSRunningApplication currentApplication].active == true);
}
#pragma mark TKContentView
@@ -858,7 +843,7 @@ ConfigureRestrictProc(
* Since it calls Tcl_DoOneEvent, we need to make sure we
* don't clobber the AutoreleasePool set up by the caller.
*/
[NSApp setPoolProtected:YES];
[NSApp _lockAutoreleasePool];
/*
* Try to prevent flickers and flashes.
@@ -889,7 +874,7 @@ ConfigureRestrictProc(
[w enableFlushWindow];
[w flushWindowIfNeeded];
NSEnableScreenUpdates();
[NSApp setPoolProtected:NO];
[NSApp _unlockAutoreleasePool];
}
}
@@ -914,16 +899,10 @@ ConfigureRestrictProc(
*/
- (void) generateExposeEvents: (HIShapeRef) shape
{
[self generateExposeEvents:shape childrenOnly:0];
}
- (void) generateExposeEvents: (HIShapeRef) shape
childrenOnly: (int) childrenOnly
{
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
unsigned long serial;
CGRect updateBounds;
int updatesNeeded;
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
if (!winPtr) {
return;
@@ -979,13 +958,8 @@ ConfigureRestrictProc(
{
NSWindow *w = [self window];
if (opaqueTag) {
return YES;
} else {
return (w && (([w styleMask] & NSTexturedBackgroundWindowMask) ||
return (w && (([w styleMask] & NSTexturedBackgroundWindowMask) ||
![w isOpaque]) ? NO : YES);
}
}
- (BOOL) wantsDefaultClipping

View File

@@ -10,6 +10,7 @@
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
* Copyright (c) 2010 Kevin Walzer/WordTech Communications LLC.
* Copyright (c) 2017 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -20,6 +21,7 @@
#include "tkMacOSXWm.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXDebug.h"
#include "tkMacOSXConstants.h"
#define DEBUG_ZOMBIES 0
@@ -53,9 +55,6 @@
| tkCanJoinAllSpacesAttribute | tkMoveToActiveSpaceAttribute \
| tkNonactivatingPanelAttribute | tkHUDWindowAttribute)
/*Objects for use in setting background color and opacity of window.*/
NSColor *colorName = NULL;
BOOL opaqueTag = FALSE;
static const struct {
const UInt64 validAttrs, defaultAttrs, forceOnAttrs, forceOffAttrs;
@@ -197,7 +196,6 @@ static Tcl_HashTable windowTable;
static int windowHashInit = false;
#pragma mark NSWindow(TKWm)
/*
@@ -214,7 +212,6 @@ static int windowHashInit = false;
{
return [self convertScreenToBase:point];
}
@end
#else
- (NSPoint) convertPointToScreen: (NSPoint) point
{
@@ -232,9 +229,10 @@ static int windowHashInit = false;
pointrect.size.height = 0;
return [self convertRectFromScreen:pointrect].origin;
}
@end
#endif
@end
#pragma mark -
@@ -364,25 +362,30 @@ static void GetMaxSize(TkWindow *winPtr, int *maxWidthPtr,
static void RemapWindows(TkWindow *winPtr,
MacDrawable *parentWin);
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
#define TK_GOT_AT_LEAST_SNOW_LEOPARD 1
#endif
#pragma mark TKWindow(TKWm)
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
@interface NSWindow(TkWm)
- (void) setCanCycle: (BOOL) canCycleFlag;
@end
#endif
@interface NSDrawerWindow : NSWindow
{
id _i1, _i2;
}
@end
@implementation TKWindow
@implementation TKWindow: NSWindow
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_12
/*
* Override automatic fullscreen button on >10.12 because system fullscreen API
* confuses Tk window geometry.
*/
- (void)toggleFullScreen:(id)sender
{
if ([self isZoomed]) {
TkMacOSXZoomToplevel(self, inZoomIn);
} else {
TkMacOSXZoomToplevel(self, inZoomOut);
}
}
#endif
@end
@implementation TKWindow(TKWm)
@@ -396,6 +399,8 @@ static void RemapWindows(TkWindow *winPtr,
kWindowNoActivatesAttribute)) ? NO : YES;
}
#if DEBUG_ZOMBIES
- (id) retain
{
@@ -412,7 +417,6 @@ static void RemapWindows(TkWindow *winPtr,
- (id) autorelease
{
static int xcount = 0;
id result = [super autorelease];
const char *title = [[self title] UTF8String];
if (title == nil) {
@@ -767,6 +771,10 @@ TkWmMapWindow(
XMapWindow(winPtr->display, winPtr->window);
/*Add window to Window menu.*/
NSWindow *win = TkMacOSXDrawableWindow(winPtr->window);
[win setExcludedFromWindowsMenu:NO];
}
/*
@@ -877,11 +885,6 @@ TkWmDeadWindow(
if (parent) {
[parent removeChildWindow:window];
}
[window close];
TkMacOSXUnregisterMacWindow(window);
if (winPtr->window) {
((MacDrawable *) winPtr->window)->view = nil;
}
#if DEBUG_ZOMBIES > 0
{
const char *title = [[window title] UTF8String];
@@ -891,17 +894,42 @@ TkWmDeadWindow(
printf(">>>> Closing <%s>. Count is: %lu\n", title, [window retainCount]);
}
#endif
[window release];
[window close];
TkMacOSXUnregisterMacWindow(window);
if (winPtr->window) {
((MacDrawable *) winPtr->window)->view = nil;
}
wmPtr->window = NULL;
[window release];
/* Activate the highest window left on the screen. */
NSArray *windows = [NSApp orderedWindows];
if ( [windows count] > 0 ) {
NSWindow *front = [windows objectAtIndex:0];
if ( front && [front canBecomeKeyWindow] ) {
[front makeKeyAndOrderFront:NSApp];
for (id nswindow in windows) {
TkWindow *winPtr2 = TkMacOSXGetTkWindow(nswindow);
if (winPtr2 && nswindow != window) {
WmInfo *wmPtr = winPtr2->wmInfoPtr;
BOOL minimized = (wmPtr->hints.initial_state == IconicState ||
wmPtr->hints.initial_state == WithdrawnState);
/*
* If no windows are left on the screen and the next
* window is iconified or withdrawn, we don't want to
* make it be the KeyWindow because that would cause
* it to be displayed on the screen.
*/
if ([nswindow canBecomeKeyWindow] && !minimized) {
[nswindow makeKeyAndOrderFront:NSApp];
break;
}
}
}
/*
* Process all window events immediately to force the closed window to
* be deallocated. But don't do this for the root window as that is
* unnecessary and can lead to segfaults.
*/
if (winPtr->parentPtr) {
while (Tk_DoOneEvent(TK_WINDOW_EVENTS|TK_DONT_WAIT)) {}
}
[NSApp _resetAutoreleasePool];
#if DEBUG_ZOMBIES > 0
@@ -1935,7 +1963,7 @@ WmGridCmd(
{
register WmInfo *wmPtr = winPtr->wmInfoPtr;
int reqWidth, reqHeight, widthInc, heightInc;
char *errorMsg;
const char *errorMsg;
if ((objc != 3) && (objc != 7)) {
Tcl_WrongNumArgs(interp, 2, objv,
@@ -2314,8 +2342,7 @@ WmIconnameCmd(
* WmIconphotoCmd --
*
* This procedure is invoked to process the "wm iconphoto" Tcl command.
* See the user documentation for details on what it does. Not yet
* implemented for OS X.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
@@ -2323,6 +2350,7 @@ WmIconnameCmd(
* Side effects:
* See the user documentation.
*
*
*----------------------------------------------------------------------
*/
@@ -2334,45 +2362,52 @@ WmIconphotoCmd(
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tk_PhotoHandle photo;
int i, width, height, isDefault = 0;
Tk_Image tk_icon;
int width, height, isDefault = 0;
if (objc < 4) {
Tcl_WrongNumArgs(interp, 2, objv,
"window ?-default? image1 ?image2 ...?");
"window ?-default? image1 ?image2 ...?");
return TCL_ERROR;
}
/*Parse args.*/
if (strcmp(Tcl_GetString(objv[3]), "-default") == 0) {
isDefault = 1;
if (objc == 4) {
Tcl_WrongNumArgs(interp, 2, objv,
"window ?-default? image1 ?image2 ...?");
"window ?-default? image1 ?image2 ...?");
return TCL_ERROR;
}
}
/*
* Iterate over all images to retrieve their sizes, in order to allocate a
* buffer large enough to hold all images.
*/
for (i = 3 + isDefault; i < objc; i++) {
photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i]));
if (photo == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"can't use \"%s\" as iconphoto: not a photo image",
Tcl_GetString(objv[i])));
Tcl_SetErrorCode(interp, "TK", "WM", "ICONPHOTO", "PHOTO", NULL);
return TCL_ERROR;
}
Tk_PhotoGetSize(photo, &width, &height);
/*Get icon name. We only use the first icon name because macOS does not
support multiple images in Tk photos.*/
char *icon;
if (strcmp(Tcl_GetString(objv[3]), "-default") == 0) {
icon = Tcl_GetString(objv[4]);
} else {
icon = Tcl_GetString(objv[3]);
}
/*
* TODO: This requires implementation for OS X, but we silently return for
* now.
*/
/*Get image and convert to NSImage that can be displayed as icon.*/
tk_icon = Tk_GetImage(interp, tkwin, icon, NULL, NULL);
if (tk_icon == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"can't use \"%s\" as iconphoto: not a photo image",
icon));
Tcl_SetErrorCode(interp, "TK", "WM", "ICONPHOTO", "PHOTO", NULL);
return TCL_ERROR;
}
NSImage *newIcon;
Tk_SizeOfImage(tk_icon, &width, &height);
newIcon = TkMacOSXGetNSImageWithTkImage(winPtr->display, tk_icon, width, height);
Tk_FreeImage(tk_icon);
if (newIcon == NULL) {
return TCL_ERROR;
}
[NSApp setApplicationIconImage: newIcon];
return TCL_OK;
}
@@ -2893,17 +2928,20 @@ WmProtocolCmd(
} else {
prevPtr->nextPtr = protPtr->nextPtr;
}
if (protPtr->command)
ckfree(protPtr->command);
Tcl_EventuallyFree(protPtr, TCL_DYNAMIC);
break;
}
}
cmd = Tcl_GetStringFromObj(objv[4], &cmdLength);
if (cmdLength > 0) {
protPtr = ckalloc(HANDLER_SIZE(cmdLength));
protPtr = ckalloc(sizeof(ProtocolHandler));
protPtr->protocol = protocol;
protPtr->nextPtr = wmPtr->protPtr;
wmPtr->protPtr = protPtr;
protPtr->interp = interp;
protPtr->command = ckalloc(cmdLength+1);
strcpy(protPtr->command, cmd);
}
return TCL_OK;
@@ -3472,6 +3510,10 @@ WmWithdrawCmd(
return TCL_ERROR;
}
TkpWmSetState(winPtr, WithdrawnState);
/*Remove window from Window menu.*/
NSWindow *win = TkMacOSXDrawableWindow(winPtr->window);
[win setExcludedFromWindowsMenu:YES];
return TCL_OK;
}
@@ -4632,44 +4674,50 @@ TkWmRestackToplevel(
* below *all* siblings. */
{
NSWindow *macWindow;
NSInteger otherMacWindowNumber;
NSWindow *otherMacWindow;
WmInfo *wmPtr = winPtr->wmInfoPtr;
int macAboveBelow = (aboveBelow == Above ? NSWindowAbove : NSWindowBelow);
int otherNumber = 0; /* 0 will be used when otherPtr is NULL. */
/*
* Get the mac window. Make sure it exists & is mapped.
* If the Tk windows has no drawable, or is withdrawn do nothing.
*/
if (winPtr->window == None) {
Tk_MakeWindowExist((Tk_Window) winPtr);
}
if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
/*
* Can't set stacking order properly until the window is on the screen
* (mapping it may give it a reparent window), so make sure it's on
* the screen.
*/
TkWmMapWindow(winPtr);
if (winPtr->window == None ||
wmPtr == NULL ||
wmPtr->hints.initial_state == WithdrawnState) {
return;
}
macWindow = TkMacOSXDrawableWindow(winPtr->window);
if (macWindow == nil) {
return;
}
if (otherPtr) {
/*
* When otherPtr is non-NULL, if the other window has no
* drawable or is withdrawn, do nothing.
*/
WmInfo *otherWmPtr = otherPtr->wmInfoPtr;
if (winPtr->window == None ||
otherWmPtr == NULL ||
otherWmPtr->hints.initial_state == WithdrawnState) {
return;
}
otherMacWindow = TkMacOSXDrawableWindow(otherPtr->window);
if (otherMacWindow == nil) {
return;
} else {
/*
* If the other window is OK, get its number.
*/
otherNumber = [otherMacWindow windowNumber];
}
}
/*
* Get the window in which a raise or lower is in relation to.
* Just let the Mac window manager deal with all the subtleties
* of keeping track of off-screen windows, etc.
*/
if (otherPtr != NULL) {
if (otherPtr->window == None) {
Tk_MakeWindowExist((Tk_Window) otherPtr);
}
if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
TkWmMapWindow(otherPtr);
}
otherMacWindowNumber = [TkMacOSXDrawableWindow(otherPtr->window)
windowNumber];
} else {
otherMacWindowNumber = 0;
}
[macWindow orderWindow:(aboveBelow == Above ? NSWindowAbove : NSWindowBelow)
relativeTo:otherMacWindowNumber];
[macWindow orderWindow:macAboveBelow relativeTo:otherNumber];
}
/*
@@ -5089,8 +5137,8 @@ TkMacOSXGetTkWindow(
*
* TkMacOSXIsWindowZoomed --
*
* Ask Carbon if the given window is in the zoomed out state. Because
* dragging & growing a window can change the Carbon zoom state, we
* Ask Cocoa if the given window is in the zoomed out state. Because
* dragging & growing a window can change the Cocoa zoom state, we
* cannot rely on wmInfoPtr->hints.initial_state for this information.
*
* Results:
@@ -5108,6 +5156,7 @@ TkMacOSXIsWindowZoomed(
{
return [TkMacOSXDrawableWindow(winPtr->window) isZoomed];
}
/*
*----------------------------------------------------------------------
@@ -5150,12 +5199,13 @@ TkMacOSXZoomToplevel(
* Do nothing if already in desired zoom state.
*/
if (![window isZoomed] == (zoomPart == inZoomIn)) {
if ((![window isZoomed] == (zoomPart == inZoomIn))) {
return false;
}
[window zoom:NSApp];
wmPtr->hints.initial_state =
(zoomPart == inZoomIn ? NormalState : ZoomState);
[window zoom:NSApp];
wmPtr->hints.initial_state =
(zoomPart == inZoomIn ? NormalState : ZoomState);
return true;
}
@@ -5193,54 +5243,13 @@ TkUnsupported1ObjCmd(
};
Tk_Window tkwin = clientData;
TkWindow *winPtr;
int index, i;
int index;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "option window ?arg ...?");
return TCL_ERROR;
}
/*
* Iterate through objc/objv to set correct background color and toggle
* opacity of window.
*/
for (i= 0; i < objc; i++) {
if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*black*")) {
colorName = [NSColor blackColor]; // use #000000 in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*dark*")) {
colorName = [NSColor darkGrayColor]; //use #545454 in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*light*")) {
colorName = [NSColor lightGrayColor]; //use #ababab in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*white*")) {
colorName = [NSColor whiteColor]; //use #ffffff in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "gray*")) {
colorName = [NSColor grayColor]; //use #7f7f7f in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*red*")) {
colorName = [NSColor redColor]; //use #ff0000 in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*green*")) {
colorName = [NSColor greenColor]; //use #00ff00 in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*blue*")) {
colorName = [NSColor blueColor]; //use #0000ff in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*cyan*")) {
colorName = [NSColor cyanColor]; //use #00ffff in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*yellow*")) {
colorName = [NSColor yellowColor]; //use #ffff00 in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*magenta*")) {
colorName = [NSColor magentaColor]; //use #ff00ff in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*orange*")) {
colorName = [NSColor orangeColor]; //use #ff8000 in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*purple*")) {
colorName = [NSColor purpleColor]; //use #800080 in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*brown*")){
colorName = [NSColor brownColor]; //use #996633 in Tk scripts to match
} else if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*clear*")) {
colorName = [NSColor clearColor]; //use systemTransparent in Tk scripts to match
}
if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*opacity*")) {
opaqueTag = YES;
}
}
winPtr = (TkWindow *)
Tk_NameToWindow(interp, Tcl_GetString(objv[2]), tkwin);
@@ -5603,6 +5612,7 @@ TkMacOSXMakeRealWindowExist(
}
TKContentView *contentView = [[TKContentView alloc]
initWithFrame:NSZeroRect];
[window setColorSpace:[NSColorSpace deviceRGBColorSpace]];
[window setContentView:contentView];
[contentView release];
[window setDelegate:NSApp];
@@ -5621,20 +5631,6 @@ TkMacOSXMakeRealWindowExist(
[window setMovableByWindowBackground:NO];
}
/* Set background color and opacity of window if those flags are set. */
if (colorName != NULL) {
[window setBackgroundColor: colorName];
}
if (opaqueTag) {
#ifdef TK_GOT_AT_LEAST_SNOW_LEOPARD
[window setOpaque: opaqueTag];
#else
[window setOpaque: YES];
#endif
}
[window setDocumentEdited:NO];
wmPtr->window = window;
macWin->view = window.contentView;
@@ -6325,24 +6321,12 @@ ApplyWindowAttributeFlagChanges(
} else if (newAttributes & tkMoveToActiveSpaceAttribute) {
b |= NSWindowCollectionBehaviorMoveToActiveSpace;
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
if (newAttributes & kWindowDoesNotCycleAttribute) {
b |= NSWindowCollectionBehaviorIgnoresCycle;
} else {
b |= NSWindowCollectionBehaviorParticipatesInCycle;
}
#endif
[macWindow setCollectionBehavior:b];
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
if (((changedAttributes & kWindowDoesNotCycleAttribute) || initial)
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
&& tkMacOSXMacOSXVersion < 1060
#endif
) {
[macWindow setCanCycle:
!(newAttributes & kWindowDoesNotCycleAttribute)];
}
#endif
}
if ((wmPtr->flags & WM_TOPMOST) != (oldFlags & WM_TOPMOST)) {
[macWindow setLevel:(wmPtr->flags & WM_TOPMOST) ?
@@ -6474,9 +6458,7 @@ TkMacOSXMakeFullscreen(
{
WmInfo *wmPtr = winPtr->wmInfoPtr;
int result = TCL_OK, wasFullscreen = (wmPtr->flags & WM_FULLSCREEN);
#ifdef TK_GOT_AT_LEAST_SNOW_LEOPARD
static unsigned long prevMask = 0, prevPres = 0;
#endif /*TK_GOT_AT_LEAST_SNOW_LEOPARD*/
if (fullscreen) {
int screenWidth = WidthOfScreen(Tk_Screen(winPtr));
@@ -6498,6 +6480,7 @@ TkMacOSXMakeFullscreen(
result = TCL_ERROR;
wmPtr->flags &= ~WM_FULLSCREEN;
} else {
Tk_UnmapWindow((Tk_Window) winPtr);
NSRect bounds = [window contentRectForFrameRect:[window frame]];
NSRect screenBounds = NSMakeRect(0, 0, screenWidth, screenHeight);
@@ -6516,30 +6499,20 @@ TkMacOSXMakeFullscreen(
wmPtr->flags |= WM_FULLSCREEN;
}
#ifdef TK_GOT_AT_LEAST_SNOW_LEOPARD
/*
* We can't set these features on Leopard or earlier, as they don't
* exist (neither options nor API that uses them). This formally means
* that there's a bug with full-screen windows with Tk on old OSX, but
* it isn't worth blocking a build just for this.
*/
prevMask = [window styleMask];
prevPres = [NSApp presentationOptions];
[window setStyleMask: NSBorderlessWindowMask];
[NSApp setPresentationOptions: NSApplicationPresentationAutoHideDock
| NSApplicationPresentationAutoHideMenuBar];
#endif /*TK_GOT_AT_LEAST_SNOW_LEOPARD*/
Tk_MapWindow((Tk_Window) winPtr);
} else {
wmPtr->flags &= ~WM_FULLSCREEN;
#ifdef TK_GOT_AT_LEAST_SNOW_LEOPARD
[NSApp setPresentationOptions: prevPres];
[window setStyleMask: prevMask];
#endif /*TK_GOT_AT_LEAST_SNOW_LEOPARD*/
}
if (wasFullscreen && !(wmPtr->flags & WM_FULLSCREEN)) {
Tk_UnmapWindow((Tk_Window) winPtr);
UInt64 oldAttributes = wmPtr->attributes;
NSRect bounds = NSMakeRect(wmPtr->configX, tkMacOSXZeroScreenHeight -
(wmPtr->configY + wmPtr->yInParent + wmPtr->configHeight),
@@ -6553,6 +6526,7 @@ TkMacOSXMakeFullscreen(
wmPtr->flags |= WM_SYNC_PENDING;
[window setFrame:[window frameRectForContentRect:bounds] display:YES];
wmPtr->flags &= ~WM_SYNC_PENDING;
Tk_MapWindow((Tk_Window) winPtr);
}
return result;
}

View File

@@ -29,15 +29,13 @@ typedef struct ProtocolHandler {
* same top-level window, or NULL for end of
* list. */
Tcl_Interp *interp; /* Interpreter in which to invoke command. */
char command[4]; /* Tcl command to invoke when a client message
char* command; /* Tcl command to invoke when a client message
* for this protocol arrives. The actual size
* of the structure varies to accommodate the
* needs of the actual command. THIS MUST BE
* THE LAST FIELD OF THE STRUCTURE. */
} ProtocolHandler;
#define HANDLER_SIZE(cmdLength) \
((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength))
/*
* A data structure of the following type holds window-manager-related

View File

@@ -53,14 +53,6 @@ static XID MacXIdAlloc(Display *display);
static int DefaultErrorHandler(Display *display,
XErrorEvent *err_evt);
/*
* Other declarations
*/
static int DestroyImage(XImage *image);
static unsigned long ImageGetPixel(XImage *image, int x, int y);
static int ImagePutPixel(XImage *image, int x, int y,
unsigned long pixel);
/*
*----------------------------------------------------------------------
@@ -183,7 +175,7 @@ TkpOpenDisplay(
{
int major, minor, patch;
#if MAC_OS_X_VERSION_MIN_REQUIRED < 10100
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
Gestalt(gestaltSystemVersionMajor, (SInt32*)&major);
Gestalt(gestaltSystemVersionMinor, (SInt32*)&minor);
Gestalt(gestaltSystemVersionBugFix, (SInt32*)&patch);
@@ -208,6 +200,7 @@ TkpOpenDisplay(
screen->root_visual = ckalloc(sizeof(Visual));
screen->root_visual->visualid = 0;
screen->root_visual->class = TrueColor;
screen->root_visual->alpha_mask = 0xFF000000;
screen->root_visual->red_mask = 0x00FF0000;
screen->root_visual->green_mask = 0x0000FF00;
screen->root_visual->blue_mask = 0x000000FF;
@@ -383,13 +376,6 @@ XGetAtomName(
return NULL;
}
int
_XInitImageFuncPtrs(
XImage *image)
{
return 0;
}
XErrorHandler
XSetErrorHandler(
XErrorHandler handler)
@@ -528,7 +514,7 @@ XClearWindow(
}
/*
void
int
XDrawPoint(
Display* display,
Drawable d,
@@ -538,7 +524,7 @@ XDrawPoint(
{
}
void
int
XDrawPoints(
Display* display,
Drawable d,
@@ -763,386 +749,6 @@ TkGetServerInfo(
buffer2, NULL);
}
#pragma mark XImage handling
/*
*----------------------------------------------------------------------
*
* XCreateImage --
*
* Allocates storage for a new XImage.
*
* Results:
* Returns a newly allocated XImage.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
XImage *
XCreateImage(
Display* display,
Visual* visual,
unsigned int depth,
int format,
int offset,
char* data,
unsigned int width,
unsigned int height,
int bitmap_pad,
int bytes_per_line)
{
XImage *ximage;
display->request++;
ximage = ckalloc(sizeof(XImage));
ximage->height = height;
ximage->width = width;
ximage->depth = depth;
ximage->xoffset = offset;
ximage->format = format;
ximage->data = data;
ximage->obdata = NULL;
/* 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) {
ximage->bits_per_pixel = 32;
ximage->bitmap_unit = 32;
} else {
ximage->bits_per_pixel = 1;
ximage->bitmap_unit = 8;
}
if (bitmap_pad) {
ximage->bitmap_pad = bitmap_pad;
} else {
/* Use 16 byte alignment for best Quartz perfomance */
ximage->bitmap_pad = 128;
}
if (bytes_per_line) {
ximage->bytes_per_line = bytes_per_line;
} else {
ximage->bytes_per_line = ((width * ximage->bits_per_pixel +
(ximage->bitmap_pad - 1)) >> 3) &
~((ximage->bitmap_pad >> 3) - 1);
}
#ifdef WORDS_BIGENDIAN
ximage->byte_order = MSBFirst;
ximage->bitmap_bit_order = MSBFirst;
#else
ximage->byte_order = LSBFirst;
ximage->bitmap_bit_order = LSBFirst;
#endif
ximage->red_mask = 0x00FF0000;
ximage->green_mask = 0x0000FF00;
ximage->blue_mask = 0x000000FF;
ximage->f.create_image = NULL;
ximage->f.destroy_image = DestroyImage;
ximage->f.get_pixel = ImageGetPixel;
ximage->f.put_pixel = ImagePutPixel;
ximage->f.sub_image = NULL;
ximage->f.add_pixel = NULL;
return ximage;
}
/*
*----------------------------------------------------------------------
*
* XGetImage --
*
* This function copies data from a pixmap or window into an XImage.
*
* Results:
* Returns a newly allocated XImage containing the data from the given
* rectangle of the given drawable, or NULL if the XImage could not be
* constructed. NOTE: If we are copying from a window on a Retina
* display, the dimensions of the XImage will be 2*width x 2*height.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
XImage *
XGetImage(
Display *display,
Drawable d,
int x,
int y,
unsigned int width,
unsigned int height,
unsigned long plane_mask,
int format)
{
NSBitmapImageRep *bitmap_rep;
NSUInteger bitmap_fmt;
XImage * imagePtr = NULL;
char * bitmap = NULL;
char * image_data=NULL;
int depth = 32;
int offset = 0;
int bitmap_pad = 0;
int bytes_per_row = 4*width;
int size;
MacDrawable *macDraw = (MacDrawable *) d;
NSWindow *win = TkMacOSXDrawableWindow(d);
/* This code assumes that backing scale factors are integers. Currently
* Retina displays use a scale factor of 2.0 and normal displays use 1.0.
* We do not support any other values here.
*/
int scalefactor = 1;
if (win && [win respondsToSelector:@selector(backingScaleFactor)]) {
scalefactor = ([win backingScaleFactor] == 2.0) ? 2 : 1;
}
int scaled_height = height * scalefactor;
int scaled_width = width * scalefactor;
if (format == ZPixmap) {
if (width == 0 || height == 0) {
/* This happens all the time.
TkMacOSXDbgMsg("XGetImage: empty image requested");
*/
return NULL;
}
bitmap_rep = BitmapRepFromDrawableRect(d, x, y, width, height);
bitmap_fmt = [bitmap_rep bitmapFormat];
if ( bitmap_rep == Nil ||
(bitmap_fmt != 0 && bitmap_fmt != 1) ||
[bitmap_rep samplesPerPixel] != 4 ||
[bitmap_rep isPlanar] != 0 ) {
TkMacOSXDbgMsg("XGetImage: Failed to construct NSBitmapRep");
return NULL;
}
NSSize image_size = NSMakeSize(width, height);
NSImage* ns_image = [[NSImage alloc]initWithSize:image_size];
[ns_image addRepresentation:bitmap_rep];
/* Assume premultiplied nonplanar data with 4 bytes per pixel.*/
if ( [bitmap_rep isPlanar ] == 0 &&
[bitmap_rep samplesPerPixel] == 4 ) {
bytes_per_row = [bitmap_rep bytesPerRow];
assert(bytes_per_row == 4 * scaled_width);
assert([bitmap_rep bytesPerPlane] == bytes_per_row * scaled_height);
size = bytes_per_row*scaled_height;
image_data = (char*)[bitmap_rep bitmapData];
if ( image_data ) {
int row, n, m;
bitmap = ckalloc(size);
/*
Oddly enough, the bitmap has the top row at the beginning,
and the pixels are in BGRA or ABGR format.
*/
if (bitmap_fmt == 0) {
/* BGRA */
for (row=0, n=0; row<scaled_height; row++, n+=bytes_per_row) {
for (m=n; m<n+bytes_per_row; m+=4) {
*(bitmap+m) = *(image_data+m+2);
*(bitmap+m+1) = *(image_data+m+1);
*(bitmap+m+2) = *(image_data+m);
*(bitmap+m+3) = *(image_data+m+3);
}
}
} else {
/* ABGR */
for (row=0, n=0; row<scaled_height; row++, n+=bytes_per_row) {
for (m=n; m<n+bytes_per_row; m+=4) {
*(bitmap+m) = *(image_data+m+3);
*(bitmap+m+1) = *(image_data+m+2);
*(bitmap+m+2) = *(image_data+m+1);
*(bitmap+m+3) = *(image_data+m);
}
}
}
}
}
if (bitmap) {
imagePtr = XCreateImage(display, NULL, depth, format, offset,
(char*)bitmap, scaled_width, scaled_height,
bitmap_pad, bytes_per_row);
if (scalefactor == 2) {
imagePtr->pixelpower = 1;
}
[ns_image removeRepresentation:bitmap_rep]; /*releases the rep*/
[ns_image release];
}
} else {
TkMacOSXDbgMsg("Could not extract image from drawable.");
}
return imagePtr;
}
/*
*----------------------------------------------------------------------
*
* DestroyImage --
*
* Destroys storage associated with an image.
*
* Results:
* None.
*
* Side effects:
* Deallocates the image.
*
*----------------------------------------------------------------------
*/
static int
DestroyImage(
XImage *image)
{
if (image) {
if (image->data) {
ckfree(image->data);
}
ckfree(image);
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* ImageGetPixel --
*
* Get a single pixel from an image.
*
* Results:
* Returns the 32 bit pixel value.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static unsigned long
ImageGetPixel(
XImage *image,
int x,
int y)
{
unsigned char r = 0, g = 0, b = 0;
if (image && image->data) {
unsigned char *srcPtr = ((unsigned char*) image->data)
+ (y * image->bytes_per_line)
+ (((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;
}
}
return (PIXEL_MAGIC << 24) | (r << 16) | (g << 8) | b;
}
/*
*----------------------------------------------------------------------
*
* ImagePutPixel --
*
* Set a single pixel in an image.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
ImagePutPixel(
XImage *image,
int x,
int y,
unsigned long pixel)
{
if (image && image->data) {
unsigned char r = ((pixel & image->red_mask) >> 16) & 0xff;
unsigned char g = ((pixel & image->green_mask) >> 8) & 0xff;
unsigned char b = ((pixel & image->blue_mask) ) & 0xff;
unsigned char *dstPtr = ((unsigned char*) image->data)
+ (y * image->bytes_per_line)
+ (((image->xoffset + x) * image->bits_per_pixel) / NBBY);
switch (image->bits_per_pixel) {
case 32:
*((unsigned int*) dstPtr) = (0xff << 24) | (r << 16) |
(g << 8) | b;
/*if (image->byte_order == LSBFirst) {
dstPtr[3] = 0xff; dstPtr[2] = r; dstPtr[1] = g; dstPtr[0] = b;
} else {
dstPtr[0] = 0xff; dstPtr[1] = r; dstPtr[2] = g; dstPtr[3] = b;
}*/
break;
case 16:
*((unsigned short*) dstPtr) = ((r & 0xf8) << 7) |
((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
break;
case 8:
*dstPtr = ((r & 0xc0) >> 2) | ((g & 0xc0) >> 4) |
((b & 0xc0) >> 6);
break;
case 4: {
unsigned char c = ((r & 0x80) >> 5) | ((g & 0x80) >> 6) |
((b & 0x80) >> 7);
*dstPtr = (x % 2) ? ((*dstPtr & 0xf0) | (c & 0x0f)) :
((*dstPtr & 0x0f) | ((c << 4) & 0xf0));
break;
}
case 1:
*dstPtr = ((r|g|b) & 0x80) ? (*dstPtr | (0x80 >> (x % 8))) :
(*dstPtr & ~(0x80 >> (x % 8)));
break;
}
}
return 0;
}
/*
*----------------------------------------------------------------------
*
@@ -1367,7 +973,7 @@ void
Tk_ResetUserInactiveTime(
Display *dpy)
{
IOGPoint loc;
IOGPoint loc = {0, 0};
kern_return_t kr;
NXEvent nullEvent = {NX_NULLEVENT, {0, 0}, 0, -1, 0};
enum { kNULLEventPostThrottle = 10 };