Import Tk 8.6.8
This commit is contained in:
316
macosx/README
316
macosx/README
@@ -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.
|
||||
|
||||
|
||||
@@ -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 */,
|
||||
|
||||
@@ -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 */,
|
||||
|
||||
@@ -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
64
macosx/configure
vendored
Normal file → Executable 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
|
||||
;;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)]]) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "tkMacOSXPrivate.h"
|
||||
#include "tkMacOSXEvent.h"
|
||||
#include "tkMacOSXConstants.h"
|
||||
|
||||
/*
|
||||
#ifdef TK_MAC_DEBUG
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "tkMacOSXWm.h"
|
||||
#include "tkMacOSXEvent.h"
|
||||
#include "tkMacOSXDebug.h"
|
||||
#include "tkMacOSXConstants.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned int state;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user