summaryrefslogtreecommitdiffstats
path: root/macosx
diff options
context:
space:
mode:
authorfvogel <fvogelnew1@free.fr>2016-01-11 13:23:20 (GMT)
committerfvogel <fvogelnew1@free.fr>2016-01-11 13:23:20 (GMT)
commitddae56bbd0023f29a24d0529ed4fa0e3820ce7f2 (patch)
tree87dfd77a94fb45488edde792e3b0735459a1fea7 /macosx
parent5c01788dc22a4a2f8e6d9e943dc61a5b73b28291 (diff)
parent4a2efd946fe6674e460172920d097f7329d8e5d9 (diff)
downloadtk-ddae56bbd0023f29a24d0529ed4fa0e3820ce7f2.zip
tk-ddae56bbd0023f29a24d0529ed4fa0e3820ce7f2.tar.gz
tk-ddae56bbd0023f29a24d0529ed4fa0e3820ce7f2.tar.bz2
merged trunk
Diffstat (limited to 'macosx')
-rw-r--r--macosx/GNUmakefile2
-rw-r--r--macosx/README61
-rw-r--r--macosx/Tk-Info.plist.in4
-rw-r--r--macosx/Wish-Info.plist.in14
-rw-r--r--macosx/tkMacOSXButton.c1872
-rw-r--r--macosx/tkMacOSXCursor.c5
-rw-r--r--macosx/tkMacOSXDefault.h37
-rw-r--r--macosx/tkMacOSXDialog.c208
-rw-r--r--macosx/tkMacOSXDraw.c416
-rw-r--r--macosx/tkMacOSXEmbed.c54
-rw-r--r--macosx/tkMacOSXEvent.c33
-rw-r--r--macosx/tkMacOSXFont.c28
-rw-r--r--macosx/tkMacOSXHLEvents.c749
-rw-r--r--macosx/tkMacOSXInit.c84
-rw-r--r--macosx/tkMacOSXInt.h5
-rw-r--r--macosx/tkMacOSXKeyEvent.c80
-rw-r--r--macosx/tkMacOSXKeyboard.c3
-rw-r--r--macosx/tkMacOSXMenu.c67
-rw-r--r--macosx/tkMacOSXMenubutton.c992
-rw-r--r--macosx/tkMacOSXMenus.c17
-rw-r--r--macosx/tkMacOSXMouseEvent.c121
-rw-r--r--macosx/tkMacOSXNotify.c157
-rw-r--r--macosx/tkMacOSXPort.h10
-rw-r--r--macosx/tkMacOSXPrivate.h72
-rw-r--r--macosx/tkMacOSXRegion.c64
-rw-r--r--macosx/tkMacOSXScale.c2
-rw-r--r--macosx/tkMacOSXScrlbr.c730
-rw-r--r--macosx/tkMacOSXSubwindows.c96
-rw-r--r--macosx/tkMacOSXTest.c14
-rw-r--r--macosx/tkMacOSXWindowEvent.c379
-rw-r--r--macosx/tkMacOSXWm.c220
-rw-r--r--macosx/tkMacOSXXStubs.c149
-rw-r--r--macosx/ttkMacOSXTheme.c18
33 files changed, 3728 insertions, 3035 deletions
diff --git a/macosx/GNUmakefile b/macosx/GNUmakefile
index 333961c..02240ed 100644
--- a/macosx/GNUmakefile
+++ b/macosx/GNUmakefile
@@ -134,7 +134,7 @@ endif
INSTALL_TARGETS = install-binaries install-libraries
ifeq (${EMBEDDED_BUILD},)
-INSTALL_TARGETS += install-private-headers install-demos
+INSTALL_TARGETS += install-private-headers install-headers install-demos
endif
ifeq (${INSTALL_BUILD}_${EMBEDDED_BUILD}_${BUILD_STYLE},1__Deployment)
INSTALL_TARGETS += html-tk
diff --git a/macosx/README b/macosx/README
index 69be037..202dbbd 100644
--- a/macosx/README
+++ b/macosx/README
@@ -388,3 +388,64 @@ make overrides to the tk/macosx GNUmakefile, e.g.
sudo make -C tk${ver}/macosx install \
TCL_FRAMEWORK_DIR=$HOME/Library/Frameworks TCLSH_DIR=$HOME/usr/bin
The Makefile variables TCL_FRAMEWORK_DIR and TCLSH_DIR were added with Tk 8.4.3.
+
+4. About the event loop in Tk for Mac OSX
+-----------------------------------------
+
+The main program in a typical OSX application looks like this (see *)
+
+ void NSApplicationMain(int argc, char *argv[]) {
+ [NSApplication sharedApplication];
+ [NSBundle loadNibNamed:@"myMain" owner:NSApp];
+ [NSApp run];
+ }
+
+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
+NSAutoreleasePool. Third, it starts an event loop which drains the
+NSAutoreleasePool every time the queue is empty, and replaces the
+drained pool with a new one. This third step is essential to
+preventing memory leaks, since the internal methods of Appkit objects
+all assume that an autorelease pool is in scope and will be drained
+when the event processing cycle ends.
+
+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.
+
+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.
+
+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.
+
+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
+NSAutoreleasePools whenever they call methods of Appkit objects
+(e.g. NSFont).
+
+* https://developer.apple.com/library/mac/documentation/Cocoa/\
+Reference/ApplicationKit/Classes/NSApplication_Class
diff --git a/macosx/Tk-Info.plist.in b/macosx/Tk-Info.plist.in
index 50b9d24..7b0c305 100644
--- a/macosx/Tk-Info.plist.in
+++ b/macosx/Tk-Info.plist.in
@@ -17,6 +17,10 @@
<string>Tk @TK_WINDOWINGSYSTEM@ @TK_VERSION@@TK_PATCH_LEVEL@,
Copyright © 1989-@TK_YEAR@ Tcl Core Team,
Copyright © 2002-@TK_YEAR@ Daniel A. Steffen,
+ Copyright © 1989-@TK_YEAR@ Contributors,
+ Copyright © 2011-@TK_YEAR@ Kevin Walzer/WordTech
+ Communications LLC,
+ Copyright © 2014-@TK_YEAR@ Marc Culler,
Copyright © 2001-2009 Apple Inc.,
Copyright © 2001-2002 Jim Ingham &amp; Ian Reid</string>
<key>CFBundleIdentifier</key>
diff --git a/macosx/Wish-Info.plist.in b/macosx/Wish-Info.plist.in
index 90e00a4..db75cf2 100644
--- a/macosx/Wish-Info.plist.in
+++ b/macosx/Wish-Info.plist.in
@@ -40,10 +40,14 @@
<string>Wish</string>
<key>CFBundleGetInfoString</key>
<string>Wish Shell @TK_VERSION@@TK_PATCH_LEVEL@,
-Copyright © 1989-@TK_YEAR@ Tcl Core Team,
-Copyright © 2002-@TK_YEAR@ Daniel A. Steffen,
-Copyright © 2001-2009 Apple Inc.,
-Copyright © 2001-2002 Jim Ingham &amp; Ian Reid</string>
+ Copyright © 1989-@TK_YEAR@ Tcl Core Team,
+ Copyright © 1989-@TK_YEAR@ Contributors,
+ Copyright © 2011-@TK_YEAR@ Kevin Walzer/WordTech
+ Communications LLC,
+ Copyright © 2014-@TK_YEAR@ Marc Culler,
+ Copyright © 2002-@TK_YEAR@ Daniel A. Steffen,
+ Copyright © 2001-2009 Apple Inc.,
+ Copyright © 2001-2002 Jim Ingham &amp; Ian Reid</string>
<key>CFBundleIconFile</key>
<string>Wish.icns</string>
<key>CFBundleIdentifier</key>
@@ -72,5 +76,7 @@ Copyright © 2001-2002 Jim Ingham &amp; Ian Reid</string>
<true/>
<key>OSAScriptingDefinition</key>
<string>Wish.sdef</string>
+ <key>NSHighResolutionCapable</key>
+ <string>True</string>
</dict>
</plist>
diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c
index 036624d..59d394e 100644
--- a/macosx/tkMacOSXButton.c
+++ b/macosx/tkMacOSXButton.c
@@ -5,11 +5,15 @@
* button widgets.
*
* Copyright (c) 1996-1997 by Sun Microsystems, Inc.
- * Copyright 2001-2009, Apple Inc.
- * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2001, Apple Computer, Inc.
+ * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2007 Revar Desmera.
+ * Copyright 2015 Kevin Walzer/WordTech Communications LLC.
+ * Copyright 2015 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
*/
#include "tkMacOSXPrivate.h"
@@ -17,60 +21,82 @@
#include "tkMacOSXFont.h"
#include "tkMacOSXDebug.h"
+
+#define FIRST_DRAW 2
+#define ACTIVE 4
+
+
/*
-#ifdef TK_MAC_DEBUG
-#define TK_MAC_DEBUG_BUTTON
-#endif
-*/
-
-typedef struct MacButton {
- TkButton info;
- NSButton *button;
- NSImage *image, *selectImage, *tristateImage;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- int fix;
-#endif
-} MacButton;
+ * Default insets for controls
+ */
+
+#define DEF_INSET_LEFT 12
+#define DEF_INSET_RIGHT 12
+#define DEF_INSET_TOP 1
+#define DEF_INSET_BOTTOM 1
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+/*
+ * Some defines used to control what type of control is drawn.
+ */
-int tkMacOSXUseCompatibilityMetrics = 1;
+#define DRAW_LABEL 0 /* Labels are treated genericly. */
+#define DRAW_CONTROL 1 /* Draw using the Native control. */
+#define DRAW_CUSTOM 2 /* Make our own button drawing. */
+#define DRAW_BEVEL 3
/*
- * Use the following heuristic conversion constants to make NSButton-based
- * widget metrics match up with the old Carbon control buttons (for the
- * default Lucida Grande 13 font).
+ * The delay in milliseconds between pulsing default button redraws.
+ */
+#define PULSE_TIMER_MSECS 62 /* Largest value that didn't look stuttery */
+
+/*
+ * Declaration of Mac specific button structure.
*/
-#define NATIVE_BUTTON_INSET 2
-#define NATIVE_BUTTON_EXTRA_H 2
typedef struct {
- int trimW, trimH, inset, shrinkH, offsetX, offsetY;
-} BoundsFix;
-
-#define fixForTypeStyle(type, style) ( \
- type == NSSwitchButton ? 0 : \
- type == NSRadioButton ? 1 : \
- style == NSRoundedBezelStyle ? 2 : \
- style == NSRegularSquareBezelStyle ? 3 : \
- style == NSShadowlessSquareBezelStyle ? 4 : \
- INT_MIN)
-
-static const BoundsFix boundsFixes[] = {
- [fixForTypeStyle(NSSwitchButton,0)] = { 2, 2, -1, 0, 2, 1 },
- [fixForTypeStyle(NSRadioButton,0)] = { 0, 2, -1, 0, 1, 1 },
- [fixForTypeStyle(0,NSRoundedBezelStyle)] = { 28, 16, -6, 0, 0, 3 },
- [fixForTypeStyle(0,NSRegularSquareBezelStyle)] = { 28, 15, -2, -1 },
- [fixForTypeStyle(0,NSShadowlessSquareBezelStyle)] = { 2, 2 },
-};
+ int drawType;
+ Tk_3DBorder border;
+ int relief;
+ int offset; /* 0 means this is a normal widget. 1 means
+ * it is an image button, so we offset the
+ * image to make the button appear to move
+ * up and down as the relief changes. */
+ GC gc;
+ int hasImageOrBitmap;
+} DrawParams;
-#endif
+typedef struct {
+ TkButton info; /* Generic button info */
+ int id;
+ int usingControl;
+ int useTkText;
+ int flags; /* Initialisation status */
+ ThemeButtonKind btnkind;
+ HIThemeButtonDrawInfo drawinfo;
+ HIThemeButtonDrawInfo lastdrawinfo;
+ DrawParams drawParams;
+ Tcl_TimerToken defaultPulseHandler;
+} MacButton;
+
+/*
+ * Forward declarations for procedures defined later in this file:
+ */
+
+
+static void ButtonBackgroundDrawCB (const HIRect *btnbounds, MacButton *ptr,
+ SInt16 depth, Boolean isColorDev);
+static void ButtonContentDrawCB (const HIRect *bounds, ThemeButtonKind kind,
+ const HIThemeButtonDrawInfo *info, MacButton *ptr, SInt16 depth,
+ Boolean isColorDev);
+static void ButtonEventProc(ClientData clientData, XEvent *eventPtr);
+static void TkMacOSXComputeButtonParams (TkButton * butPtr, ThemeButtonKind* btnkind,
+ HIThemeButtonDrawInfo* drawinfo);
+static int TkMacOSXComputeButtonDrawParams (TkButton * butPtr, DrawParams * dpPtr);
+static void TkMacOSXDrawButton (MacButton *butPtr, GC gc, Pixmap pixmap);
+static void DrawButtonImageAndText(TkButton* butPtr);
+static void PulseDefaultButtonProc(ClientData clientData);
-static void DisplayNativeButton(TkButton *butPtr);
-static void ComputeNativeButtonGeometry(TkButton *butPtr);
-static void DisplayUnixButton(TkButton *butPtr);
-static void ComputeUnixButtonGeometry(TkButton *butPtr);
/*
* The class procedure table for the button widgets.
@@ -79,67 +105,67 @@ static void ComputeUnixButtonGeometry(TkButton *butPtr);
const Tk_ClassProcs tkpButtonProcs = {
sizeof(Tk_ClassProcs), /* size */
TkButtonWorldChanged, /* worldChangedProc */
- NULL, /* createProc */
- NULL /* modalProc */
};
-
+static int bCount;
+
/*
*----------------------------------------------------------------------
*
- * TkpCreateButton --
+ * TkpButtonSetDefaults --
*
- * Allocate a new TkButton structure.
+ * This procedure is invoked before option tables are created for
+ * buttons. It modifies some of the default values to match the current
+ * values defined for this platform.
*
* Results:
- * Returns a newly allocated TkButton structure.
+ * Some of the default values in *specPtr are modified.
*
* Side effects:
- * Registers an event handler for the widget.
+ * Updates some of.
*
*----------------------------------------------------------------------
*/
-TkButton *
-TkpCreateButton(
- Tk_Window tkwin)
+void
+TkpButtonSetDefaults()
{
- MacButton *macButtonPtr = ckalloc(sizeof(MacButton));
-
- macButtonPtr->button = nil;
- macButtonPtr->image = nil;
- macButtonPtr->selectImage = nil;
- macButtonPtr->tristateImage = nil;
-
- return (TkButton *) macButtonPtr;
+/*No-op.*/
}
+
/*
*----------------------------------------------------------------------
*
- * TkpDestroyButton --
+ * TkpCreateButton --
*
- * Free data structures associated with the button control.
+ * Allocate a new TkButton structure.
*
* Results:
- * None.
+ * Returns a newly allocated TkButton structure.
*
* Side effects:
- * Restores the default control state.
+ * Registers an event handler for the widget.
*
*----------------------------------------------------------------------
*/
-void
-TkpDestroyButton(
- TkButton *butPtr)
+TkButton *
+TkpCreateButton(
+ Tk_Window tkwin)
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
-
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->button);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->selectImage);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->selectImage);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->tristateImage);
+ MacButton *macButtonPtr = (MacButton *) ckalloc(sizeof(MacButton));
+
+ Tk_CreateEventHandler(tkwin, ActivateMask,
+ ButtonEventProc, (ClientData) macButtonPtr);
+ macButtonPtr->id = bCount++;
+ macButtonPtr->flags = FIRST_DRAW;
+ macButtonPtr->btnkind = kThemePushButton;
+ macButtonPtr->defaultPulseHandler = NULL;
+ bzero(&macButtonPtr->drawinfo, sizeof(macButtonPtr->drawinfo));
+ bzero(&macButtonPtr->lastdrawinfo, sizeof(macButtonPtr->lastdrawinfo));
+
+ return (TkButton *)macButtonPtr;
}
/*
@@ -164,22 +190,61 @@ void
TkpDisplayButton(
ClientData clientData) /* Information about widget. */
{
+ MacButton *macButtonPtr = (MacButton *) clientData;
TkButton *butPtr = (TkButton *) clientData;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ DrawParams* dpPtr = &macButtonPtr->drawParams;
+ int needhighlight = 0;
butPtr->flags &= ~REDRAW_PENDING;
- if (!butPtr->tkwin || !Tk_IsMapped(butPtr->tkwin)) {
+ if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
return;
}
+ pixmap = (Pixmap) Tk_WindowId(tkwin);
+ TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin));
- switch (butPtr->type) {
- case TYPE_LABEL:
- DisplayUnixButton(butPtr);
- break;
- case TYPE_BUTTON:
- case TYPE_CHECK_BUTTON:
- case TYPE_RADIO_BUTTON:
- DisplayNativeButton(butPtr);
- break;
+ if (TkMacOSXComputeButtonDrawParams(butPtr, dpPtr) ) {
+ macButtonPtr->useTkText = 0;
+ } else {
+ macButtonPtr->useTkText = 1;
+ }
+
+
+ /*
+ * Set up clipping region. Make sure the we are using the port
+ * for this button, or we will set the wrong window's clip.
+ */
+
+ if (macButtonPtr->useTkText) {
+ if (butPtr->type == TYPE_BUTTON) {
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+ } else {
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+ }
+
+ /* Display image or bitmap or text for labels or custom controls. */
+ DrawButtonImageAndText(butPtr);
+ needhighlight = 1;
+ } else {
+ /* Draw the native portion of the buttons. */
+ TkMacOSXDrawButton(macButtonPtr, dpPtr->gc, pixmap);
+
+ /* Draw highlight border, if needed. */
+ if (butPtr->highlightWidth < 3) {
+ needhighlight = 1;
+ }
+ }
+
+ /* Draw highlight border, if needed. */
+ if (needhighlight) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ Tk_Draw3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin),
+ butPtr->highlightWidth, TK_RELIEF_SOLID);
+ }
}
}
@@ -203,977 +268,946 @@ TkpDisplayButton(
void
TkpComputeButtonGeometry(
- register TkButton *butPtr) /* Button whose geometry may have changed. */
+ TkButton *butPtr) /* Button whose geometry may have changed. */
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
+ int width = 0, height = 0, charWidth = 1, haveImage = 0, haveText = 0;
+ int txtWidth = 0, txtHeight = 0;
+ MacButton *mbPtr = (MacButton*)butPtr;
+ Tk_FontMetrics fm;
+ DrawParams drawParams;
- switch (butPtr->type) {
- case TYPE_LABEL:
- if (macButtonPtr->button && [macButtonPtr->button superview]) {
- [macButtonPtr->button removeFromSuperviewWithoutNeedingDisplay];
- }
- ComputeUnixButtonGeometry(butPtr);
- break;
- case TYPE_BUTTON:
- case TYPE_CHECK_BUTTON:
- case TYPE_RADIO_BUTTON:
- if (!macButtonPtr->button) {
- NSButton *button = [[NSButton alloc] initWithFrame:NSZeroRect];
- macButtonPtr->button = TkMacOSXMakeUncollectable(button);
- }
- ComputeNativeButtonGeometry(butPtr);
+ /*
+ * First figure out the size of the contents of the button.
+ */
+
+ TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
+
+ /*
+ * If the indicator is on, get its size.
+ */
+
+ if ( butPtr->indicatorOn ) {
+ switch (butPtr->type) {
+ case TYPE_RADIO_BUTTON:
+ GetThemeMetric(kThemeMetricRadioButtonWidth, &butPtr->indicatorDiameter);
+ break;
+ case TYPE_CHECK_BUTTON:
+ GetThemeMetric(kThemeMetricCheckBoxWidth, &butPtr->indicatorDiameter);
+ break;
+ default:
break;
+ }
+ /* Allow 2px extra space next to the indicator. */
+ butPtr->indicatorSpace = butPtr->indicatorDiameter + 2;
+ } else {
+ butPtr->indicatorSpace = 0;
+ butPtr->indicatorDiameter = 0;
}
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkpButtonSetDefaults --
- *
- * This procedure is invoked before option tables are created for
- * buttons. It modifies some of the default values to match the current
- * values defined for this platform.
- *
- * Results:
- * Some of the default values in *specPtr are modified.
- *
- * Side effects:
- * Updates some of.
- *
- *----------------------------------------------------------------------
- */
-void
-TkpButtonSetDefaults()
-{
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (!tkMacOSXUseCompatibilityMetrics) {
- strcpy(tkDefButtonHighlightWidth, DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM);
- strcpy(tkDefLabelHighlightWidth, DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM);
- strcpy(tkDefButtonPadx, DEF_BUTTON_PADX_NOCM);
- strcpy(tkDefLabelPadx, DEF_BUTTON_PADX_NOCM);
- strcpy(tkDefButtonPady, DEF_BUTTON_PADY_NOCM);
- strcpy(tkDefLabelPady, DEF_BUTTON_PADY_NOCM);
+ if (butPtr->image != NULL) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
}
-#endif
-}
-#pragma mark -
-#pragma mark Native Buttons:
+ if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
+ Tk_FreeTextLayout(butPtr->textLayout);
+ butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
+ Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength,
+ butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
-
-/*
- *----------------------------------------------------------------------
- *
- * DisplayNativeButton --
- *
- * This procedure is invoked to display a button widget. It is
- * normally invoked as an idle handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Commands are output to X to display the button in its
- * current mode. The REDRAW_PENDING flag is cleared.
- *
- *----------------------------------------------------------------------
- */
+ txtWidth = butPtr->textWidth + DEF_INSET_LEFT + DEF_INSET_RIGHT;
+ txtHeight = butPtr->textHeight + DEF_INSET_BOTTOM + DEF_INSET_TOP;
+ charWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
+ Tk_GetFontMetrics(butPtr->tkfont, &fm);
+ haveText = (txtWidth != 0 && txtHeight != 0);
+ }
-static void
-DisplayNativeButton(
- TkButton *butPtr)
-{
- MacButton *macButtonPtr = (MacButton *) butPtr;
- NSButton *button = macButtonPtr->button;
- Tk_Window tkwin = butPtr->tkwin;
- TkWindow *winPtr = (TkWindow *) tkwin;
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
- TkMacOSXDrawingContext dc;
- NSView *view = TkMacOSXDrawableView(macWin);
- CGFloat viewHeight = [view bounds].size.height;
- CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
- .ty = viewHeight};
- NSRect frame;
- int enabled;
- NSCellStateValue state;
-
- if (!view ||
- !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
- return;
+ if (haveImage && haveText) { /* Image and Text */
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM:
+ /*
+ * Image is above or below text.
+ */
+
+ height += txtHeight + butPtr->padY;
+ width = (width > txtWidth ? width : txtWidth);
+ break;
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT:
+ /*
+ * Image is left or right of text.
+ */
+
+ width += txtWidth + butPtr->padX;
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ case COMPOUND_CENTER:
+ /*
+ * Image and text are superimposed.
+ */
+
+ width = (width > txtWidth ? width : txtWidth);
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ default:
+ break;
+ }
+ width += butPtr->indicatorSpace;
+
+ } else if (haveImage) { /* Image only */
+ width = butPtr->width > 0 ? butPtr->width : width + butPtr->indicatorSpace;
+ height = butPtr->height > 0 ? butPtr->height : height;
+
+ } else { /* Text only */
+ width = txtWidth + butPtr->indicatorSpace;
+ height = txtHeight;
+ if (butPtr->width > 0) {
+ width = butPtr->width * charWidth;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height * fm.linespace;
+ }
}
- CGContextConcatCTM(dc.context, t);
+
+ /* Add padding */
+ width += 2 * butPtr->padX;
+ height += 2 * butPtr->padY;
/*
- * We cannot change the background color of the button itself, only the
- * color of the background of its container.
- * This will be the color that peeks around the rounded corners of the
- * button. We make this the highlightbackground rather than the background,
- * because if you color the background of a frame containing a
- * button, you usually also color the highlightbackground as well,
- * or you will get a thin grey ring around the button.
+ * Now figure out the size of the border decorations for the button.
*/
- Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, butPtr->type == TYPE_BUTTON ?
- butPtr->highlightBorder : butPtr->normalBorder, 0, 0,
- Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
- if ([button superview] != view) {
- [view addSubview:button];
- }
- if (macButtonPtr->tristateImage) {
- NSImage *selectImage = macButtonPtr->selectImage ?
- macButtonPtr->selectImage : macButtonPtr->image;
- [button setImage:(butPtr->flags & TRISTATED ?
- selectImage : macButtonPtr->image)];
- [button setAlternateImage:(butPtr->flags & TRISTATED ?
- macButtonPtr->tristateImage : selectImage)];
- }
- if (butPtr->flags & SELECTED) {
- state = NSOnState;
- } else if (butPtr->flags & TRISTATED) {
- state = NSMixedState;
- } else {
- state = NSOffState;
- }
- [button setState:state];
- enabled = !(butPtr->state == STATE_DISABLED);
- [button setEnabled:enabled];
- if (enabled) {
- //[button highlight:(butPtr->state == STATE_ACTIVE)];
- //[cell setHighlighted:(butPtr->state == STATE_ACTIVE)];
+ if (butPtr->highlightWidth < 0) {
+ butPtr->highlightWidth = 0;
}
- if (butPtr->type == TYPE_BUTTON && butPtr->defaultState == STATE_ACTIVE) {
- //[[view window] setDefaultButtonCell:cell];
- [button setKeyEquivalent:@"\r"];
+
+ butPtr->inset = 0;
+ butPtr->inset += butPtr->highlightWidth;
+
+ if (TkMacOSXComputeButtonDrawParams(butPtr,&drawParams)) {
+ HIRect tmpRect;
+ HIRect contBounds;
+ int paddingx = 0;
+ int paddingy = 0;
+
+ tmpRect = CGRectMake(0, 0, width, height);
+
+ HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds);
+ /* If the content region has a minimum height, match it. */
+ if (height < contBounds.size.height) {
+ height = contBounds.size.height;
+ }
+
+ /* If the content region has a minimum width, match it. */
+ if (width < contBounds.size.width) {
+ width = contBounds.size.width;
+ }
+
+ /* Pad to fill difference between content bounds and button bounds. */
+ paddingx = contBounds.origin.x;
+ paddingy = contBounds.origin.y;
+
+ if (height < paddingx - 4) {
+ /* can't have buttons much shorter than button side diameter. */
+ height = paddingx - 4;
+ }
+
} else {
- [button setKeyEquivalent:@""];
- }
- frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin),
- Tk_Height(tkwin));
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- BoundsFix boundsFix = boundsFixes[macButtonPtr->fix];
- frame = NSOffsetRect(frame, boundsFix.offsetX, boundsFix.offsetY);
- frame.size.height -= boundsFix.shrinkH + NATIVE_BUTTON_EXTRA_H;
- frame = NSInsetRect(frame, boundsFix.inset + NATIVE_BUTTON_INSET,
- boundsFix.inset + NATIVE_BUTTON_INSET);
+ height += butPtr->borderWidth*2;
+ width += butPtr->borderWidth*2;
}
-#endif
- frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
- if (!NSEqualRects(frame, [button frame])) {
- [button setFrame:frame];
- }
- [button displayRectIgnoringOpacity:[button bounds]];
- TkMacOSXRestoreDrawingContext(&dc);
-#ifdef TK_MAC_DEBUG_BUTTON
- TKLog(@"button %s frame %@ width %d height %d",
- ((TkWindow *)butPtr->tkwin)->pathName, NSStringFromRect(frame),
- Tk_Width(tkwin), Tk_Height(tkwin));
-#endif
+
+ width += butPtr->inset*2;
+ height += butPtr->inset*2;
+
+ Tk_GeometryRequest(butPtr->tkwin, width, height);
+ Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
}
-
+
/*
*----------------------------------------------------------------------
*
- * ComputeNativeButtonGeometry --
+ * DrawButtonImageAndText --
*
- * After changes in a button's text or bitmap, this procedure
- * recomputes the button's geometry and passes this information
- * along to the geometry manager for the window.
+ * Draws the image and text associated with a button or label.
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * The button's window may change size.
+ * The image and text are drawn.
*
*----------------------------------------------------------------------
*/
-
static void
-ComputeNativeButtonGeometry(
- TkButton *butPtr) /* Button whose geometry may have changed. */
+DrawButtonImageAndText(
+ TkButton* butPtr)
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
- NSButton *button = macButtonPtr->button;
- NSButtonCell *cell = [button cell];
- NSButtonType type = -1;
- NSBezelStyle style = 0;
- NSInteger highlightsBy = 0, showsStateBy = 0;
- NSFont *font;
- NSRect bounds = NSZeroRect, titleRect = NSZeroRect;
- int haveImage = (butPtr->image || butPtr->bitmap != None), haveText = 0;
- int haveCompound = (butPtr->compound != COMPOUND_NONE);
- int width, height, border = 0;
-
- butPtr->indicatorSpace = 0;
- butPtr->inset = 0;
- if (butPtr->highlightWidth < 0) {
- butPtr->highlightWidth = 0;
- }
- switch (butPtr->type) {
- case TYPE_BUTTON:
- type = NSMomentaryPushInButton;
- if (!haveImage) {
- style = NSRoundedBezelStyle;
- butPtr->inset = butPtr->defaultState != STATE_DISABLED ?
- butPtr->highlightWidth : 0;
- [button setImage:nil];
- [button setImagePosition:NSNoImage];
- } else {
- style = NSShadowlessSquareBezelStyle;
- highlightsBy = butPtr->selectImage || butPtr->bitmap ?
- NSContentsCellMask : 0;
- border = butPtr->borderWidth;
- }
- break;
- case TYPE_RADIO_BUTTON:
- case TYPE_CHECK_BUTTON:
- if (!haveImage /*|| butPtr->indicatorOn*/) { // TODO: indicatorOn
- type = butPtr->type == TYPE_RADIO_BUTTON ?
- NSRadioButton : NSSwitchButton;
- butPtr->inset = /*butPtr->indicatorOn ? 0 :*/ butPtr->borderWidth;
- } else {
- type = NSPushOnPushOffButton;
- style = NSShadowlessSquareBezelStyle;
- highlightsBy = butPtr->selectImage || butPtr->bitmap ?
- NSContentsCellMask : 0;
- showsStateBy = butPtr->selectImage || butPtr->tristateImage ?
- NSContentsCellMask : 0;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- border = butPtr->borderWidth > 1 ? butPtr->borderWidth - 1 : 1;
- } else
-#endif
- {
- border = butPtr->borderWidth;
- }
- }
- break;
- }
- [button setButtonType:type];
- if (style) {
- [button setBezelStyle:style];
- }
- if (highlightsBy) {
- [cell setHighlightsBy:highlightsBy|[cell highlightsBy]];
- }
- if (showsStateBy) {
- [cell setShowsStateBy:showsStateBy|[cell showsStateBy]];
+
+ MacButton *mbPtr = (MacButton*)butPtr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ int haveImage = 0;
+ int haveText = 0;
+ int imageWidth = 0;
+ int imageHeight = 0;
+ int imageXOffset = 0;
+ int imageYOffset = 0;
+ int textXOffset = 0;
+ int textYOffset = 0;
+ int width = 0;
+ int height = 0;
+ int fullWidth = 0;
+ int fullHeight = 0;
+ int pressed = 0;
+
+
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
-#if 0
- if (style == NSShadowlessSquareBezelStyle) {
- NSControlSize controlSize = NSRegularControlSize;
-
- if (butPtr->borderWidth <= 2) {
- controlSize = NSMiniControlSize;
- } else if (butPtr->borderWidth == 3) {
- controlSize = NSSmallControlSize;
- }
- [cell setControlSize:controlSize];
+
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+ if (butPtr->image != None) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
}
-#endif
- [button setAllowsMixedState:YES];
-
- if (!haveImage || haveCompound) {
- int len;
- char *text = Tcl_GetStringFromObj(butPtr->textPtr, &len);
-
- if (len) {
- NSString *title = [[NSString alloc] initWithBytes:text length:len
- encoding:NSUTF8StringEncoding];
- [button setTitle:title];
- [title release];
- haveText = 1;
- }
+
+ imageWidth = width;
+ imageHeight = height;
+
+ if (mbPtr->drawinfo.state == kThemeStatePressed) {
+ /* Offset bitmaps by a bit when the button is pressed. */
+ pressed = 1;
}
- haveCompound = (haveCompound && haveImage && haveText);
- if (haveText) {
- NSTextAlignment alignment = NSNaturalTextAlignment;
-
- switch (butPtr->justify) {
- case TK_JUSTIFY_LEFT:
- alignment = NSLeftTextAlignment;
- break;
- case TK_JUSTIFY_RIGHT:
- alignment = NSRightTextAlignment;
- break;
- case TK_JUSTIFY_CENTER:
- alignment = NSCenterTextAlignment;
- break;
+
+ haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
+ if (haveImage && haveText) { /* Image and Text */
+ int x;
+ int y;
+ textXOffset = 0;
+ textYOffset = 0;
+ fullWidth = 0;
+ fullHeight = 0;
+
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM: {
+ /* Image is above or below text */
+ if (butPtr->compound == COMPOUND_TOP) {
+ textYOffset = height + butPtr->padY;
+ } else {
+ imageYOffset = butPtr->textHeight + butPtr->padY;
+ }
+ fullHeight = height + butPtr->textHeight + butPtr->padY;
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ break;
}
- [button setAlignment:alignment];
- } else {
- [button setTitle:@""];
- }
- font = TkMacOSXNSFontForFont(butPtr->tkfont);
- if (font) {
- [button setFont:font];
- }
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->image);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->selectImage);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->tristateImage);
- if (haveImage) {
- int width, height;
- NSImage *image, *selectImage = nil, *tristateImage = nil;
- NSCellImagePosition pos = NSImageOnly;
-
- if (butPtr->image) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- image = TkMacOSXGetNSImageWithTkImage(butPtr->display,
- butPtr->image, width, height);
- if (butPtr->selectImage) {
- selectImage = TkMacOSXGetNSImageWithTkImage(butPtr->display,
- butPtr->selectImage, width, height);
- }
- if (butPtr->tristateImage) {
- tristateImage = TkMacOSXGetNSImageWithTkImage(butPtr->display,
- butPtr->tristateImage, width, height);
- }
- } else {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- image = TkMacOSXGetNSImageWithBitmap(butPtr->display,
- butPtr->bitmap, butPtr->normalTextGC, width, height);
- selectImage = TkMacOSXGetNSImageWithBitmap(butPtr->display,
- butPtr->bitmap, butPtr->activeTextGC, width, height);
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT: {
+ /*
+ * Image is left or right of text
+ */
+
+ if (butPtr->compound == COMPOUND_LEFT) {
+ textXOffset = width + butPtr->padX;
+ } else {
+ imageXOffset = butPtr->textWidth + butPtr->padX;
+ }
+ fullWidth = butPtr->textWidth + butPtr->padX + width;
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
}
- [button setImage:image];
- if (selectImage) {
- [button setAlternateImage:selectImage];
+ case COMPOUND_CENTER: {
+ /*
+ * Image and text are superimposed
+ */
+
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
}
- if (tristateImage) {
- macButtonPtr->image = TkMacOSXMakeUncollectableAndRetain(image);
- if (selectImage) {
- macButtonPtr->selectImage =
- TkMacOSXMakeUncollectableAndRetain(selectImage);
- }
- macButtonPtr->tristateImage =
- TkMacOSXMakeUncollectableAndRetain(tristateImage);
+ default:
+ break;
}
- if (haveCompound) {
- switch ((enum compound) butPtr->compound) {
- case COMPOUND_TOP:
- pos = NSImageAbove;
- break;
- case COMPOUND_BOTTOM:
- pos = NSImageBelow;
- break;
- case COMPOUND_LEFT:
- pos = NSImageLeft;
- break;
- case COMPOUND_RIGHT:
- pos = NSImageRight;
- break;
- case COMPOUND_CENTER:
- pos = NSImageOverlaps;
- break;
- case COMPOUND_NONE:
- pos = NSImageOnly;
- break;
- }
+
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ fullWidth + butPtr->indicatorSpace, fullHeight, &x, &y);
+ x += butPtr->indicatorSpace;
+
+ if (dpPtr->relief == TK_RELIEF_SUNKEN) {
+ x += dpPtr->offset;
+ y += dpPtr->offset;
+ } else if (dpPtr->relief == TK_RELIEF_RAISED) {
+ x -= dpPtr->offset;
+ y -= dpPtr->offset;
+ }
+ if (pressed) {
+ x += dpPtr->offset;
+ y += dpPtr->offset;
+ }
+ imageXOffset += x;
+ imageYOffset += y;
+ textYOffset -= 1;
+
+ if (butPtr->image != NULL) {
+ if ((butPtr->selectImage != NULL) &&
+ (butPtr->flags & SELECTED)) {
+ Tk_RedrawImage(butPtr->selectImage, 0, 0,
+ width, height, pixmap, imageXOffset, imageYOffset);
+ } else if ((butPtr->tristateImage != NULL) &&
+ (butPtr->flags & TRISTATED)) {
+ Tk_RedrawImage(butPtr->tristateImage, 0, 0,
+ width, height, pixmap, imageXOffset, imageYOffset);
+ } else {
+ Tk_RedrawImage(butPtr->image, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ }
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc,
+ imageXOffset, imageYOffset);
+ XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width, (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+
+ Tk_DrawTextLayout(butPtr->display, pixmap,
+ dpPtr->gc, butPtr->textLayout,
+ x + textXOffset, y + textYOffset, 0, -1);
+ Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout,
+ x + textXOffset, y + textYOffset,
+ butPtr->underline);
+ } else if (haveImage) { /* Image only */
+ int x = 0;
+ int y;
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ width + butPtr->indicatorSpace,
+ height, &x, &y);
+ x += butPtr->indicatorSpace;
+ if (pressed) {
+ x += dpPtr->offset;
+ y += dpPtr->offset;
}
- [button setImagePosition:pos];
- }
+ imageXOffset += x;
+ imageYOffset += y;
- // if font is too tall, we can't use the fixed-height rounded bezel
- if (!haveImage && haveText && style == NSRoundedBezelStyle) {
- Tk_FontMetrics fm;
- Tk_GetFontMetrics(butPtr->tkfont, &fm);
- if (fm.linespace > 18) {
- [button setBezelStyle:(style = NSShadowlessSquareBezelStyle)];
- }
- }
+ if (butPtr->image != NULL) {
- bounds.size = [cell cellSize];
- if (haveText) {
- titleRect = [cell titleRectForBounds:bounds];
- if (butPtr->wrapLength > 0 &&
- titleRect.size.width > butPtr->wrapLength) {
- if (style == NSRoundedBezelStyle) {
- [button setBezelStyle:(style = NSRegularSquareBezelStyle)];
- bounds.size = [cell cellSize];
- titleRect = [cell titleRectForBounds:bounds];
- }
- bounds.size.width -= titleRect.size.width - butPtr->wrapLength;
- bounds.size.height = 40000.0;
- [cell setWraps:YES];
- bounds.size = [cell cellSizeForBounds:bounds];
-#ifdef TK_MAC_DEBUG_BUTTON
- titleRect = [cell titleRectForBounds:bounds];
-#endif
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- bounds.size.height += 3;
- }
-#endif
+ if ((butPtr->selectImage != NULL) &&
+ (butPtr->flags & SELECTED)) {
+ Tk_RedrawImage(butPtr->selectImage, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ } else if ((butPtr->tristateImage != NULL) &&
+ (butPtr->flags & TRISTATED)) {
+ Tk_RedrawImage(butPtr->tristateImage, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ } else {
+ Tk_RedrawImage(butPtr->image, 0, 0, width, height,
+ pixmap, imageXOffset, imageYOffset);
+ }
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc, x, y);
+ XCopyPlane(butPtr->display, butPtr->bitmap,
+ pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width,
+ (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
}
+ } else { /* Text only */
+ int x, y;
+ TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
+ butPtr->textWidth + butPtr->indicatorSpace,
+ butPtr->textHeight, &x, &y);
+ x += butPtr->indicatorSpace;
+ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout,
+ x, y - DEF_INSET_BOTTOM, 0, -1);
}
- width = lround(bounds.size.width);
- height = lround(bounds.size.height);
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- macButtonPtr->fix = fixForTypeStyle(type, style);
- width -= boundsFixes[macButtonPtr->fix].trimW;
- height -= boundsFixes[macButtonPtr->fix].trimH;
- }
-#endif
- if (haveImage || haveCompound) {
- if (butPtr->width > 0) {
- width = butPtr->width;
- }
- if (butPtr->height > 0) {
- height = butPtr->height;
- }
- } else {
- if (butPtr->width > 0) {
- int avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
- width = butPtr->width * avgWidth;
- }
- if (butPtr->height > 0) {
- Tk_FontMetrics fm;
+ /*
+ * If the button is disabled with a stipple rather than a special
+ * foreground color, generate the stippled effect. If the widget
+ * is selected and we use a different background color when selected,
+ * must temporarily modify the GC so the stippling is the right color.
+ */
- Tk_GetFontMetrics(butPtr->tkfont, &fm);
- height = butPtr->height * fm.linespace;
- }
- }
- if (!haveImage || haveCompound) {
- width += 2*butPtr->padX;
- height += 2*butPtr->padY;
- }
- if (haveImage) {
- width += 2*border;
- height += 2*border;
+ if (mbPtr->useTkText) {
+ if ((butPtr->state == STATE_DISABLED)
+ && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) {
+ if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
+ && (butPtr->selectBorder != NULL)) {
+ XSetForeground(butPtr->display, butPtr->stippleGC,
+ Tk_3DBorderColor(butPtr->selectBorder)->pixel);
+ }
+ /*
+ * Stipple the whole button if no disabledFg was specified,
+ * otherwise restrict stippling only to displayed image
+ */
+ if (butPtr->disabledFg == NULL) {
+ XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
+ 0, 0, (unsigned) Tk_Width(tkwin),
+ (unsigned) Tk_Height(tkwin));
+ } else {
+ XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
+ imageXOffset, imageYOffset,
+ (unsigned) imageWidth, (unsigned) imageHeight);
+ }
+ if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
+ && (butPtr->selectBorder != NULL)
+ ) {
+ XSetForeground(butPtr->display, butPtr->stippleGC,
+ Tk_3DBorderColor(butPtr->normalBorder)->pixel);
+ }
+ }
+
+ /*
+ * Draw the border and traversal highlight last. This way, if the
+ * button's contents overflow they'll be covered up by the border.
+ */
+
+ if (dpPtr->relief != TK_RELIEF_FLAT) {
+ int inset = butPtr->highlightWidth;
+ Tk_Draw3DRectangle(tkwin, pixmap, dpPtr->border, inset, inset,
+ Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset,
+ butPtr->borderWidth, dpPtr->relief);
+ }
}
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- width += 2*NATIVE_BUTTON_INSET;
- height += 2*NATIVE_BUTTON_INSET + NATIVE_BUTTON_EXTRA_H;
- }
-#endif
- Tk_GeometryRequest(butPtr->tkwin, width, height);
- Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
-#ifdef TK_MAC_DEBUG_BUTTON
- TKLog(@"button %s bounds %@ titleRect %@ width %d height %d inset %d borderWidth %d",
- ((TkWindow *)butPtr->tkwin)->pathName, NSStringFromRect(bounds),
- NSStringFromRect(titleRect), width, height, butPtr->inset,
- butPtr->borderWidth);
-#endif
-}
-#pragma mark -
-#pragma mark Unix Buttons:
+ }
+
+
+
-
/*
*----------------------------------------------------------------------
*
- * DisplayUnixButton --
+ * TkpDestroyButton --
*
- * This procedure is invoked to display a button widget. It is
- * normally invoked as an idle handler.
+ * Free data structures associated with the button control.
*
* Results:
* None.
*
* Side effects:
- * Commands are output to X to display the button in its
- * current mode. The REDRAW_PENDING flag is cleared.
+ * Restores the default control state.
*
*----------------------------------------------------------------------
*/
void
-DisplayUnixButton(
+TkpDestroyButton(
TkButton *butPtr)
{
- GC gc;
- Tk_3DBorder border;
- Pixmap pixmap;
- int x = 0; /* Initialization only needed to stop compiler
- * warning. */
- int y, relief;
- Tk_Window tkwin = butPtr->tkwin;
- int width = 0, height = 0, fullWidth, fullHeight;
- int textXOffset, textYOffset;
- int haveImage = 0, haveText = 0;
- int imageWidth, imageHeight;
- int imageXOffset = 0, imageYOffset = 0;
- /* image information that will be used to
- * restrict disabled pixmap as well */
-
- border = butPtr->normalBorder;
- if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
- gc = butPtr->disabledGC;
- } else if ((butPtr->state == STATE_ACTIVE)
- && !Tk_StrictMotif(butPtr->tkwin)) {
- gc = butPtr->activeTextGC;
- border = butPtr->activeBorder;
- } else {
- gc = butPtr->normalTextGC;
- }
- if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE)
- && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) {
- border = butPtr->selectBorder;
+ MacButton *mbPtr = (MacButton *) butPtr; /* Mac button. */
+ if (mbPtr->defaultPulseHandler) {
+ Tcl_DeleteTimerHandler(mbPtr->defaultPulseHandler);
}
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TkMacOSXDrawButton --
+ *
+ * This function draws the tk button using Mac controls
+ * In addition, this code may apply custom colors passed
+ * in the TkButton.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The control is created, or reinitialised as needed
+ *
+ *--------------------------------------------------------------
+ */
- relief = butPtr->relief;
-
- pixmap = (Pixmap) Tk_WindowId(tkwin);
- Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
- Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
-
- /*
- * Display image or bitmap or text for button.
- */
+static void
+TkMacOSXDrawButton(
+ MacButton *mbPtr, /* Mac button. */
+ GC gc, /* The GC we are drawing into - needed for
+ * the bevel button */
+ Pixmap pixmap) /* The pixmap we are drawing into - needed
+ * for the bevel button */
+{
+ TkButton * butPtr = ( TkButton *)mbPtr;
+ TkWindow * winPtr;
+ HIRect cntrRect;
+ TkMacOSXDrawingContext dc;
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ int useNewerHITools = 1;
- if (butPtr->image != NULL) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- haveImage = 1;
- } else if (butPtr->bitmap != None) {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- haveImage = 1;
- }
- imageWidth = width;
- imageHeight = height;
+ winPtr = (TkWindow *)butPtr->tkwin;
- haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
+ TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
- if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
- textXOffset = 0;
- textYOffset = 0;
- fullWidth = 0;
- fullHeight = 0;
+ cntrRect = CGRectMake(winPtr->privatePtr->xOff,
+ winPtr->privatePtr->yOff,
+ Tk_Width(butPtr->tkwin),
+ Tk_Height(butPtr->tkwin));
- switch ((enum compound) butPtr->compound) {
- case COMPOUND_TOP:
- case COMPOUND_BOTTOM:
- /*
- * Image is above or below text.
- */
+ cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset);
- if (butPtr->compound == COMPOUND_TOP) {
- textYOffset = height + butPtr->padY;
- } else {
- imageYOffset = butPtr->textHeight + butPtr->padY;
- }
- fullHeight = height + butPtr->textHeight + butPtr->padY;
- fullWidth = (width > butPtr->textWidth ? width :
- butPtr->textWidth);
- textXOffset = (fullWidth - butPtr->textWidth)/2;
- imageXOffset = (fullWidth - width)/2;
- break;
- case COMPOUND_LEFT:
- case COMPOUND_RIGHT:
- /*
- * Image is left or right of text.
- */
+ if (useNewerHITools == 1) {
+ HIRect contHIRec;
+ static HIThemeButtonDrawInfo hiinfo;
- if (butPtr->compound == COMPOUND_LEFT) {
- textXOffset = width + butPtr->padX;
- } else {
- imageXOffset = butPtr->textWidth + butPtr->padX;
- }
- fullWidth = butPtr->textWidth + butPtr->padX + width;
- fullHeight = (height > butPtr->textHeight ? height :
- butPtr->textHeight);
- textYOffset = (fullHeight - butPtr->textHeight)/2;
- imageYOffset = (fullHeight - height)/2;
- break;
- case COMPOUND_CENTER:
- /*
- * Image and text are superimposed.
- */
+ ButtonBackgroundDrawCB(&cntrRect, mbPtr, 32, true);
- fullWidth = (width > butPtr->textWidth ? width :
- butPtr->textWidth);
- fullHeight = (height > butPtr->textHeight ? height :
- butPtr->textHeight);
- textXOffset = (fullWidth - butPtr->textWidth)/2;
- imageXOffset = (fullWidth - width)/2;
- textYOffset = (fullHeight - butPtr->textHeight)/2;
- imageYOffset = (fullHeight - height)/2;
- break;
- case COMPOUND_NONE:
- break;
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
}
- TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
- fullWidth, fullHeight, &x, &y);
-
- imageXOffset += x;
- imageYOffset += y;
- if (butPtr->image != NULL) {
+ if (mbPtr->btnkind == kThemePushButton) {
/*
- * Do boundary clipping, so that Tk_RedrawImage is passed valid
- * coordinates. [Bug 979239]
+ * For some reason, pushbuttons get drawn a bit
+ * too low, normally. Correct for this.
*/
-
- if (imageXOffset < 0) {
- imageXOffset = 0;
- }
- if (imageYOffset < 0) {
- imageYOffset = 0;
- }
- if (width > Tk_Width(tkwin)) {
- width = Tk_Width(tkwin);
- }
- if (height > Tk_Height(tkwin)) {
- height = Tk_Height(tkwin);
- }
- if ((width + imageXOffset) > Tk_Width(tkwin)) {
- imageXOffset = Tk_Width(tkwin) - width;
+ if (cntrRect.size.height < 22) {
+ cntrRect.origin.y -= 1;
+ } else if (cntrRect.size.height < 23) {
+ cntrRect.origin.y -= 2;
}
- if ((height + imageYOffset) > Tk_Height(tkwin)) {
- imageYOffset = Tk_Height(tkwin) - height;
- }
-
- if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) {
- Tk_RedrawImage(butPtr->selectImage, 0, 0,
- width, height, pixmap, imageXOffset, imageYOffset);
- } else if ((butPtr->tristateImage != NULL) && (butPtr->flags & TRISTATED)) {
- Tk_RedrawImage(butPtr->tristateImage, 0, 0,
- width, height, pixmap, imageXOffset, imageYOffset);
- } else {
- Tk_RedrawImage(butPtr->image, 0, 0, width,
- height, pixmap, imageXOffset, imageYOffset);
- }
- } else {
- XSetClipOrigin(butPtr->display, gc, imageXOffset, imageYOffset);
- XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc,
- 0, 0, (unsigned int) width, (unsigned int) height,
- imageXOffset, imageYOffset, 1);
- XSetClipOrigin(butPtr->display, gc, 0, 0);
}
- Tk_DrawTextLayout(butPtr->display, pixmap, gc,
- butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1);
- Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
- butPtr->textLayout, x + textXOffset, y + textYOffset,
- butPtr->underline);
- y += fullHeight/2;
- } else {
- if (haveImage) {
- TkComputeAnchor(butPtr->anchor, tkwin, 0, 0,
- width, height, &x, &y);
- imageXOffset += x;
- imageYOffset += y;
- if (butPtr->image != NULL) {
- /*
- * Do boundary clipping, so that Tk_RedrawImage is passed
- * valid coordinates. [Bug 979239]
- */
+ hiinfo.version = 0;
+ hiinfo.state = mbPtr->drawinfo.state;
+ hiinfo.kind = mbPtr->btnkind;
+ hiinfo.value = mbPtr->drawinfo.value;
+ hiinfo.adornment = mbPtr->drawinfo.adornment;
+ hiinfo.animation.time.current = CFAbsoluteTimeGetCurrent();
+ if (hiinfo.animation.time.start == 0) {
+ hiinfo.animation.time.start = hiinfo.animation.time.current;
+ }
- if (imageXOffset < 0) {
- imageXOffset = 0;
- }
- if (imageYOffset < 0) {
- imageYOffset = 0;
- }
- if (width > Tk_Width(tkwin)) {
- width = Tk_Width(tkwin);
- }
- if (height > Tk_Height(tkwin)) {
- height = Tk_Height(tkwin);
- }
- if ((width + imageXOffset) > Tk_Width(tkwin)) {
- imageXOffset = Tk_Width(tkwin) - width;
- }
- if ((height + imageYOffset) > Tk_Height(tkwin)) {
- imageYOffset = Tk_Height(tkwin) - height;
- }
+ HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal,
+ &contHIRec);
- if ((butPtr->selectImage != NULL) &&
- (butPtr->flags & SELECTED)) {
- Tk_RedrawImage(butPtr->selectImage, 0, 0, width,
- height, pixmap, imageXOffset, imageYOffset);
- } else if ((butPtr->tristateImage != NULL) &&
- (butPtr->flags & TRISTATED)) {
- Tk_RedrawImage(butPtr->tristateImage, 0, 0, width,
- height, pixmap, imageXOffset, imageYOffset);
- } else {
- Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap,
- imageXOffset, imageYOffset);
- }
- } else {
- XSetClipOrigin(butPtr->display, gc, x, y);
- XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0,
- (unsigned int) width, (unsigned int) height, x, y, 1);
- XSetClipOrigin(butPtr->display, gc, 0, 0);
- }
- y += height/2;
- } else {
- TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
- butPtr->textWidth, butPtr->textHeight, &x, &y);
-
- Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout,
- x, y, 0, -1);
- Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
- butPtr->textLayout, x, y, butPtr->underline);
- y += butPtr->textHeight/2;
+ TkMacOSXRestoreDrawingContext(&dc);
+ ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo,
+ (MacButton *)mbPtr, 32, true);
+
+ } else {
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
}
+
+ TkMacOSXRestoreDrawingContext(&dc);
}
+ mbPtr->lastdrawinfo = mbPtr->drawinfo;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ButtonBackgroundDrawCB --
+ *
+ * This function draws the background that
+ * lies under checkboxes and radiobuttons.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The background gets updated to the current color.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+ButtonBackgroundDrawCB (
+ const HIRect * btnbounds,
+ MacButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
+{
+ MacButton* mbPtr = (MacButton*)ptr;
+ TkButton* butPtr = (TkButton*)mbPtr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ int usehlborder = 0;
- /*
- * If the button is disabled with a stipple rather than a special
- * foreground color, generate the stippled effect. If the widget is
- * selected and we use a different background color when selected, must
- * temporarily modify the GC so the stippling is the right color.
- */
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
+ }
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+ if (butPtr->type != TYPE_LABEL) {
+ switch (mbPtr->btnkind) {
+ case kThemeSmallBevelButton:
+ case kThemeBevelButton:
+ case kThemeRoundedBevelButton:
+ case kThemePushButton:
+ usehlborder = 1;
+ break;
+ }
+ }
+ if (usehlborder) {
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+ } else {
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ButtonContentDrawCB --
+ *
+ * This function draws the label and image for the button.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The content of the button gets updated.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+ButtonContentDrawCB (
+ const HIRect * btnbounds,
+ ThemeButtonKind kind,
+ const HIThemeButtonDrawInfo *drawinfo,
+ MacButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
+{
+ TkButton *butPtr = (TkButton *)ptr;
+ Tk_Window tkwin = butPtr->tkwin;
- if ((butPtr->state == STATE_DISABLED)
- && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) {
- if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
- && (butPtr->selectBorder != NULL)) {
- XSetForeground(butPtr->display, butPtr->stippleGC,
- Tk_3DBorderColor(butPtr->selectBorder)->pixel);
- }
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
+ }
- /*
- * Stipple the whole button if no disabledFg was specified, otherwise
- * restrict stippling only to displayed image
- */
+ /*Overlay Tk elements over button native region: drawing elements within button boundaries/native region causes unpredictable metrics.*/
+ DrawButtonImageAndText( butPtr);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ButtonEventProc --
+ *
+ * This procedure is invoked by the Tk dispatcher for various
+ * events on buttons.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * When it gets exposed, it is redisplayed.
+ *
+ *--------------------------------------------------------------
+ */
+
+static void
+ButtonEventProc(
+ ClientData clientData, /* Information about window. */
+ XEvent *eventPtr) /* Information about event. */
+{
+ TkButton *buttonPtr = (TkButton *) clientData;
+ MacButton *mbPtr = (MacButton *) clientData;
- if (butPtr->disabledFg == NULL) {
- XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC, 0, 0,
- (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin));
+ if (eventPtr->type == ActivateNotify
+ || eventPtr->type == DeactivateNotify) {
+ if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) {
+ return;
+ }
+ if (eventPtr->type == ActivateNotify) {
+ mbPtr->flags |= ACTIVE;
} else {
- XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
- imageXOffset, imageYOffset,
- (unsigned) imageWidth, (unsigned) imageHeight);
+ mbPtr->flags &= ~ACTIVE;
}
- if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
- && (butPtr->selectBorder != NULL)) {
- XSetForeground(butPtr->display, butPtr->stippleGC,
- Tk_3DBorderColor(butPtr->normalBorder)->pixel);
+ if ((buttonPtr->flags & REDRAW_PENDING) == 0) {
+ Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) buttonPtr);
+ buttonPtr->flags |= REDRAW_PENDING;
}
}
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXComputeButtonParams --
+ *
+ * This procedure computes the various parameters used
+ * when creating a Carbon Appearance control.
+ * These are determined by the various tk button parameters
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Sets the btnkind and drawinfo parameters
+ *
+ *----------------------------------------------------------------------
+ */
- /*
- * Draw the border and traversal highlight last. This way, if the button's
- * contents overflow they'll be covered up by the border. This code is
- * complicated by the possible combinations of focus highlight and default
- * rings. We draw the focus and highlight rings using the highlight border
- * and highlight foreground color.
- */
-
- if (relief != TK_RELIEF_FLAT) {
- int inset = butPtr->highlightWidth;
-
- if (butPtr->defaultState == DEFAULT_ACTIVE) {
- /*
- * Draw the default ring with 2 pixels of space between the
- * default ring and the button and the default ring and the focus
- * ring. Note that we need to explicitly draw the space in the
- * highlightBorder color to ensure that we overwrite any overflow
- * text and/or a different button background color.
- */
-
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
- inset, Tk_Width(tkwin) - 2*inset,
- Tk_Height(tkwin) - 2*inset, 2, TK_RELIEF_FLAT);
- inset += 2;
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
- inset, Tk_Width(tkwin) - 2*inset,
- Tk_Height(tkwin) - 2*inset, 1, TK_RELIEF_SUNKEN);
- inset++;
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
- inset, Tk_Width(tkwin) - 2*inset,
- Tk_Height(tkwin) - 2*inset, 2, TK_RELIEF_FLAT);
-
- inset += 2;
- } else if (butPtr->defaultState == DEFAULT_NORMAL) {
- /*
- * Leave room for the default ring and write over any text or
- * background color.
- */
+static void
+TkMacOSXComputeButtonParams(
+ TkButton * butPtr,
+ ThemeButtonKind* btnkind,
+ HIThemeButtonDrawInfo *drawinfo)
+{
+ MacButton *mbPtr = (MacButton *)butPtr;
+
+ if (butPtr->borderWidth <= 2) {
+ *btnkind = kThemeSmallBevelButton;
+ } else if (butPtr->borderWidth == 3) {
+ *btnkind = kThemeBevelButton;
+ } else if (butPtr->borderWidth == 4) {
+ *btnkind = kThemeRoundedBevelButton;
+ } else {
+ *btnkind = kThemePushButton;
+ }
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0,
- 0, Tk_Width(tkwin), Tk_Height(tkwin), 5, TK_RELIEF_FLAT);
- inset += 5;
+ if ((butPtr->image == None) && (butPtr->bitmap == None)) {
+ switch (butPtr->type) {
+ case TYPE_BUTTON:
+ *btnkind = kThemePushButton;
+ break;
+ case TYPE_RADIO_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallRadioButton;
+ } else {
+ *btnkind = kThemeRadioButton;
+ }
+ break;
+ case TYPE_CHECK_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallCheckBox;
+ } else {
+ *btnkind = kThemeCheckBox;
+ }
+ break;
}
+ }
- /*
- * Draw the button border.
- */
+ if (butPtr->indicatorOn) {
+ switch (butPtr->type) {
+ case TYPE_RADIO_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallRadioButton;
+ } else {
+ *btnkind = kThemeRadioButton;
+ }
+ break;
+ case TYPE_CHECK_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallCheckBox;
+ } else {
+ *btnkind = kThemeCheckBox;
+ }
+ break;
+ }
+ } else {
+ if (butPtr->type == TYPE_RADIO_BUTTON ||
+ butPtr->type == TYPE_CHECK_BUTTON
+ ) {
+ if (*btnkind == kThemePushButton) {
+ *btnkind = kThemeBevelButton;
+ }
+ }
+ }
- Tk_Draw3DRectangle(tkwin, pixmap, border, inset, inset,
- Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset,
- butPtr->borderWidth, relief);
+ if (butPtr->flags & SELECTED) {
+ drawinfo->value = kThemeButtonOn;
+ } else if (butPtr->flags & TRISTATED) {
+ drawinfo->value = kThemeButtonMixed;
+ } else {
+ drawinfo->value = kThemeButtonOff;
}
- if (butPtr->highlightWidth > 0) {
- GC gc;
- if (butPtr->flags & GOT_FOCUS) {
- gc = Tk_GCForColor(butPtr->highlightColorPtr, pixmap);
- } else {
- gc = Tk_GCForColor(Tk_3DBorderColor(butPtr->highlightBorder),
- pixmap);
+ if ((mbPtr->flags & FIRST_DRAW) != 0) {
+ mbPtr->flags &= ~FIRST_DRAW;
+ if (Tk_MacOSXIsAppInFront()) {
+ mbPtr->flags |= ACTIVE;
}
+ }
- /*
- * Make sure the focus ring shrink-wraps the actual button, not the
- * padding space left for a default ring.
- */
+ drawinfo->state = kThemeStateInactive;
+ if ((mbPtr->flags & ACTIVE) == 0) {
+ if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailableInactive;
+ } else {
+ drawinfo->state = kThemeStateInactive;
+ }
+ } else if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailable;
+ } else if (butPtr->state == STATE_ACTIVE) {
+ drawinfo->state = kThemeStatePressed;
+ } else {
+ drawinfo->state = kThemeStateActive;
+ }
- if (butPtr->defaultState == DEFAULT_NORMAL) {
- TkDrawInsetFocusHighlight(tkwin, gc, butPtr->highlightWidth,
- pixmap, 5);
- } else {
- Tk_DrawFocusHighlight(tkwin, gc, butPtr->highlightWidth, pixmap);
- }
+ drawinfo->adornment = kThemeAdornmentNone;
+ if (butPtr->defaultState == DEFAULT_ACTIVE) {
+ drawinfo->adornment |= kThemeAdornmentDefault;
+ if (!mbPtr->defaultPulseHandler) {
+ mbPtr->defaultPulseHandler = Tcl_CreateTimerHandler(
+ PULSE_TIMER_MSECS, PulseDefaultButtonProc,
+ (ClientData) butPtr);
+ }
+ } else if (mbPtr->defaultPulseHandler) {
+ Tcl_DeleteTimerHandler(mbPtr->defaultPulseHandler);
+ }
+ if (butPtr->highlightWidth >= 3) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ drawinfo->adornment |= kThemeAdornmentFocus;
+ }
}
}
/*
*----------------------------------------------------------------------
*
- * ComputeUnixButtonGeometry --
+ * TkMacOSXComputeButtonDrawParams --
*
- * After changes in a button's text or bitmap, this procedure
- * recomputes the button's geometry and passes this information
- * along to the geometry manager for the window.
+ * This procedure computes the various parameters used
+ * when drawing a button
+ * These are determined by the various tk button parameters
*
* Results:
- * None.
+ * 1 if control will be used, 0 otherwise.
*
* Side effects:
- * The button's window may change size.
+ * Sets the button draw parameters
*
*----------------------------------------------------------------------
*/
-void
-ComputeUnixButtonGeometry(
- register TkButton *butPtr) /* Button whose geometry may have changed. */
+static int
+TkMacOSXComputeButtonDrawParams(
+ TkButton *butPtr,
+ DrawParams *dpPtr)
{
- int width, height, avgWidth, txtWidth, txtHeight;
- int haveImage = 0, haveText = 0;
- Tk_FontMetrics fm;
-
- butPtr->inset = butPtr->highlightWidth + butPtr->borderWidth;
-
- /*
- * Leave room for the default ring if needed.
- */
-
- if (butPtr->defaultState != DEFAULT_DISABLED) {
- butPtr->inset += 5;
+ MacButton *mbPtr = (MacButton *)butPtr;
+
+ dpPtr->hasImageOrBitmap = ((butPtr->image != NULL)
+ || (butPtr->bitmap != None));
+
+ if (butPtr->type != TYPE_LABEL) {
+ dpPtr->offset = 0;
+ if (dpPtr->hasImageOrBitmap) {
+ switch (mbPtr->btnkind) {
+ case kThemeSmallBevelButton:
+ case kThemeBevelButton:
+ case kThemeRoundedBevelButton:
+ case kThemePushButton:
+ dpPtr->offset = 1;
+ break;
+ }
+ }
}
- butPtr->indicatorSpace = 0;
- width = 0;
- height = 0;
- txtWidth = 0;
- txtHeight = 0;
- avgWidth = 0;
- if (butPtr->image != NULL) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- haveImage = 1;
- } else if (butPtr->bitmap != None) {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- haveImage = 1;
+ dpPtr->border = butPtr->normalBorder;
+ if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
+ dpPtr->gc = butPtr->disabledGC;
+ } else if (butPtr->type == TYPE_BUTTON && butPtr->state == STATE_ACTIVE) {
+ dpPtr->gc = butPtr->activeTextGC;
+ dpPtr->border = butPtr->activeBorder;
+ } else {
+ dpPtr->gc = butPtr->normalTextGC;
}
- if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
- Tk_FreeTextLayout(butPtr->textLayout);
-
- butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
- Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength,
- butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
-
- txtWidth = butPtr->textWidth;
- txtHeight = butPtr->textHeight;
- avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
- Tk_GetFontMetrics(butPtr->tkfont, &fm);
- haveText = (txtWidth != 0 && txtHeight != 0);
+ if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE)
+ && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) {
+ dpPtr->border = butPtr->selectBorder;
}
/*
- * If the button is compound (i.e., it shows both an image and text), the
- * new geometry is a combination of the image and text geometry. We only
- * honor the compound bit if the button has both text and an image,
- * because otherwise it is not really a compound button.
+ * Override the relief specified for the button if this is a
+ * checkbutton or radiobutton and there's no indicator.
*/
- if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
- switch ((enum compound) butPtr->compound) {
- case COMPOUND_TOP:
- case COMPOUND_BOTTOM:
- /*
- * Image is above or below text.
- */
+ dpPtr->relief = butPtr->relief;
- height += txtHeight + butPtr->padY;
- width = (width > txtWidth ? width : txtWidth);
- break;
- case COMPOUND_LEFT:
- case COMPOUND_RIGHT:
- /*
- * Image is left or right of text.
- */
-
- width += txtWidth + butPtr->padX;
- height = (height > txtHeight ? height : txtHeight);
- break;
- case COMPOUND_CENTER:
- /*
- * Image and text are superimposed.
- */
-
- width = (width > txtWidth ? width : txtWidth);
- height = (height > txtHeight ? height : txtHeight);
- break;
- case COMPOUND_NONE:
- break;
- }
- if (butPtr->width > 0) {
- width = butPtr->width;
- }
- if (butPtr->height > 0) {
- height = butPtr->height;
+ if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) {
+ if (!dpPtr->hasImageOrBitmap) {
+ dpPtr->relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN
+ : TK_RELIEF_RAISED;
}
+ }
- width += 2*butPtr->padX;
- height += 2*butPtr->padY;
- } else {
- if (haveImage) {
- if (butPtr->width > 0) {
- width = butPtr->width;
- }
- if (butPtr->height > 0) {
- height = butPtr->height;
- }
- } else {
- width = txtWidth;
- height = txtHeight;
+ /*
+ * Determine the draw type
+ */
- if (butPtr->width > 0) {
- width = butPtr->width * avgWidth;
- }
- if (butPtr->height > 0) {
- height = butPtr->height * fm.linespace;
- }
+ if (butPtr->type == TYPE_LABEL) {
+ dpPtr->drawType = DRAW_LABEL;
+ } else if (butPtr->type == TYPE_BUTTON) {
+ if (!dpPtr->hasImageOrBitmap) {
+ dpPtr->drawType = DRAW_CONTROL;
+ } else {
+ dpPtr->drawType = DRAW_BEVEL;
}
+ } else if (butPtr->indicatorOn) {
+ dpPtr->drawType = DRAW_CONTROL;
+ } else if (dpPtr->hasImageOrBitmap) {
+ dpPtr->drawType = DRAW_BEVEL;
+ } else {
+ dpPtr->drawType = DRAW_CUSTOM;
}
- if (!haveImage) {
- width += 2*butPtr->padX;
- height += 2*butPtr->padY;
+ if ((dpPtr->drawType == DRAW_CONTROL) || (dpPtr->drawType == DRAW_BEVEL)) {
+ return 1;
+ } else {
+ return 0;
}
- Tk_GeometryRequest(butPtr->tkwin, (int) (width
- + 2*butPtr->inset), (int) (height + 2*butPtr->inset));
- Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
}
/*
- * Local Variables:
- * mode: objc
- * c-basic-offset: 4
- * fill-column: 79
- * coding: utf-8
- * End:
+ *--------------------------------------------------------------
+ *
+ * PulseDefaultButtonProc --
+ *
+ * This function redraws the button on a timer, to pulse
+ * default buttons.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Sets a timer to run itself again.
+ *
+ *--------------------------------------------------------------
*/
+static void
+PulseDefaultButtonProc(ClientData clientData)
+{
+ MacButton *mbPtr = (MacButton *)clientData;
+ TkpDisplayButton(clientData);
+ mbPtr->defaultPulseHandler = Tcl_CreateTimerHandler(
+ PULSE_TIMER_MSECS, PulseDefaultButtonProc, clientData);
+}
+
diff --git a/macosx/tkMacOSXCursor.c b/macosx/tkMacOSXCursor.c
index 53c2cd2..b6394b7 100644
--- a/macosx/tkMacOSXCursor.c
+++ b/macosx/tkMacOSXCursor.c
@@ -344,7 +344,7 @@ FindCursorByName(
macCursor = [[NSCursor alloc] initWithImage:image hotSpot:hotSpot];
[image release];
}
- macCursorPtr->macCursor = TkMacOSXMakeUncollectable(macCursor);
+ macCursorPtr->macCursor = macCursor;
}
/*
@@ -454,7 +454,8 @@ TkpFreeCursor(
{
TkMacOSXCursor *macCursorPtr = (TkMacOSXCursor *) cursorPtr;
- TkMacOSXMakeCollectableAndRelease(macCursorPtr->macCursor);
+ [macCursorPtr->macCursor release];
+ macCursorPtr->macCursor = NULL;
if (macCursorPtr == gCurrentCursor) {
gCurrentCursor = NULL;
}
diff --git a/macosx/tkMacOSXDefault.h b/macosx/tkMacOSXDefault.h
index 903f5f9..dc73188 100644
--- a/macosx/tkMacOSXDefault.h
+++ b/macosx/tkMacOSXDefault.h
@@ -16,9 +16,9 @@
#ifndef _TKMACDEFAULT
#define _TKMACDEFAULT
-#ifndef TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-#define TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS 1
-#endif
+//#ifndef TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+//#define TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS 1
+//#endif
/*
* The definitions below provide symbolic names for the default colors.
@@ -72,12 +72,12 @@
#define DEF_BUTTON_HIGHLIGHT_BG_MONO DEF_BUTTON_BG_MONO
#define DEF_BUTTON_HIGHLIGHT "systemButtonFrame"
#define DEF_LABEL_HIGHLIGHT_WIDTH "0"
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-#define DEF_BUTTON_HIGHLIGHT_WIDTH "4"
-#define DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM "1"
-#else
+//#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+//#define DEF_BUTTON_HIGHLIGHT_WIDTH "4"
+//#define DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM "1"
+//#else
#define DEF_BUTTON_HIGHLIGHT_WIDTH "1"
-#endif
+//#endif
#define DEF_BUTTON_IMAGE ((char *) NULL)
#define DEF_BUTTON_INDICATOR "1"
#define DEF_BUTTON_JUSTIFY "center"
@@ -85,19 +85,19 @@
#define DEF_BUTTON_ON_VALUE "1"
#define DEF_BUTTON_TRISTATE_VALUE ""
#define DEF_BUTTON_OVER_RELIEF ""
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-#define DEF_BUTTON_PADX "12"
-#define DEF_BUTTON_PADX_NOCM "1"
-#else
+//#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+//#define DEF_BUTTON_PADX "12"
+//#define DEF_BUTTON_PADX_NOCM "1"
+//#else
#define DEF_BUTTON_PADX "1"
-#endif
+//#endif
#define DEF_LABCHKRAD_PADX "1"
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-#define DEF_BUTTON_PADY "3"
-#define DEF_BUTTON_PADY_NOCM "1"
-#else
+//#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+//#define DEF_BUTTON_PADY "3"
+//#define DEF_BUTTON_PADY_NOCM "1"
+//#else
#define DEF_BUTTON_PADY "1"
-#endif
+//#endif
#define DEF_LABCHKRAD_PADY "1"
#define DEF_BUTTON_RELIEF "flat"
#define DEF_LABCHKRAD_RELIEF "flat"
@@ -410,6 +410,7 @@
#define DEF_PANEDWINDOW_HEIGHT ""
#define DEF_PANEDWINDOW_OPAQUERESIZE "1"
#define DEF_PANEDWINDOW_ORIENT "horizontal"
+#define DEF_PANEDWINDOW_PROXYBORDER "2"
#define DEF_PANEDWINDOW_RELIEF "flat"
#define DEF_PANEDWINDOW_SASHCURSOR ""
#define DEF_PANEDWINDOW_SASHPAD "0"
diff --git a/macosx/tkMacOSXDialog.c b/macosx/tkMacOSXDialog.c
index a66939a..257f16d 100644
--- a/macosx/tkMacOSXDialog.c
+++ b/macosx/tkMacOSXDialog.c
@@ -14,6 +14,17 @@
#include "tkMacOSXPrivate.h"
#include "tkFileFilter.h"
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
+#define modalOK NSOKButton
+#define modalCancel NSCancelButton
+#else
+#define modalOK NSModalResponseOK
+#define modalCancel NSModalResponseCancel
+#endif
+#define modalOther -1
+#define modalError -2
+
+
static const char *const colorOptionStrings[] = {
"-initialcolor", "-parent", "-title", NULL
};
@@ -130,6 +141,23 @@ static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = {
[TYPE_YESNO] = {5, 6, 0},
[TYPE_YESNOCANCEL] = {5, 6, 4},
};
+
+/*
+ * 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];
+ }
+ if (filename) {
+ url = [NSURL URLWithString:filename relativeToURL:url];
+ }
+ return url;
+}
+#endif
#pragma mark TKApplication(TKDialog)
@@ -149,12 +177,12 @@ static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = {
if (callbackInfo->multiple) {
resultObj = Tcl_NewListObj(0, NULL);
- for (NSString *name in [(NSOpenPanel*)panel filenames]) {
+ for (NSURL *url in [(NSOpenPanel*)panel URLs]) {
Tcl_ListObjAppendElement(callbackInfo->interp, resultObj,
- Tcl_NewStringObj([name UTF8String], -1));
+ Tcl_NewStringObj([[url path] UTF8String], -1));
}
} else {
- resultObj = Tcl_NewStringObj([[panel filename] UTF8String], -1);
+ resultObj = Tcl_NewStringObj([[[panel URL]path] UTF8String], -1);
}
if (callbackInfo->cmdObj) {
Tcl_Obj **objv, **tmpv;
@@ -189,7 +217,7 @@ static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = {
{
AlertCallbackInfo *callbackInfo = contextInfo;
- if (returnCode != NSAlertErrorReturn) {
+ if (returnCode >= NSAlertFirstButtonReturn) {
Tcl_Obj *resultObj = Tcl_NewStringObj(alertButtonStrings[
alertNativeButtonIndexAndTypeToButtonIndex[callbackInfo->
typeIndex][returnCode - NSAlertFirstButtonReturn]], -1);
@@ -309,7 +337,7 @@ Tk_ChooseColorObjCmd(
[colorPanel setColor:initialColor];
}
returnCode = [NSApp runModalForWindow:colorPanel];
- if (returnCode == NSOKButton) {
+ if (returnCode == modalOK) {
color = [[colorPanel color] colorUsingColorSpace:
[NSColorSpace genericRGBColorSpace]];
numberOfComponents = [color numberOfComponents];
@@ -369,7 +397,8 @@ Tk_GetOpenFileObjCmd(
NSWindow *parent;
NSMutableArray *fileTypes = nil;
NSOpenPanel *panel = [NSOpenPanel openPanel];
- NSInteger returnCode = NSAlertErrorReturn;
+ NSInteger modalReturnCode = modalError;
+ BOOL parentIsKey = NO;
TkInitFileFilters(&fl);
for (i = 1; i < objc; i += 2) {
@@ -439,6 +468,7 @@ Tk_GetOpenFileObjCmd(
break;
}
}
+ [panel setAllowsMultipleSelection:multiple];
if (fl.filters) {
fileTypes = [NSMutableArray array];
for (FileFilter *filterPtr = fl.filters; filterPtr;
@@ -471,7 +501,7 @@ Tk_GetOpenFileObjCmd(
}
}
}
- [panel setAllowsMultipleSelection:multiple];
+ [panel setAllowedFileTypes:fileTypes];
if (cmdObj) {
callbackInfo = ckalloc(sizeof(FilePanelCallbackInfo));
if (Tcl_IsShared(cmdObj)) {
@@ -484,19 +514,41 @@ Tk_GetOpenFileObjCmd(
callbackInfo->multiple = multiple;
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
if (haveParentOption && parent && ![parent attachedSheet]) {
- [panel beginSheetForDirectory:directory file:filename types:fileTypes
- modalForWindow:parent modalDelegate:NSApp didEndSelector:
- @selector(tkFilePanelDidEnd:returnCode:contextInfo:)
- contextInfo:callbackInfo];
- returnCode = cmdObj ? NSAlertOtherReturn :
- [NSApp runModalForWindow:panel];
+ 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
+ completionHandler:^(NSInteger returnCode)
+ { [NSApp tkFilePanelDidEnd:panel
+ returnCode:returnCode
+ contextInfo:callbackInfo ]; } ];
+#endif
+ modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:panel];
} else {
- returnCode = [panel runModalForDirectory:directory file:filename
- types:fileTypes];
- [NSApp tkFilePanelDidEnd:panel returnCode:returnCode
+#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
contextInfo:callbackInfo];
}
- result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR;
+ result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR;
+ if (parentIsKey) {
+ [parent makeKeyWindow];
+ }
if (typeVariablePtr && result == TCL_OK) {
/*
* The -typevariable option is not really supported.
@@ -548,7 +600,8 @@ Tk_GetSaveFileObjCmd(
NSWindow *parent;
NSMutableArray *fileTypes = nil;
NSSavePanel *panel = [NSSavePanel savePanel];
- NSInteger returnCode = NSAlertErrorReturn;
+ NSInteger modalReturnCode = modalError;
+ BOOL parentIsKey = NO;
TkInitFileFilters(&fl);
for (i = 1; i < objc; i += 2) {
@@ -665,19 +718,38 @@ Tk_GetSaveFileObjCmd(
callbackInfo->multiple = 0;
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
if (haveParentOption && parent && ![parent attachedSheet]) {
- [panel beginSheetForDirectory:directory file:filename
- modalForWindow:parent modalDelegate:NSApp didEndSelector:
- @selector(tkFilePanelDidEnd:returnCode:contextInfo:)
- contextInfo:callbackInfo];
- returnCode = cmdObj ? NSAlertOtherReturn :
- [NSApp runModalForWindow:panel];
+ 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
+ completionHandler:^(NSInteger returnCode)
+ { [NSApp tkFilePanelDidEnd:panel
+ returnCode:returnCode
+ contextInfo:callbackInfo ]; } ];
+#endif
+ modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:panel];
} else {
- returnCode = [panel runModalForDirectory:directory file:filename];
- [NSApp tkFilePanelDidEnd:panel returnCode:returnCode
+#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
contextInfo:callbackInfo];
}
- result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR;
-
+ result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR;
+ if (parentIsKey) {
+ [parent makeKeyWindow];
+ }
end:
TkFreeFileFilters(&fl);
return result;
@@ -719,7 +791,8 @@ Tk_ChooseDirectoryObjCmd(
NSString *message, *title;
NSWindow *parent;
NSOpenPanel *panel = [NSOpenPanel openPanel];
- NSInteger returnCode = NSAlertErrorReturn;
+ NSInteger modalReturnCode = modalError;
+ BOOL parentIsKey = NO;
for (i = 1; i < objc; i += 2) {
if (Tcl_GetIndexFromObjStruct(interp, objv[i], chooseOptionStrings,
@@ -787,19 +860,37 @@ Tk_ChooseDirectoryObjCmd(
callbackInfo->multiple = 0;
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
if (haveParentOption && parent && ![parent attachedSheet]) {
- [panel beginSheetForDirectory:directory file:filename
- modalForWindow:parent modalDelegate:NSApp didEndSelector:
- @selector(tkFilePanelDidEnd:returnCode:contextInfo:)
+ 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];
- returnCode = cmdObj ? NSAlertOtherReturn :
- [NSApp runModalForWindow:panel];
+#else
+ [panel setDirectoryURL:getFileURL(directory, filename)];
+ [panel beginSheetModalForWindow:parent
+ completionHandler:^(NSInteger returnCode)
+ { [NSApp tkFilePanelDidEnd:panel
+ returnCode:returnCode
+ contextInfo:callbackInfo ]; } ];
+#endif
+ modalReturnCode = cmdObj ? modalOther : [NSApp runModalForWindow:panel];
} else {
- returnCode = [panel runModalForDirectory:directory file:filename];
- [NSApp tkFilePanelDidEnd:panel returnCode:returnCode
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+ modalReturnCode = [panel runModalForDirectory:directory file:nil];
+#else
+ [panel setDirectoryURL:getFileURL(directory, filename)];
+ modalReturnCode = [panel runModal];
+#endif
+ [NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode
contextInfo:callbackInfo];
}
- result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR;
-
+ result = (modalReturnCode != modalError) ? TCL_OK : TCL_ERROR;
+ if (parentIsKey) {
+ [parent makeKeyWindow];
+ }
end:
return result;
}
@@ -857,6 +948,9 @@ TkAboutDlg(void)
[[[NSAttributedString alloc] initWithString:
[NSString stringWithFormat:
@"%1$C 1987-%2$@ Tcl Core Team." "\n\n"
+ "%1$C 1989-%2$@ Contributors." "\n\n"
+ "%1$C 2011-%2$@ Kevin Walzer/WordTech Communications LLC." "\n\n"
+ "%1$C 2014-%2$@ Marc Culler." "\n\n"
"%1$C 2002-%2$@ Daniel A. Steffen." "\n\n"
"%1$C 2001-2009 Apple Inc." "\n\n"
"%1$C 2001-2002 Jim Ingham & Ian Reid" "\n\n"
@@ -896,7 +990,7 @@ TkMacOSXStandardAboutPanelObjCmd(
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
- [NSApp orderFrontStandardAboutPanelWithOptions:nil];
+ [NSApp orderFrontStandardAboutPanelWithOptions:[NSDictionary dictionary]];
return TCL_OK;
}
@@ -934,8 +1028,9 @@ Tk_MessageBoxObjCmd(
NSWindow *parent;
NSArray *buttons;
NSAlert *alert = [NSAlert new];
- NSInteger returnCode = NSAlertErrorReturn;
-
+ NSInteger modalReturnCode = 1;
+ BOOL parentIsKey = NO;
+
iconIndex = ICON_INFO;
typeIndex = TYPE_OK;
for (i = 1; i < objc; i += 2) {
@@ -1061,19 +1156,32 @@ Tk_MessageBoxObjCmd(
callbackInfo->typeIndex = typeIndex;
parent = TkMacOSXDrawableWindow(((TkWindow *) tkwin)->window);
if (haveParentOption && parent && ![parent attachedSheet]) {
- [alert beginSheetModalForWindow:parent modalDelegate:NSApp
- didEndSelector:@selector(tkAlertDidEnd:returnCode:contextInfo:)
- contextInfo:callbackInfo];
- returnCode = cmdObj ? NSAlertOtherReturn :
- [NSApp runModalForWindow:[alert window]];
+ parentIsKey = [parent isKeyWindow];
+#if MAC_OS_X_VERSION_MIN_REQUIRED > 1090
+ [alert beginSheetModalForWindow:parent
+ completionHandler:^(NSModalResponse returnCode)
+ { [NSApp tkAlertDidEnd:alert
+ returnCode:returnCode
+ contextInfo:callbackInfo ]; } ];
+#else
+ [alert beginSheetModalForWindow:parent
+ modalDelegate:NSApp
+ didEndSelector:@selector(tkAlertDidEnd:returnCode:contextInfo:)
+ contextInfo:callbackInfo];
+#endif
+ modalReturnCode = cmdObj ? 0 :
+ [NSApp runModalForWindow:[alert window]];
} else {
- returnCode = [alert runModal];
- [NSApp tkAlertDidEnd:alert returnCode:returnCode
+ modalReturnCode = [alert runModal];
+ [NSApp tkAlertDidEnd:alert returnCode:modalReturnCode
contextInfo:callbackInfo];
}
- result = (returnCode != NSAlertErrorReturn) ? TCL_OK : TCL_ERROR;
+ result = (modalReturnCode >= NSAlertFirstButtonReturn) ? TCL_OK : TCL_ERROR;
end:
[alert release];
+ if (parentIsKey) {
+ [parent makeKeyWindow];
+ }
return result;
}
@@ -1643,9 +1751,7 @@ TkInitFontchooser(
Tcl_SetAssocData(interp, "::tk::fontchooser", DeleteFontchooserData,
fcdPtr);
if (!fontPanelFontAttributes) {
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
fontPanelFontAttributes = [NSMutableDictionary new];
- [pool drain];
}
return TCL_OK;
}
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c
index 0727b26..6a0b409 100644
--- a/macosx/tkMacOSXDraw.c
+++ b/macosx/tkMacOSXDraw.c
@@ -8,6 +8,7 @@
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2014 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -16,7 +17,7 @@
#include "tkMacOSXPrivate.h"
#include "tkMacOSXDebug.h"
#include "xbytes.h"
-
+#include "tkButton.h"
/*
#ifdef TK_MAC_DEBUG
@@ -100,13 +101,6 @@ TkMacOSXInitCGDrawing(
(char *) &useThemedFrame, TCL_LINK_BOOLEAN) != TCL_OK) {
Tcl_ResetResult(interp);
}
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (Tcl_LinkVar(interp, "::tk::mac::useCompatibilityMetrics",
- (char *) &tkMacOSXUseCompatibilityMetrics, TCL_LINK_BOOLEAN)
- != TCL_OK) {
- Tcl_ResetResult(interp);
- }
-#endif
}
return TCL_OK;
}
@@ -114,10 +108,81 @@ TkMacOSXInitCGDrawing(
/*
*----------------------------------------------------------------------
*
+ * BitmapRepFromDrawableRect
+ *
+ * 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.
+ *
+ * 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
+ * left as used by NSView.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+NSBitmapImageRep*
+BitmapRepFromDrawableRect(
+ Drawable drawable,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height)
+{
+ MacDrawable *mac_drawable = (MacDrawable *) drawable;
+ CGContextRef cg_context=NULL;
+ CGImageRef cg_image=NULL, sub_cg_image=NULL;
+ NSBitmapImageRep *bitmap_rep=NULL;
+ 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.
+ */
+ cg_context = GetCGContextForDrawable(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];
+ }
+ if ( cg_image ) {
+ CGImageRelease(cg_image);
+ }
+ } else if ( (view = TkMacOSXDrawableView(mac_drawable)) ) {
+ /* convert top-left coordinates to NSView 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);
+
+ 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];
+ } else {
+ TkMacOSXDbgMsg("Could not lock focus on view.");
+ }
+
+ } else {
+ TkMacOSXDbgMsg("Invalid source drawable");
+ }
+ return bitmap_rep;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* XCopyArea --
*
- * Copies data from one drawable to another using block transfer
- * routines.
+ * Copies data from one drawable to another.
*
* Results:
* None.
@@ -134,86 +199,63 @@ XCopyArea(
Display *display, /* Display. */
Drawable src, /* Source drawable. */
Drawable dst, /* Destination drawable. */
- GC gc, /* GC to use. */
+ GC gc, /* GC to use. */
int src_x, /* X & Y, width & height */
int src_y, /* define the source rectangle */
- unsigned int width, /* that will be copied. */
+ unsigned int width, /* that will be copied. */
unsigned int height,
int dest_x, /* Dest X & Y on dest rect. */
int dest_y)
{
TkMacOSXDrawingContext dc;
MacDrawable *srcDraw = (MacDrawable *) src;
+ NSBitmapImageRep *bitmap_rep = NULL;
+ CGImageRef img = NULL;
display->request++;
+
if (!width || !height) {
- /* TkMacOSXDbgMsg("Drawing of emtpy area requested"); */
+ /* This happens all the time.
+ TkMacOSXDbgMsg("Drawing of empty area requested");
+ */
return;
}
- if (srcDraw->flags & TK_IS_PIXMAP) {
- if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
- return;
- }
- if (dc.context) {
- CGImageRef img = TkMacOSXCreateCGImageWithDrawable(src);
- if (img) {
- DrawCGImage(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));
- CFRelease(img);
- } else {
- TkMacOSXDbgMsg("Invalid source drawable");
+ if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
+ return;
+ /*TkMacOSXDbgMsg("Failed to setup drawing context.");*/
+ }
+
+ if ( dc.context ) {
+ if (srcDraw->flags & TK_IS_PIXMAP) {
+ img = TkMacOSXCreateCGImageWithDrawable(src);
+ }else if (TkMacOSXDrawableWindow(src)) {
+ bitmap_rep = BitmapRepFromDrawableRect(src, src_x, src_y, width, height);
+ if ( bitmap_rep ) {
+ img = [bitmap_rep CGImage];
}
} else {
- TkMacOSXDbgMsg("Invalid destination drawable");
- }
- TkMacOSXRestoreDrawingContext(&dc);
- } else if (TkMacOSXDrawableWindow(src)) {
- NSView *view = TkMacOSXDrawableView(srcDraw);
- NSWindow *w = [view window];
- NSInteger gs = [w windowNumber] > 0 ? [w gState] : 0;
- /* // alternative using per-view gState:
- NSInteger gs = [view gState];
- if (!gs) {
- [view allocateGState];
- if ([view lockFocusIfCanDraw]) {
- [view unlockFocus];
- }
- gs = [view gState];
+ TkMacOSXDbgMsg("Invalid source drawable - neither window nor pixmap.");
}
- */
- if (!gs || !TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
- return;
- }
- if (dc.context) {
- NSGraphicsContext *gc = nil;
- CGFloat boundsH = [view bounds].size.height;
- NSRect srcRect = NSMakeRect(srcDraw->xOff + src_x, boundsH -
- height - (srcDraw->yOff + src_y), width, height);
-
- if (((MacDrawable *) dst)->flags & TK_IS_PIXMAP) {
- gc = [NSGraphicsContext graphicsContextWithGraphicsPort:
- dc.context flipped:NO];
- if (gc) {
- [NSGraphicsContext saveGraphicsState];
- [NSGraphicsContext setCurrentContext:gc];
- }
- }
- NSCopyBits(gs, srcRect, NSMakePoint(dest_x,
- dc.portBounds.size.height - dest_y));
- if (gc) {
- [NSGraphicsContext restoreGraphicsState];
- }
+
+ if (img) {
+ DrawCGImage(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));
+ CFRelease(img);
+
+
} else {
- TkMacOSXDbgMsg("Invalid destination drawable");
+ TkMacOSXDbgMsg("Failed to construct CGImage.");
}
- TkMacOSXRestoreDrawingContext(&dc);
+
} else {
- TkMacOSXDbgMsg("Invalid source drawable");
+ TkMacOSXDbgMsg("Invalid destination drawable - no context.");
+ return;
}
+
+ TkMacOSXRestoreDrawingContext(&dc);
}
/*
@@ -240,10 +282,10 @@ XCopyPlane(
Display *display, /* Display. */
Drawable src, /* Source drawable. */
Drawable dst, /* Destination drawable. */
- GC gc, /* GC to use. */
+ GC gc, /* GC to use. */
int src_x, /* X & Y, width & height */
int src_y, /* define the source rectangle */
- unsigned int width, /* that will be copied. */
+ unsigned int width, /* that will be copied. */
unsigned int height,
int dest_x, /* Dest X & Y on dest rect. */
int dest_y,
@@ -251,10 +293,11 @@ XCopyPlane(
{
TkMacOSXDrawingContext dc;
MacDrawable *srcDraw = (MacDrawable *) src;
+ MacDrawable *dstDraw = (MacDrawable *) dst;
display->request++;
if (!width || !height) {
- /* TkMacOSXDbgMsg("Drawing of emtpy area requested"); */
+ /* TkMacOSXDbgMsg("Drawing of empty area requested"); */
return;
}
if (plane != 1) {
@@ -264,33 +307,47 @@ XCopyPlane(
if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
return;
}
- if (dc.context) {
+ CGContextRef context = dc.context;
+ if (context) {
CGImageRef img = TkMacOSXCreateCGImageWithDrawable(src);
-
if (img) {
TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask;
unsigned long imageBackground = gc->background;
-
- if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP &&
- clipPtr->value.pixmap == src) {
- imageBackground = TRANSPARENT_PIXEL << 24;
+ if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP){
+ CGImageRef mask = TkMacOSXCreateCGImageWithDrawable(clipPtr->value.pixmap);
+ CGRect rect = CGRectMake(dest_x, dest_y, width, height);
+ rect = CGRectOffset(rect, dstDraw->xOff, dstDraw->yOff);
+ CGContextSaveGState(context);
+ /* Move the origin of the destination to top left. */
+ CGContextTranslateCTM(context, 0, rect.origin.y + CGRectGetMaxY(rect));
+ CGContextScaleCTM(context, 1, -1);
+ /* Fill with the background color, clipping to the mask. */
+ CGContextClipToMask(context, rect, mask);
+ TkMacOSXSetColorInContext(gc, gc->background, dc.context);
+ CGContextFillRect(dc.context, rect);
+ /* Fill with the foreground color, clipping to the intersection of img and mask. */
+ CGContextClipToMask(context, rect, img);
+ TkMacOSXSetColorInContext(gc, gc->foreground, context);
+ CGContextFillRect(context, rect);
+ CGContextRestoreGState(context);
+ CGImageRelease(mask);
+ CGImageRelease(img);
+ } else {
+ DrawCGImage(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));
+ CGImageRelease(img);
}
- DrawCGImage(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));
- CFRelease(img);
- } else {
+ } else { /* no image */
TkMacOSXDbgMsg("Invalid source drawable");
}
} else {
- TkMacOSXDbgMsg("Invalid destination drawable");
+ TkMacOSXDbgMsg("Invalid destination drawable - could not get a bitmap context.");
}
TkMacOSXRestoreDrawingContext(&dc);
- } else {
- XCopyArea(display, src, dst, gc, src_x, src_y, width, height, dest_x,
- dest_y);
+ } else { /* source drawable is a window, not a Pixmap */
+ XCopyArea(display, src, dst, gc, src_x, src_y, width, height, dest_x, dest_y);
}
}
@@ -314,16 +371,16 @@ XCopyPlane(
int
TkPutImage(
unsigned long *colors, /* Unused on Macintosh. */
- int ncolors, /* Unused on Macintosh. */
+ int ncolors, /* Unused on Macintosh. */
Display* display, /* Display. */
Drawable d, /* Drawable to place image on. */
- GC gc, /* GC to use. */
+ 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 width, /* Same width & height for both */
unsigned int height) /* distination and source. */
{
TkMacOSXDrawingContext dc;
@@ -384,22 +441,17 @@ CreateCGImageWithXImage(
char *data = NULL;
CGDataProviderReleaseDataCallback releaseData = ReleaseData;
- if (image->obdata) {
- /*
- * Image from XGetImage
- */
-
- img = TkMacOSXCreateCGImageWithDrawable((Pixmap) image->obdata);
- } else if (image->bits_per_pixel == 1) {
+ 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;
- decode = decodeWB;
if (image->bitmap_bit_order != MSBFirst) {
char *srcPtr = image->data + image->xoffset;
char *endPtr = srcPtr + len;
@@ -409,23 +461,21 @@ CreateCGImageWithXImage(
*destPtr++ = xBitReverseTable[(unsigned char)(*(srcPtr++))];
}
} else {
- data = memcpy(ckalloc(len), image->data + image->xoffset,
- len);
+ 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);
+ bitsPerPixel, image->bytes_per_line, provider, decode, 0);
}
} else if (image->format == ZPixmap && image->bits_per_pixel == 32) {
/*
* Color image
*/
- CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
bitsPerComponent = 8;
bitsPerPixel = 32;
@@ -440,6 +490,7 @@ CreateCGImageWithXImage(
img = CGImageCreate(image->width, image->height, bitsPerComponent,
bitsPerPixel, image->bytes_per_line, colorspace, bitmapInfo,
provider, decode, 0, kCGRenderingIntentDefault);
+ CFRelease(provider);
}
if (colorspace) {
CFRelease(colorspace);
@@ -447,10 +498,6 @@ CreateCGImageWithXImage(
} else {
TkMacOSXDbgMsg("Unsupported image type");
}
- if (provider) {
- CFRelease(provider);
- }
-
return img;
}
@@ -619,17 +666,16 @@ GetCGContextForDrawable(
CGColorSpaceRef colorspace = NULL;
CGBitmapInfo bitmapInfo =
#ifdef __LITTLE_ENDIAN__
- kCGBitmapByteOrder32Host;
+ kCGBitmapByteOrder32Host;
#else
- kCGBitmapByteOrderDefault;
+ kCGBitmapByteOrderDefault;
#endif
char *data;
- CGRect bounds = CGRectMake(0, 0, macDraw->size.width,
- macDraw->size.height);
+ CGRect bounds = CGRectMake(0, 0, macDraw->size.width, macDraw->size.height);
if (macDraw->flags & TK_IS_BW_PIXMAP) {
bitsPerPixel = 8;
- bitmapInfo = kCGImageAlphaOnly;
+ bitmapInfo = (CGBitmapInfo)kCGImageAlphaOnly;
} else {
colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
bitsPerPixel = 32;
@@ -698,9 +744,11 @@ DrawCGImage(
}
}
dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff);
+
if (CGImageIsMask(image)) {
/*CGContextSaveGState(context);*/
if (macDraw->flags & TK_IS_BW_PIXMAP) {
+ /* Set fill color to black, background comes from the context, or is transparent. */
if (imageBackground != TRANSPARENT_PIXEL << 24) {
CGContextClearRect(context, dstBounds);
}
@@ -713,6 +761,7 @@ DrawCGImage(
TkMacOSXSetColorInContext(gc, imageForeground, context);
}
}
+
#ifdef TK_MAC_DEBUG_IMAGE_DRAWING
CGContextSaveGState(context);
CGContextSetLineWidth(context, 1.0);
@@ -732,8 +781,7 @@ DrawCGImage(
dstBounds.size.width, dstBounds.size.height);
#else /* TK_MAC_DEBUG_IMAGE_DRAWING */
CGContextSaveGState(context);
- CGContextTranslateCTM(context,
- 0, dstBounds.origin.y + CGRectGetMaxY(dstBounds));
+ CGContextTranslateCTM(context, 0, dstBounds.origin.y + CGRectGetMaxY(dstBounds));
CGContextScaleCTM(context, 1, -1);
CGContextDrawImage(context, dstBounds, image);
CGContextRestoreGState(context);
@@ -1441,43 +1489,94 @@ TkScrollWindow(
int dx, int dy, /* Distance rectangle should be moved. */
TkRegion damageRgn) /* Region to accumulate damage in. */
{
- MacDrawable *macDraw = (MacDrawable *) Tk_WindowId(tkwin);
- NSView *view = TkMacOSXDrawableView(macDraw);
- CGRect visRect, srcRect, dstRect;
- CGFloat boundsH;
- HIShapeRef dmgRgn, dstRgn;
- int result;
-
- if (view && !CGRectIsEmpty(visRect = NSRectToCGRect([view visibleRect]))) {
- boundsH = [view bounds].size.height;
- srcRect = CGRectMake(macDraw->xOff + x, boundsH - height -
- (macDraw->yOff + y), width, height);
- dstRect = CGRectIntersection(CGRectOffset(srcRect, dx, -dy), visRect);
- srcRect = CGRectIntersection(srcRect, visRect);
- if (!CGRectIsEmpty(srcRect) && !CGRectIsEmpty(dstRect)) {
- /*
- CGRect sRect = CGRectIntersection(CGRectOffset(dstRect, -dx, dy),
- srcRect);
- NSCopyBits(0, NSRectFromCGRect(sRect),
- NSPointFromCGPoint(CGRectOffset(sRect, dx, -dy).origin));
- */
- [view scrollRect:NSRectFromCGRect(srcRect) by:NSMakeSize(dx, -dy)];
- }
- srcRect.origin.y = boundsH - srcRect.size.height - srcRect.origin.y;
- dstRect.origin.y = boundsH - dstRect.size.height - dstRect.origin.y;
- srcRect = CGRectUnion(srcRect, dstRect);
- dmgRgn = HIShapeCreateMutableWithRect(&srcRect);
- dstRgn = HIShapeCreateWithRect(&dstRect);
- ChkErr(HIShapeDifference, dmgRgn, dstRgn, (HIMutableShapeRef) dmgRgn);
- CFRelease(dstRgn);
- TkMacOSXInvalidateViewRegion(view, dmgRgn);
+ Drawable drawable = Tk_WindowId(tkwin);
+ MacDrawable *macDraw = (MacDrawable *) drawable;
+ TKContentView *view = (TKContentView *)TkMacOSXDrawableView(macDraw);
+ CGRect srcRect, dstRect;
+ HIShapeRef dmgRgn = NULL, extraRgn = NULL;
+ NSRect bounds, visRect, scrollSrc, scrollDst;
+ int result = 0;
+
+ if ( view ) {
+ /* Get the scroll area in NSView coordinates (origin at bottom left). */
+ bounds = [view bounds];
+ scrollSrc = NSMakeRect(
+ macDraw->xOff + x,
+ bounds.size.height - height - (macDraw->yOff + y),
+ width, height);
+ scrollDst = NSOffsetRect(scrollSrc, dx, -dy);
+
+ /* Limit scrolling to the window content area. */
+ visRect = [view visibleRect];
+ 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)
+ * and converted to Tk coordinates later.
+ */
+
+ 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. */
+ TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn);
+ if (extraRgn) {
+ CFRelease(extraRgn);
+ }
+
+ /* 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();
+ TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn);
}
- TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn);
- result = HIShapeIsEmpty(dmgRgn) ? 0 : 1;
- CFRelease(dmgRgn);
+ if (dmgRgn) {
+ CFRelease(dmgRgn);
+ }
return result;
}
@@ -1590,13 +1689,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),
@@ -1754,7 +1853,6 @@ TkMacOSXGetClipRgn(
} else if (macDraw->visRgn) {
clipRgn = HIShapeCreateCopy(macDraw->visRgn);
}
-
return clipRgn;
}
@@ -1812,10 +1910,11 @@ TkpClipDrawableToRect(
CFRelease(macDraw->drawRgn);
macDraw->drawRgn = NULL;
}
+
if (width >= 0 && height >= 0) {
- CGRect drawRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff,
+ CGRect clipRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff,
width, height);
- HIShapeRef drawRgn = HIShapeCreateWithRect(&drawRect);
+ HIShapeRef drawRgn = HIShapeCreateWithRect(&clipRect);
if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) {
TkMacOSXUpdateClipRgn(macDraw->winPtr);
@@ -1828,9 +1927,9 @@ TkpClipDrawableToRect(
macDraw->drawRgn = drawRgn;
}
if (view && view != [NSView focusView] && [view lockFocusIfCanDraw]) {
- drawRect.origin.y = [view bounds].size.height -
- (drawRect.origin.y + drawRect.size.height);
- NSRectClip(NSRectFromCGRect(drawRect));
+ clipRect.origin.y = [view bounds].size.height -
+ (clipRect.origin.y + clipRect.size.height);
+ NSRectClip(NSRectFromCGRect(clipRect));
macDraw->flags |= TK_FOCUSED_VIEW;
}
} else {
@@ -1959,7 +2058,7 @@ TkpDrawHighlightBorder (
* TkpDrawFrame --
*
* This procedure draws the rectangular frame area. If the user
- * has request themeing, it draws with a the background theme.
+ * has requested themeing, it draws with the background theme.
*
* Results:
* None.
@@ -1989,6 +2088,7 @@ TkpDrawFrame(
border = themedBorder;
}
}
+
Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin),
border, highlightWidth, highlightWidth,
Tk_Width(tkwin) - 2 * highlightWidth,
diff --git a/macosx/tkMacOSXEmbed.c b/macosx/tkMacOSXEmbed.c
index e2e05d2..99f7584 100644
--- a/macosx/tkMacOSXEmbed.c
+++ b/macosx/tkMacOSXEmbed.c
@@ -174,6 +174,50 @@ TkpMakeWindow(
/*
*----------------------------------------------------------------------
*
+ * TkpScanWindowId --
+ *
+ * Given a string, produce the corresponding Window Id.
+ *
+ * Results:
+ * The return value is normally TCL_OK; in this case *idPtr will be set
+ * to the Window value equivalent to string. If string is improperly
+ * formed then TCL_ERROR is returned and an error message will be left in
+ * the interp's result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkpScanWindowId(
+ Tcl_Interp *interp,
+ CONST char * string,
+ Window *idPtr)
+{
+ int code;
+ Tcl_Obj obj;
+
+ obj.refCount = 1;
+ obj.bytes = (char *) string; /* DANGER?! */
+ obj.length = strlen(string);
+ obj.typePtr = NULL;
+
+ code = Tcl_GetLongFromObj(interp, &obj, (long *)idPtr);
+
+ if (obj.refCount > 1) {
+ Tcl_Panic("invalid sharing of Tcl_Obj on C stack");
+ }
+ if (obj.typePtr && obj.typePtr->freeIntRepProc) {
+ obj.typePtr->freeIntRepProc(&obj);
+ }
+ return code;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TkpUseWindow --
*
* This procedure causes a Tk window to use a given X window as its
@@ -215,7 +259,7 @@ TkpUseWindow(
}
/*
- * Decode the container pointer, and look for it among the list of
+ * Decode the container window ID, and look for it among the list of
* available containers.
*
* N.B. For now, we are limiting the containers to be in the same Tk
@@ -223,7 +267,7 @@ TkpUseWindow(
* containers.
*/
- if (Tcl_GetInt(interp, string, (int*) &parent) != TCL_OK) {
+ if (TkpScanWindowId(interp, string, (Window *)&parent) != TCL_OK) {
return TCL_ERROR;
}
@@ -563,15 +607,15 @@ int
TkpTestembedCmd(
ClientData clientData, /* Main window for application. */
Tcl_Interp *interp, /* Current interpreter. */
- int argc, /* Number of arguments. */
- const char **argv) /* Argument strings. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *const objv[]) /* Argument strings. */
{
int all;
Container *containerPtr;
Tcl_DString dString;
char buffer[50];
- if ((argc > 1) && (strcmp(argv[1], "all") == 0)) {
+ if ((objc > 1) && (strcmp(Tcl_GetString(objv[1]), "all") == 0)) {
all = 1;
} else {
all = 0;
diff --git a/macosx/tkMacOSXEvent.c b/macosx/tkMacOSXEvent.c
index ea262ff..7f3357f 100644
--- a/macosx/tkMacOSXEvent.c
+++ b/macosx/tkMacOSXEvent.c
@@ -31,18 +31,19 @@ enum {
NSEvent *processedEvent = theEvent;
NSEventType type = [theEvent type];
NSInteger subtype;
- NSUInteger flags;
switch ((NSInteger)type) {
case NSAppKitDefined:
subtype = [theEvent subtype];
switch (subtype) {
+ /* Ignored at the moment. */
case NSApplicationActivatedEventType:
break;
case NSApplicationDeactivatedEventType:
break;
case NSWindowExposedEventType:
+ break;
case NSScreenChangedEventType:
break;
case NSWindowMovedEventType:
@@ -53,13 +54,12 @@ enum {
default:
break;
}
- break;
+ break; /* AppkitEvent. Return theEvent */
case NSKeyUp:
case NSKeyDown:
case NSFlagsChanged:
- flags = [theEvent modifierFlags];
processedEvent = [self tkProcessKeyEvent:theEvent];
- break;
+ break; /* Key event. Return the processed event. */
case NSLeftMouseDown:
case NSLeftMouseUp:
case NSRightMouseDown:
@@ -76,7 +76,7 @@ enum {
case NSTabletPoint:
case NSTabletProximity:
processedEvent = [self tkProcessMouseEvent:theEvent];
- break;
+ break; /* Mouse event. Return the processed event. */
#if 0
case NSSystemDefined:
subtype = [theEvent subtype];
@@ -100,7 +100,7 @@ enum {
#endif
default:
- break;
+ break; /* return theEvent */
}
return processedEvent;
}
@@ -113,14 +113,14 @@ enum {
*
* TkMacOSXFlushWindows --
*
- * This routine flushes all the windows of the application. It is
+ * This routine flushes all the visible windows of the application. It is
* called by XSync().
*
* Results:
* None.
*
* Side effects:
- * Flushes all Carbon windows
+ * Flushes all visible Cocoa windows
*
*----------------------------------------------------------------------
*/
@@ -128,22 +128,15 @@ enum {
MODULE_SCOPE void
TkMacOSXFlushWindows(void)
{
- NSInteger windowCount;
- NSInteger *windowNumbers;
+ NSArray *macWindows = [NSApp orderedWindows];
- NSCountWindows(&windowCount);
- if(windowCount) {
- windowNumbers = ckalloc(windowCount * sizeof(NSInteger));
- NSWindowList(windowCount, windowNumbers);
- for (NSInteger index = 0; index < windowCount; index++) {
- NSWindow *w = [NSApp windowWithWindowNumber:windowNumbers[index]];
- if (TkMacOSXGetXWindow(w)) {
- [w flushWindow];
- }
+ for (NSWindow *w in macWindows) {
+ if (TkMacOSXGetXWindow(w)) {
+ [w flushWindow];
}
- ckfree(windowNumbers);
}
}
+
/*
* Local Variables:
diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c
index d800ae5..c48e56e 100644
--- a/macosx/tkMacOSXFont.c
+++ b/macosx/tkMacOSXFont.c
@@ -15,6 +15,19 @@
#include "tkMacOSXPrivate.h"
#include "tkMacOSXFont.h"
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+#define defaultOrientation kCTFontDefaultOrientation
+#define verticalOrientation kCTFontVerticalOrientation
+#else
+#define defaultOrientation kCTFontOrientationDefault
+#define verticalOrientation kCTFontOrientationVertical
+#endif
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
+#define fixedPitch kCTFontUserFixedPitchFontType
+#else
+#define fixedPitch kCTFontUIFontUserFixedPitch
+#endif
+
/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_FONTS
@@ -197,6 +210,7 @@ FindNSFont(
nsFont = [fm convertFont:nsFont toSize:size];
nsFont = [fm convertFont:nsFont toHaveTrait:traits];
}
+ [nsFont retain];
#undef defaultFont
return nsFont;
}
@@ -270,7 +284,7 @@ InitFont(
fmPtr->fixed = [nsFont advancementForGlyph:glyphs[0]].width ==
[nsFont advancementForGlyph:glyphs[1]].width;
bounds = NSRectFromCGRect(CTFontGetBoundingRectsForGlyphs((CTFontRef)
- nsFont, kCTFontDefaultOrientation, ch, boundingRects, nCh));
+ nsFont, defaultOrientation, ch, boundingRects, nCh));
kern = [nsFont advancementForGlyph:glyphs[2]].width -
[fontPtr->nsFont advancementForGlyph:glyphs[2]].width;
}
@@ -293,7 +307,7 @@ InitFont(
[NSNumber numberWithInt:fmPtr->fixed ? 0 : 1],
NSLigatureAttributeName,
[NSNumber numberWithDouble:kern], NSKernAttributeName, nil];
- fontPtr->nsAttributes = TkMacOSXMakeUncollectableAndRetain(nsAttributes);
+ fontPtr->nsAttributes = [nsAttributes retain];
#undef nCh
}
@@ -358,6 +372,7 @@ TkpFontPkgInit(
NSFont *nsFont;
TkFontAttributes fa;
NSMutableCharacterSet *cs;
+ /* Since we called before TkpInit, we need our own autorelease pool. */
NSAutoreleasePool *pool = [NSAutoreleasePool new];
/* force this for now */
@@ -382,8 +397,7 @@ TkpFontPkgInit(
systemFont++;
}
TkInitFontAttributes(&fa);
- nsFont = (NSFont*) CTFontCreateUIFontForLanguage(
- kCTFontUserFixedPitchFontType, 11, NULL);
+ nsFont = (NSFont*) CTFontCreateUIFontForLanguage(fixedPitch, 11, NULL);
if (nsFont) {
GetTkFontAttributesForNSFont(nsFont, &fa);
CFRelease(nsFont);
@@ -518,7 +532,7 @@ TkpGetFontFromAttributes(
nsFont = FindNSFont(faPtr->family, traits, weight, points, 1);
}
if (!nsFont) {
- Tcl_Panic("Could not deternmine NSFont from TkFontAttributes");
+ Tcl_Panic("Could not determine NSFont from TkFontAttributes");
}
if (tkFontPtr == NULL) {
fontPtr = ckalloc(sizeof(MacFont));
@@ -557,7 +571,8 @@ TkpDeleteFont(
{
MacFont *fontPtr = (MacFont *) tkFontPtr;
- TkMacOSXMakeCollectableAndRelease(fontPtr->nsAttributes);
+ [fontPtr->nsAttributes release];
+ fontPtr->nsAttributes = NULL;
CFRelease(fontPtr->nsFont); /* Either a CTFontRef or a CFRetained NSFont */
}
@@ -662,7 +677,6 @@ TkpGetFontAttrsForChar(
{
MacFont *fontPtr = (MacFont *) tkfont;
NSFont *nsFont = fontPtr->nsFont;
-
*faPtr = fontPtr->font.fa;
if (nsFont && ![[nsFont coveredCharacterSet] characterIsMember:c]) {
UTF16Char ch = c;
diff --git a/macosx/tkMacOSXHLEvents.c b/macosx/tkMacOSXHLEvents.c
index ffbb06d..f5aeff0 100644
--- a/macosx/tkMacOSXHLEvents.c
+++ b/macosx/tkMacOSXHLEvents.c
@@ -7,12 +7,15 @@
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright (c) 2015 Marc Culler
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tkMacOSXPrivate.h"
+#include <sys/param.h>
+#define URL_MAX_LENGTH (17 + MAXPATHLEN)
/*
* This is a Tcl_Event structure that the Quit AppleEvent handler uses to
@@ -30,154 +33,32 @@ typedef struct KillEvent {
* Static functions used only in this file.
*/
-static OSErr QuitHandler(const AppleEvent *event,
- AppleEvent *reply, SRefCon handlerRefcon);
-static OSErr OappHandler(const AppleEvent *event,
- AppleEvent *reply, SRefCon handlerRefcon);
-static OSErr RappHandler(const AppleEvent *event,
- AppleEvent *reply, SRefCon handlerRefcon);
-static OSErr OdocHandler(const AppleEvent *event,
- AppleEvent *reply, SRefCon handlerRefcon);
-static OSErr PrintHandler(const AppleEvent *event,
- AppleEvent *reply, SRefCon handlerRefcon);
-static OSErr ScriptHandler(const AppleEvent *event,
- AppleEvent *reply, SRefCon handlerRefcon);
-static OSErr PrefsHandler(const AppleEvent *event,
- AppleEvent *reply, SRefCon handlerRefcon);
-static int MissedAnyParameters(const AppleEvent *theEvent);
-static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
-static OSStatus FSRefToDString(const FSRef *fsref, Tcl_DString *ds);
+static void tkMacOSXProcessFiles(NSAppleEventDescriptor* event,
+ NSAppleEventDescriptor* replyEvent,
+ Tcl_Interp *interp,
+ char* procedure);
+static int MissedAnyParameters(const AppleEvent *theEvent);
+static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
#pragma mark TKApplication(TKHLEvents)
@implementation TKApplication(TKHLEvents)
- (void) terminate: (id) sender
{
- QuitHandler(NULL, NULL, (SRefCon) _eventInterp);
+ [self handleQuitApplicationEvent:Nil withReplyEvent:Nil];
}
- (void) preferences: (id) sender
{
- PrefsHandler(NULL, NULL, (SRefCon) _eventInterp);
+ [self handleShowPreferencesEvent:Nil withReplyEvent:Nil];
}
-@end
-
-#pragma mark -
-
-/*
- *----------------------------------------------------------------------
- *
- * TkMacOSXInitAppleEvents --
- *
- * Initilize the Apple Events on the Macintosh. This registers the core
- * event handlers.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkMacOSXInitAppleEvents(
- Tcl_Interp *interp) /* Interp to handle basic events. */
-{
- AEEventHandlerUPP OappHandlerUPP, RappHandlerUPP, OdocHandlerUPP;
- AEEventHandlerUPP PrintHandlerUPP, QuitHandlerUPP, ScriptHandlerUPP;
- AEEventHandlerUPP PrefsHandlerUPP;
- static Boolean initialized = FALSE;
-
- if (!initialized) {
- initialized = TRUE;
-
- /*
- * Install event handlers for the core apple events.
- */
-
- QuitHandlerUPP = NewAEEventHandlerUPP(QuitHandler);
- ChkErr(AEInstallEventHandler, kCoreEventClass, kAEQuitApplication,
- QuitHandlerUPP, (SRefCon) interp, false);
-
- OappHandlerUPP = NewAEEventHandlerUPP(OappHandler);
- ChkErr(AEInstallEventHandler, kCoreEventClass, kAEOpenApplication,
- OappHandlerUPP, (SRefCon) interp, false);
-
- RappHandlerUPP = NewAEEventHandlerUPP(RappHandler);
- ChkErr(AEInstallEventHandler, kCoreEventClass, kAEReopenApplication,
- RappHandlerUPP, (SRefCon) interp, false);
-
- OdocHandlerUPP = NewAEEventHandlerUPP(OdocHandler);
- ChkErr(AEInstallEventHandler, kCoreEventClass, kAEOpenDocuments,
- OdocHandlerUPP, (SRefCon) interp, false);
-
- PrintHandlerUPP = NewAEEventHandlerUPP(PrintHandler);
- ChkErr(AEInstallEventHandler, kCoreEventClass, kAEPrintDocuments,
- PrintHandlerUPP, (SRefCon) interp, false);
-
- PrefsHandlerUPP = NewAEEventHandlerUPP(PrefsHandler);
- ChkErr(AEInstallEventHandler, kCoreEventClass, kAEShowPreferences,
- PrefsHandlerUPP, (SRefCon) interp, false);
-
- if (interp) {
- ScriptHandlerUPP = NewAEEventHandlerUPP(ScriptHandler);
- ChkErr(AEInstallEventHandler, kAEMiscStandards, kAEDoScript,
- ScriptHandlerUPP, (SRefCon) interp, false);
- }
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkMacOSXDoHLEvent --
- *
- * Dispatch incomming highlevel events.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Depends on the incoming event.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkMacOSXDoHLEvent(
- void *theEvent)
-{
- return AEProcessAppleEvent((EventRecord *)theEvent);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * QuitHandler --
- *
- * This is the 'quit' core Apple event handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static OSErr
-QuitHandler(
- const AppleEvent *event,
- AppleEvent *reply,
- SRefCon handlerRefcon)
+- (void) handleQuitApplicationEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
- Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
KillEvent *eventPtr;
- if (interp) {
+ if (_eventInterp) {
/*
* Call the exit command from the event loop, since you are not
* supposed to call ExitToShell in an Apple Event Handler. We put this
@@ -188,287 +69,290 @@ QuitHandler(
eventPtr = ckalloc(sizeof(KillEvent));
eventPtr->header.proc = ReallyKillMe;
- eventPtr->interp = interp;
+ eventPtr->interp = _eventInterp;
Tcl_QueueEvent((Tcl_Event *) eventPtr, TCL_QUEUE_HEAD);
}
- return noErr;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * OappHandler --
- *
- * This is the 'oapp' core Apple event handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static OSErr
-OappHandler(
- const AppleEvent *event,
- AppleEvent *reply,
- SRefCon handlerRefcon)
+- (void) handleOpenApplicationEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
- Tcl_CmdInfo dummy;
- Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
+ Tcl_Interp *interp = _eventInterp;
if (interp &&
- Tcl_GetCommandInfo(interp, "::tk::mac::OpenApplication", &dummy)){
- int code = Tcl_EvalEx(interp, "::tk::mac::OpenApplication", -1, TCL_EVAL_GLOBAL);
+ Tcl_FindCommand(_eventInterp, "::tk::mac::OpenApplication", NULL, 0)){
+ int code = Tcl_EvalEx(_eventInterp, "::tk::mac::OpenApplication",
+ -1, TCL_EVAL_GLOBAL);
if (code != TCL_OK) {
- Tcl_BackgroundException(interp, code);
+ Tcl_BackgroundException(_eventInterp, code);
}
}
- return noErr;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * RappHandler --
- *
- * This is the 'rapp' core Apple event handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static OSErr
-RappHandler(
- const AppleEvent *event,
- AppleEvent *reply,
- SRefCon handlerRefcon)
+- (void) handleReopenApplicationEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
- Tcl_CmdInfo dummy;
- Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
ProcessSerialNumber thePSN = {0, kCurrentProcess};
- OSStatus err = ChkErr(SetFrontProcess, &thePSN);
-
- if (interp && Tcl_GetCommandInfo(interp,
- "::tk::mac::ReopenApplication", &dummy)) {
- int code = Tcl_EvalEx(interp, "::tk::mac::ReopenApplication", -1, TCL_EVAL_GLOBAL);
+ SetFrontProcess(&thePSN);
+#else
+ [[NSApplication sharedApplication] activateIgnoringOtherApps: YES];
+#endif
+ if (_eventInterp && Tcl_FindCommand(_eventInterp,
+ "::tk::mac::ReopenApplication", NULL, 0)) {
+ int code = Tcl_EvalEx(_eventInterp, "::tk::mac::ReopenApplication",
+ -1, TCL_EVAL_GLOBAL);
if (code != TCL_OK){
- Tcl_BackgroundException(interp, code);
+ Tcl_BackgroundException(_eventInterp, code);
}
}
- return err;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * PrefsHandler --
- *
- * This is the 'pref' core Apple event handler. Called when the user
- * selects 'Preferences...' in MacOS X
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static OSErr
-PrefsHandler(
- const AppleEvent *event,
- AppleEvent *reply,
- SRefCon handlerRefcon)
+- (void) handleShowPreferencesEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
- Tcl_CmdInfo dummy;
- Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
-
- if (interp &&
- Tcl_GetCommandInfo(interp, "::tk::mac::ShowPreferences", &dummy)){
- int code = Tcl_EvalEx(interp, "::tk::mac::ShowPreferences", -1, TCL_EVAL_GLOBAL);
+ if (_eventInterp &&
+ Tcl_FindCommand(_eventInterp, "::tk::mac::ShowPreferences", NULL, 0)){
+ int code = Tcl_EvalEx(_eventInterp, "::tk::mac::ShowPreferences",
+ -1, TCL_EVAL_GLOBAL);
if (code != TCL_OK) {
- Tcl_BackgroundException(interp, code);
+ Tcl_BackgroundException(_eventInterp, code);
}
}
- return noErr;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * OdocHandler --
- *
- * This is the 'odoc' core Apple event handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static OSErr
-OdocHandler(
- const AppleEvent *event,
- AppleEvent *reply,
- SRefCon handlerRefcon)
+- (void) handleOpenDocumentsEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
- Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
- AEDescList fileSpecList;
- FSRef file;
- DescType type;
- Size actual;
- long count, index;
- AEKeyword keyword;
- Tcl_DString command, pathName;
- Tcl_CmdInfo dummy;
- int code;
+ tkMacOSXProcessFiles(event, replyEvent, _eventInterp, "::tk::mac::OpenDocument");
+}
- /*
- * Don't bother if we don't have an interp or the open document procedure
- * doesn't exist.
- */
+- (void) handlePrintDocumentsEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent
+{
+ tkMacOSXProcessFiles(event, replyEvent, _eventInterp, "::tk::mac::PrintDocument");
+}
- if (!interp ||
- !Tcl_GetCommandInfo(interp, "::tk::mac::OpenDocument", &dummy)) {
- return noErr;
- }
+- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent
+{
+ OSStatus err;
+ const AEDesc *theDesc = nil;
+ DescType type = 0, initialType = 0;
+ Size actual;
+ int tclErr = -1;
+ char URLBuffer[1 + URL_MAX_LENGTH];
+ char errString[128];
+ char typeString[5];
/*
- * If we get any errors while retrieving our parameters we just return with
- * no error.
+ * The DoScript event receives one parameter that should be text data or a
+ * fileURL.
*/
- if (ChkErr(AEGetParamDesc, event, keyDirectObject, typeAEList,
- &fileSpecList) != noErr) {
- return noErr;
+ theDesc = [event aeDesc];
+ if (theDesc == nil) {
+ return;
}
- if (MissedAnyParameters(event) != noErr) {
- return noErr;
- }
- if (ChkErr(AECountItems, &fileSpecList, &count) != noErr) {
- return noErr;
+
+ err = AEGetParamPtr(theDesc, keyDirectObject, typeWildCard, &initialType,
+ NULL, 0, NULL);
+ if (err != noErr) {
+ sprintf(errString, "AEDoScriptHandler: GetParamDesc error %d", (int)err);
+ AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
+ errString, strlen(errString));
+ return;
}
- /*
- * Convert our parameters into a script to evaluate, skipping things that
- * we can't handle right.
- */
+ if (MissedAnyParameters((AppleEvent*)theDesc)) {
+ sprintf(errString, "AEDoScriptHandler: extra parameters");
+ AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
+ errString, strlen(errString));
+ return;
+ }
- Tcl_DStringInit(&command);
- Tcl_DStringAppend(&command, "::tk::mac::OpenDocument", -1);
- for (index = 1; index <= count; index++) {
- if (ChkErr(AEGetNthPtr, &fileSpecList, index, typeFSRef, &keyword,
- &type, (Ptr) &file, sizeof(FSRef), &actual) != noErr) {
- continue;
+ if (initialType == typeFileURL || initialType == typeAlias) {
+ /*
+ * The descriptor can be coerced to a file url. Source the file, or
+ * pass the path as a string argument to ::tk::mac::DoScriptFile if
+ * that procedure exists.
+ */
+ err = AEGetParamPtr(theDesc, keyDirectObject, typeFileURL, &type,
+ (Ptr) URLBuffer, URL_MAX_LENGTH, &actual);
+ if (err == noErr && actual > 0){
+ URLBuffer[actual] = '\0';
+ NSString *urlString = [NSString stringWithUTF8String:(char*)URLBuffer];
+ NSURL *fileURL = [NSURL URLWithString:urlString];
+ Tcl_DString command;
+ Tcl_DStringInit(&command);
+ if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptFile", NULL, 0)){
+ Tcl_DStringAppend(&command, "::tk::mac::DoScriptFile", -1);
+ } else {
+ Tcl_DStringAppend(&command, "source", -1);
+ }
+ Tcl_DStringAppendElement(&command, [[fileURL path] UTF8String]);
+ tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command),
+ Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
}
-
- if (ChkErr(FSRefToDString, &file, &pathName) == noErr) {
- Tcl_DStringAppendElement(&command, Tcl_DStringValue(&pathName));
- Tcl_DStringFree(&pathName);
+ } else if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
+ NULL, 0, &actual)) {
+ if (actual > 0) {
+ /*
+ * The descriptor can be coerced to UTF8 text. Evaluate as Tcl, or
+ * or pass the text as a string argument to ::tk::mac::DoScriptText
+ * if that procedure exists.
+ */
+ char *data = ckalloc(actual + 1);
+ if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
+ data, actual, NULL)) {
+ if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptText", NULL, 0)){
+ Tcl_DString command;
+ Tcl_DStringInit(&command);
+ Tcl_DStringAppend(&command, "::tk::mac::DoScriptText", -1);
+ Tcl_DStringAppendElement(&command, data);
+ tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command),
+ Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
+ } else {
+ tclErr = Tcl_EvalEx(_eventInterp, data, actual, TCL_EVAL_GLOBAL);
+ }
+ }
+ ckfree(data);
+ }
+ } else {
+ /*
+ * The descriptor can not be coerced to a fileURL or UTF8 text.
+ */
+ for (int i = 0; i < 4; i++) {
+ typeString[i] = ((char*)&initialType)[3-i];
}
+ typeString[4] = '\0';
+ sprintf(errString, "AEDoScriptHandler: invalid script type '%s', "
+ "must be coercable to 'furl' or 'utf8'", typeString);
+ AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar, errString,
+ strlen(errString));
}
-
/*
- * Now handle the event by evaluating a script.
+ * If we ran some Tcl code, put the result in the reply.
*/
-
- code = Tcl_EvalEx(interp, Tcl_DStringValue(&command),
- Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
- if (code != TCL_OK) {
- Tcl_BackgroundException(interp, code);
+ if (tclErr >= 0) {
+ int reslen;
+ const char *result =
+ Tcl_GetStringFromObj(Tcl_GetObjResult(_eventInterp), &reslen);
+ if (tclErr == TCL_OK) {
+ AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyDirectObject, typeChar,
+ result, reslen);
+ } else {
+ AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
+ result, reslen);
+ AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorNumber, typeSInt32,
+ (Ptr) &tclErr,sizeof(int));
+ }
}
- Tcl_DStringFree(&command);
- return noErr;
+ return;
}
-
+@end
+
+#pragma mark -
+
/*
*----------------------------------------------------------------------
*
- * PrintHandler --
+ * TkMacOSXProcessFiles --
*
- * This is the 'pdoc' core Apple event handler.
+ * Extract a list of fileURLs from an AppleEvent and call the specified
+ * procedure with the file paths as arguments.
*
* Results:
* None.
*
* Side effects:
- * None.
+ * The event is handled by running the procedure.
*
*----------------------------------------------------------------------
*/
-static OSErr
-PrintHandler(
- const AppleEvent * event,
- AppleEvent * reply,
- SRefCon handlerRefcon)
+static void
+tkMacOSXProcessFiles(
+ NSAppleEventDescriptor* event,
+ NSAppleEventDescriptor* replyEvent,
+ Tcl_Interp *interp,
+ char* procedure)
{
- Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
- AEDescList fileSpecList;
- FSRef file;
+ Tcl_Encoding utf8 = Tcl_GetEncoding(NULL, "utf-8");
+ const AEDesc *fileSpecDesc = nil;
+ AEDesc contents;
+ char URLString[1 + URL_MAX_LENGTH];
+ NSURL *fileURL;
DescType type;
Size actual;
long count, index;
AEKeyword keyword;
Tcl_DString command, pathName;
- Tcl_CmdInfo dummy;
int code;
/*
- * Don't bother if we don't have an interp or the print document procedure
- * doesn't exist.
+ * Do nothing if we don't have an interpreter or the procedure doesn't exist.
*/
- if (!interp ||
- !Tcl_GetCommandInfo(interp, "::tk::mac::PrintDocument", &dummy)) {
- return noErr;
+ if (!interp || !Tcl_FindCommand(interp, procedure, NULL, 0)) {
+ return;
+ }
+
+ fileSpecDesc = [event aeDesc];
+ if (fileSpecDesc == nil ) {
+ return;
}
/*
- * If we get any errors while retrieving our parameters we just return with
- * no error.
+ * The AppleEvent's descriptor should either contain a value of
+ * typeObjectSpecifier or typeAEList. In the first case, the descriptor
+ * can be treated as a list of size 1 containing a value which can be
+ * coerced into a fileURL. In the second case we want to work with the list
+ * itself. Values in the list will be coerced into fileURL's if possible;
+ * otherwise they will be ignored.
*/
- if (ChkErr(AEGetParamDesc, event, keyDirectObject, typeAEList,
- &fileSpecList) != noErr) {
- return noErr;
- }
- if (ChkErr(MissedAnyParameters, event) != noErr) {
- return noErr;
+ /* Get a copy of the AppleEvent's descriptor. */
+ AEGetParamDesc(fileSpecDesc, keyDirectObject, typeWildCard, &contents);
+ if (contents.descriptorType == typeAEList) {
+ fileSpecDesc = &contents;
}
- if (ChkErr(AECountItems, &fileSpecList, &count) != noErr) {
- return noErr;
+
+ if (AECountItems(fileSpecDesc, &count) != noErr) {
+ AEDisposeDesc(&contents);
+ return;
}
+ /*
+ * Construct a Tcl command which calls the procedure, passing the
+ * paths contained in the AppleEvent as arguments.
+ */
+
Tcl_DStringInit(&command);
- Tcl_DStringAppend(&command, "::tk::mac::PrintDocument", -1);
+ Tcl_DStringAppend(&command, procedure, -1);
+
for (index = 1; index <= count; index++) {
- if (ChkErr(AEGetNthPtr, &fileSpecList, index, typeFSRef, &keyword,
- &type, (Ptr) &file, sizeof(FSRef), &actual) != noErr) {
+ if (noErr != AEGetNthPtr(fileSpecDesc, index, typeFileURL, &keyword,
+ &type, (Ptr) URLString, URL_MAX_LENGTH, &actual)) {
continue;
}
-
- if (ChkErr(FSRefToDString, &file, &pathName) == noErr) {
- Tcl_DStringAppendElement(&command, Tcl_DStringValue(&pathName));
- Tcl_DStringFree(&pathName);
+ if (type != typeFileURL) {
+ continue;
+ }
+ URLString[actual] = '\0';
+ fileURL = [NSURL URLWithString:[NSString stringWithUTF8String:(char*)URLString]];
+ if (fileURL == nil) {
+ continue;
}
+ Tcl_ExternalToUtfDString(utf8, [[fileURL path] UTF8String], -1, &pathName);
+ Tcl_DStringAppendElement(&command, Tcl_DStringValue(&pathName));
+ Tcl_DStringFree(&pathName);
}
+ AEDisposeDesc(&contents);
/*
- * Now handle the event by evaluating a script.
+ * Handle the event by evaluating the Tcl expression we constructed.
*/
code = Tcl_EvalEx(interp, Tcl_DStringValue(&command),
@@ -477,18 +361,19 @@ PrintHandler(
Tcl_BackgroundException(interp, code);
}
Tcl_DStringFree(&command);
- return noErr;
+ return;
}
/*
*----------------------------------------------------------------------
*
- * ScriptHandler --
+ * TkMacOSXInitAppleEvents --
*
- * This handler process the script event.
+ * Register AppleEvent handlers with the NSAppleEventManager for
+ * this NSApplication.
*
* Results:
- * Schedules the given event to be processed.
+ * None.
*
* Side effects:
* None.
@@ -496,108 +381,91 @@ PrintHandler(
*----------------------------------------------------------------------
*/
-static OSErr
-ScriptHandler(
- const AppleEvent *event,
- AppleEvent *reply,
- SRefCon handlerRefcon)
+void
+TkMacOSXInitAppleEvents(
+ Tcl_Interp *interp) /* not used */
{
- OSStatus theErr;
- AEDescList theDesc;
- Size size;
- int tclErr = -1;
- Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
- char errString[128];
+ NSAppleEventManager *aeManager = [NSAppleEventManager sharedAppleEventManager];
+ static Boolean initialized = FALSE;
- /*
- * The do script event receives one parameter that should be data or a
- * file.
- */
+ if (!initialized) {
+ initialized = TRUE;
- theErr = AEGetParamDesc(event, keyDirectObject, typeWildCard,
- &theDesc);
- if (theErr != noErr) {
- sprintf(errString, "AEDoScriptHandler: GetParamDesc error %d",
- (int)theErr);
- theErr = AEPutParamPtr(reply, keyErrorString, typeChar, errString,
- strlen(errString));
- } else if (MissedAnyParameters(event)) {
- /*
- * Return error if parameter is missing.
- */
+ [aeManager setEventHandler:NSApp
+ andSelector:@selector(handleQuitApplicationEvent:withReplyEvent:)
+ forEventClass:kCoreEventClass andEventID:kAEQuitApplication];
- sprintf(errString, "AEDoScriptHandler: extra parameters");
- AEPutParamPtr(reply, keyErrorString, typeChar, errString,
- strlen(errString));
- theErr = -1771;
- } else if (theDesc.descriptorType == (DescType) typeAlias &&
- AEGetParamPtr(event, keyDirectObject, typeFSRef, NULL, NULL,
- 0, &size) == noErr && size == sizeof(FSRef)) {
- /*
- * We've had a file sent to us. Source it.
- */
+ [aeManager setEventHandler:NSApp
+ andSelector:@selector(handleOpenApplicationEvent:withReplyEvent:)
+ forEventClass:kCoreEventClass andEventID:kAEOpenApplication];
- FSRef file;
- theErr = AEGetParamPtr(event, keyDirectObject, typeFSRef, NULL, &file,
- size, NULL);
- if (theErr == noErr) {
- Tcl_DString scriptName;
+ [aeManager setEventHandler:NSApp
+ andSelector:@selector(handleReopenApplicationEvent:withReplyEvent:)
+ forEventClass:kCoreEventClass andEventID:kAEReopenApplication];
- theErr = FSRefToDString(&file, &scriptName);
- if (theErr == noErr) {
- tclErr = Tcl_FSEvalFileEx(interp, Tcl_DStringValue(&scriptName), NULL);
- Tcl_DStringFree(&scriptName);
- } else {
- sprintf(errString, "AEDoScriptHandler: file not found");
- AEPutParamPtr(reply, keyErrorString, typeChar, errString,
- strlen(errString));
- }
- }
- } else if (AEGetParamPtr(event, keyDirectObject, typeUTF8Text, NULL, NULL,
- 0, &size) == noErr && size) {
- /*
- * We've had some data sent to us. Evaluate it.
- */
+ [aeManager setEventHandler:NSApp
+ andSelector:@selector(handleShowPreferencesEvent:withReplyEvent:)
+ forEventClass:kCoreEventClass andEventID:kAEShowPreferences];
- char *data = ckalloc(size + 1);
- theErr = AEGetParamPtr(event, keyDirectObject, typeUTF8Text, NULL, data,
- size, NULL);
- if (theErr == noErr) {
- tclErr = Tcl_EvalEx(interp, data, size, TCL_EVAL_GLOBAL);
- }
- } else {
- /*
- * Umm, don't recognize what we've got...
- */
+ [aeManager setEventHandler:NSApp
+ andSelector:@selector(handleOpenDocumentsEvent:withReplyEvent:)
+ forEventClass:kCoreEventClass andEventID:kAEOpenDocuments];
+
+ [aeManager setEventHandler:NSApp
+ andSelector:@selector(handleOpenDocumentsEvent:withReplyEvent:)
+ forEventClass:kCoreEventClass andEventID:kAEPrintDocuments];
- sprintf(errString, "AEDoScriptHandler: invalid script type '%-4.4s', "
- "must be 'alis' or coercable to 'utf8'",
- (char*) &theDesc.descriptorType);
- AEPutParamPtr(reply, keyErrorString, typeChar, errString,
- strlen(errString));
- theErr = -1770;
+ [aeManager setEventHandler:NSApp
+ andSelector:@selector(handleDoScriptEvent:withReplyEvent:)
+ forEventClass:kAEMiscStandards andEventID:kAEDoScript];
}
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXDoHLEvent --
+ *
+ * Dispatch an AppleEvent.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Depend on the AppleEvent.
+ *
+ *----------------------------------------------------------------------
+ */
- /*
- * If we actually go to run Tcl code - put the result in the reply.
+int
+TkMacOSXDoHLEvent(
+ void *theEvent)
+{
+ /* According to the NSAppleEventManager reference:
+ * "The theReply parameter always specifies a reply Apple event, never
+ * nil. However, the handler should not fill out the reply if the
+ * descriptor type for the reply event is typeNull, indicating the sender
+ * does not want a reply."
+ * The specified way to build such a non-nil descriptor is used here. But
+ * on OSX 10.11, the compiler nonetheless generates a warning. I am
+ * supressing the warning here -- maybe the warnings will stop in a future
+ * compiler release.
*/
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
+#endif
- if (tclErr >= 0) {
- int reslen;
- const char *result =
- Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &reslen);
+ NSAppleEventDescriptor* theReply = [NSAppleEventDescriptor nullDescriptor];
+ NSAppleEventManager *aeManager = [NSAppleEventManager sharedAppleEventManager];
- if (tclErr == TCL_OK) {
- AEPutParamPtr(reply, keyDirectObject, typeChar, result, reslen);
- } else {
- AEPutParamPtr(reply, keyErrorString, typeChar, result, reslen);
- AEPutParamPtr(reply, keyErrorNumber, typeSInt32, (Ptr) &tclErr,
- sizeof(int));
- }
- }
+ return [aeManager dispatchRawAppleEvent:(const AppleEvent*)theEvent
+ withRawReply: (AppleEvent *)theReply
+ handlerRefCon: (SRefCon)0];
- AEDisposeDesc(&theDesc);
- return theErr;
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
}
/*
@@ -605,8 +473,8 @@ ScriptHandler(
*
* ReallyKillMe --
*
- * This proc tries to kill the shell by running exit, called from an
- * event scheduled by the "Quit" AppleEvent handler.
+ * This procedure tries to kill the shell by running exit, called from
+ * an event scheduled by the "Quit" AppleEvent handler.
*
* Results:
* Runs the "exit" command which might kill the shell.
@@ -623,8 +491,7 @@ ReallyKillMe(
int flags)
{
Tcl_Interp *interp = ((KillEvent *) eventPtr)->interp;
- Tcl_CmdInfo dummy;
- int quit = Tcl_GetCommandInfo(interp, "::tk::mac::Quit", &dummy);
+ int quit = Tcl_FindCommand(interp, "::tk::mac::Quit", NULL, 0)!=NULL;
int code = Tcl_EvalEx(interp, quit ? "::tk::mac::Quit" : "exit", -1, TCL_EVAL_GLOBAL);
if (code != TCL_OK) {
@@ -667,37 +534,7 @@ MissedAnyParameters(
return (err != errAEDescNotFound);
}
-/*
- *----------------------------------------------------------------------
- *
- * FSRefToDString --
- *
- * Get a POSIX path from an FSRef.
- *
- * Results:
- * In the parameter ds.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static OSStatus
-FSRefToDString(
- const FSRef *fsref,
- Tcl_DString *ds)
-{
- UInt8 fileName[PATH_MAX+1];
- OSStatus err;
- err = ChkErr(FSRefMakePath, fsref, fileName, sizeof(fileName));
- if (err == noErr) {
- Tcl_ExternalToUtfDString(NULL, (char*) fileName, -1, ds);
- }
- return err;
-}
-
/*
* Local Variables:
* mode: objc
diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c
index 1f70149..b965a38 100644
--- a/macosx/tkMacOSXInit.c
+++ b/macosx/tkMacOSXInit.c
@@ -28,7 +28,6 @@ static char tkLibPath[PATH_MAX + 1] = "";
static char scriptPath[PATH_MAX + 1] = "";
-int tkMacOSXGCEnabled = 0;
long tkMacOSXMacOSXVersion = 0;
#pragma mark TKApplication(TKInit)
@@ -53,18 +52,24 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
- (void) _setupWindowNotifications;
@end
-@interface TKApplication(TKScrlbr)
-- (void) _setupScrollBarNotifications;
-@end
-
@interface TKApplication(TKMenus)
- (void) _setupMenus;
@end
@implementation TKApplication
+#ifndef __clang__
+@synthesize poolProtected = _poolProtected;
+#endif
@end
@implementation TKApplication(TKInit)
+- (void) _resetAutoreleasePool
+{
+ if(![self poolProtected]) {
+ [_mainPool drain];
+ _mainPool = [NSAutoreleasePool new];
+ }
+}
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
- (void) _postedNotification: (NSNotification *) notification
{
@@ -91,17 +96,17 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
- (void) _setupEventLoop
{
- _running = 1;
- if (!_appFlags._hasBeenRun) {
- _appFlags._hasBeenRun = YES;
- [self finishLaunching];
- }
+ 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];
@@ -110,14 +115,13 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
selector:@selector(_postedNotification:) name:nil object:nil];
#endif
[self _setupWindowNotifications];
- [self _setupScrollBarNotifications];
[self _setupApplicationNotifications];
}
- (NSString *) tkFrameworkImagePath: (NSString *) image
{
NSString *path = nil;
-
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
if (tkLibPath[0] != '\0') {
path = [[NSBundle bundleWithPath:[[NSString stringWithUTF8String:
tkLibPath] stringByAppendingString:@"/../.."]]
@@ -150,6 +154,8 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
}
}
#endif
+ [path retain];
+ [pool drain];
return path;
}
@end
@@ -176,6 +182,7 @@ static void
SetApplicationIcon(
ClientData clientData)
{
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSString *path = [NSApp tkFrameworkImagePath:@"Tk.icns"];
if (path) {
NSImage *image = [[NSImage alloc] initWithContentsOfFile:path];
@@ -184,6 +191,7 @@ SetApplicationIcon(
[image release];
}
}
+ [pool drain];
}
/*
@@ -236,12 +244,17 @@ TkpInit(
if (!uname(&name)) {
tkMacOSXMacOSXVersion = (strtod(name.release, NULL) + 96) * 10;
}
- if (tkMacOSXMacOSXVersion &&
+ /*Check for new versioning scheme on Yosemite (10.10) and later.*/
+ if (MAC_OS_X_VERSION_MIN_REQUIRED > 100000) {
+ tkMacOSXMacOSXVersion = MAC_OS_X_VERSION_MIN_REQUIRED/100;
+ }
+ if (tkMacOSXMacOSXVersion && MAC_OS_X_VERSION_MIN_REQUIRED < 100000 &&
tkMacOSXMacOSXVersion/10 < MAC_OS_X_VERSION_MIN_REQUIRED/10) {
Tcl_Panic("Mac OS X 10.%d or later required !",
(MAC_OS_X_VERSION_MIN_REQUIRED/10)-100);
}
+
#ifdef TK_FRAMEWORK
/*
* When Tk is in a framework, force tcl_findLibrary to look in the
@@ -256,20 +269,19 @@ TkpInit(
}
#endif
- static NSAutoreleasePool *pool = nil;
- if (!pool) {
- pool = [NSAutoreleasePool new];
+ {
+ 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];
}
- tkMacOSXGCEnabled = ([NSGarbageCollector defaultCollector] != nil);
- [[NSUserDefaults standardUserDefaults] registerDefaults:
- [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithBool:YES],
- @"_NSCanWrapButtonTitles",
- [NSNumber numberWithInt:-1],
- @"NSStringDrawingTypesetterBehavior",
- nil]];
- [TKApplication sharedApplication];
- [NSApp _setup:interp];
/* Check whether we are a bundled executable: */
bundleRef = CFBundleGetMainBundle();
@@ -326,12 +338,14 @@ TkpInit(
Tcl_DoWhenIdle(SetApplicationIcon, NULL);
}
- [NSApp _setupEventLoop];
- TkMacOSXInitAppleEvents(interp);
- TkMacOSXUseAntialiasedText(interp, -1);
- TkMacOSXInitCGDrawing(interp, TRUE, 0);
- [pool drain];
- pool = [NSAutoreleasePool new];
+ {
+ 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
@@ -488,9 +502,8 @@ TkpDisplayWarning(
MODULE_SCOPE void
TkMacOSXDefaultStartupScript(void)
{
- CFBundleRef bundleRef;
-
- bundleRef = CFBundleGetMainBundle();
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ CFBundleRef bundleRef = CFBundleGetMainBundle();
if (bundleRef != NULL) {
CFURLRef appMainURL = CFBundleCopyResourceURL(bundleRef,
@@ -514,6 +527,7 @@ TkMacOSXDefaultStartupScript(void)
CFRelease(appMainURL);
}
}
+ [pool drain];
}
/*
diff --git a/macosx/tkMacOSXInt.h b/macosx/tkMacOSXInt.h
index 813acce..6971e26 100644
--- a/macosx/tkMacOSXInt.h
+++ b/macosx/tkMacOSXInt.h
@@ -24,6 +24,7 @@
#ifndef _TKMAC
#include "tkMacOSX.h"
+#import <Cocoa/Cocoa.h>
#endif
/*
@@ -85,7 +86,7 @@ typedef struct TkWindowPrivate MacDrawable;
#define TK_FOCUSED_VIEW 0x10
#define TK_IS_PIXMAP 0x20
#define TK_IS_BW_PIXMAP 0x40
-
+#define TK_DO_NOT_DRAW 0x80
/*
* 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
@@ -196,7 +197,7 @@ MODULE_SCOPE void TkpClipDrawableToRect(Display *display, Drawable d, int x,
int y, int width, int height);
MODULE_SCOPE void TkpRetainRegion(TkRegion r);
MODULE_SCOPE void TkpReleaseRegion(TkRegion r);
-
+MODULE_SCOPE void TkpShiftButton(NSButton *button, NSPoint delta);
/*
* Include the stubbed internal platform-specific API.
*/
diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c
index 1d24960..151b4f2 100644
--- a/macosx/tkMacOSXKeyEvent.c
+++ b/macosx/tkMacOSXKeyEvent.c
@@ -7,6 +7,7 @@
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
* Copyright (c) 2012 Adrian Robert.
+ * Copyright 2015 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -27,7 +28,9 @@ static Tk_Window grabWinPtr = NULL;
/* Current grab window, NULL if no grab. */
static Tk_Window keyboardGrabWinPtr = NULL;
/* Current keyboard grab window. */
-static NSModalSession modalSession = NULL;
+static NSWindow *keyboardGrabNSWindow = nil;
+ /* NSWindow for the current keyboard grab window. */
+static NSModalSession modalSession = nil;
static BOOL processingCompose = NO;
static BOOL finishedCompose = NO;
@@ -78,16 +81,18 @@ static unsigned isFunctionKey(unsigned int code);
case NSFlagsChanged:
modifiers = [theEvent modifierFlags];
keyCode = [theEvent keyCode];
- w = [self windowWithWindowNumber:[theEvent windowNumber]];
+ // w = [self windowWithWindowNumber:[theEvent windowNumber]];
+ w = [theEvent window];
#if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1
NSLog(@"-[%@(%p) %s] r=%d mods=%u '%@' '%@' code=%u c=%d %@ %d", [self class], self, _cmd, repeat, modifiers, characters, charactersIgnoringModifiers, keyCode,([charactersIgnoringModifiers length] == 0) ? 0 : [charactersIgnoringModifiers characterAtIndex: 0], w, type);
#endif
break;
default:
- return theEvent;
+ return theEvent; /* Unrecognized key event. */
}
+ /* Create an Xevent to add to the Tk queue. */
if (!processingCompose) {
unsigned int state = 0;
@@ -128,7 +133,7 @@ static unsigned isFunctionKey(unsigned int code);
tkwin = (Tk_Window) winPtr->dispPtr->focusPtr;
if (!tkwin) {
TkMacOSXDbgMsg("tkwin == NULL");
- return theEvent;
+ return theEvent; /* Give up. No window for this event. */
}
/*
@@ -222,7 +227,7 @@ static unsigned isFunctionKey(unsigned int code);
-@implementation TKContentView(TKKeyEvent)
+@implementation TKContentView
/* <NSTextInput> implementation (called through interpretKeyEvents:]). */
/* <NSTextInput>: called when done composing;
@@ -241,7 +246,7 @@ static unsigned isFunctionKey(unsigned int code);
finishedCompose = YES;
/* first, clear any working text */
- if (_workingText != nil)
+ if (privateWorkingText != nil)
[self deleteWorkingText];
/* now insert the string as keystrokes */
@@ -272,46 +277,32 @@ static unsigned isFunctionKey(unsigned int code);
NSString *str = [aString respondsToSelector: @selector (string)] ?
[aString string] : aString;
if (NS_KEYLOG)
- NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
- selRange.length, selRange.location);
+ NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu", str,
+ (unsigned long) [str length], (unsigned long) selRange.length,
+ (unsigned long) selRange.location);
- if (_workingText != nil)
+ if (privateWorkingText != nil)
[self deleteWorkingText];
if ([str length] == 0)
return;
processingCompose = YES;
- _workingText = [str copy];
+ privateWorkingText = [str copy];
//PENDING: insert workingText underlined
}
-/* delete display of composing characters [not in <NSTextInput>] */
-- (void)deleteWorkingText
-{
- if (_workingText == nil)
- return;
- if (NS_KEYLOG)
- NSLog(@"deleteWorkingText len = %d\n", [_workingText length]);
- [_workingText release];
- _workingText = nil;
- processingCompose = NO;
-
- //PENDING: delete working text
-}
-
-
- (BOOL)hasMarkedText
{
- return _workingText != nil;
+ return privateWorkingText != nil;
}
- (NSRange)markedRange
{
- NSRange rng = _workingText != nil
- ? NSMakeRange (0, [_workingText length]) : NSMakeRange (NSNotFound, 0);
+ NSRange rng = privateWorkingText != nil
+ ? NSMakeRange (0, [privateWorkingText length]) : NSMakeRange (NSNotFound, 0);
if (NS_KEYLOG)
NSLog (@"markedRange request");
return rng;
@@ -337,7 +328,7 @@ static unsigned isFunctionKey(unsigned int code);
pt.y = caret_y;
pt = [self convertPoint: pt toView: nil];
- pt = [[self window] convertBaseToScreen: pt];
+ pt = [[self window] convertPointToScreen: pt];
pt.y -= caret_height;
rect.origin = pt;
@@ -411,6 +402,24 @@ static unsigned isFunctionKey(unsigned int code);
@end
+@implementation TKContentView(TKKeyEvent)
+/* delete display of composing characters [not in <NSTextInput>] */
+- (void)deleteWorkingText
+{
+ if (privateWorkingText == nil)
+ return;
+ if (NS_KEYLOG)
+ NSLog(@"deleteWorkingText len = %lu\n",
+ (unsigned long)[privateWorkingText length]);
+ [privateWorkingText release];
+ privateWorkingText = nil;
+ processingCompose = NO;
+
+ //PENDING: delete working text
+}
+@end
+
+
/*
* Set up basic fields in xevent for keyboard input.
@@ -472,7 +481,9 @@ XGrabKeyboard(
if (modalSession) {
Tcl_Panic("XGrabKeyboard: already grabbed");
}
- modalSession = [NSApp beginModalSessionForWindow:[w retain]];
+ keyboardGrabNSWindow = w;
+ [w retain];
+ modalSession = [NSApp beginModalSessionForWindow:w];
}
}
return GrabSuccess;
@@ -500,11 +511,12 @@ XUngrabKeyboard(
Time time)
{
if (modalSession) {
- NSWindow *w = keyboardGrabWinPtr ? TkMacOSXDrawableWindow(
- ((TkWindow *) keyboardGrabWinPtr)->window) : nil;
[NSApp endModalSession:modalSession];
- [w release];
- modalSession = NULL;
+ modalSession = nil;
+ }
+ if (keyboardGrabNSWindow) {
+ [keyboardGrabNSWindow release];
+ keyboardGrabNSWindow = nil;
}
keyboardGrabWinPtr = NULL;
}
diff --git a/macosx/tkMacOSXKeyboard.c b/macosx/tkMacOSXKeyboard.c
index 54f99d3..7ac087d 100644
--- a/macosx/tkMacOSXKeyboard.c
+++ b/macosx/tkMacOSXKeyboard.c
@@ -734,7 +734,8 @@ TkpGetKeySym(
*/
if (eventPtr->xany.send_event == -1) {
- int modifier = eventPtr->xkey.keycode;
+
+ int modifier = eventPtr->xkey.keycode & NSDeviceIndependentModifierFlagsMask;
if (modifier == NSCommandKeyMask) {
return XK_Meta_L;
diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c
index 83ad47a..c7e3a78 100644
--- a/macosx/tkMacOSXMenu.c
+++ b/macosx/tkMacOSXMenu.c
@@ -258,9 +258,10 @@ static int ModifierCharWidth(Tk_Font tkfont);
if (menuPtr && mePtr) {
Tcl_Interp *interp = menuPtr->interp;
- /*Add time for errors to fire if necessary. This is sub-optimal but avoids issues with Tcl/Cocoa event loop integration.*/
+ /*Add time for errors to fire if necessary. This is sub-optimal
+ *but avoids issues with Tcl/Cocoa event loop integration.
+ */
Tcl_Sleep(100);
-
Tcl_Preserve(interp);
Tcl_Preserve(menuPtr);
@@ -411,7 +412,7 @@ static int ModifierCharWidth(Tk_Font tkfont);
if (!mePtr || !(mePtr->entryFlags & ENTRY_APPLE_MENU)) {
applicationMenuItem = [NSMenuItem itemWithSubmenu:
- [[_defaultApplicationMenu copy] autorelease]];
+ [_defaultApplicationMenu copy]];
[menu insertItem:applicationMenuItem atIndex:0];
}
[menu setSpecial:tkMainMenu];
@@ -419,7 +420,7 @@ static int ModifierCharWidth(Tk_Font tkfont);
applicationMenu = (TKMenu *)[applicationMenuItem submenu];
if (![applicationMenu isSpecial:tkApplicationMenu]) {
for (NSMenuItem *item in _defaultApplicationMenuItems) {
- [applicationMenu addItem:[[item copy] autorelease]];
+ [applicationMenu addItem:[item copy]];
}
[applicationMenu setSpecial:tkApplicationMenu];
}
@@ -429,15 +430,13 @@ static int ModifierCharWidth(Tk_Font tkfont);
for (NSMenuItem *item in itemArray) {
TkMenuEntry *mePtr = (TkMenuEntry *)[item tag];
TKMenu *submenu = (TKMenu *)[item submenu];
-
if (mePtr && submenu) {
if ((mePtr->entryFlags & ENTRY_WINDOWS_MENU) &&
![submenu isSpecial:tkWindowsMenu]) {
NSInteger index = 0;
for (NSMenuItem *i in _defaultWindowsMenuItems) {
- [submenu insertItem:[[i copy] autorelease] atIndex:
- index++];
+ [submenu insertItem:[i copy] atIndex:index++];
}
[self setWindowsMenu:submenu];
[submenu setSpecial:tkWindowsMenu];
@@ -446,8 +445,7 @@ static int ModifierCharWidth(Tk_Font tkfont);
NSInteger index = 0;
for (NSMenuItem *i in _defaultHelpMenuItems) {
- [submenu insertItem:[[i copy] autorelease] atIndex:
- index++];
+ [submenu insertItem:[i copy] atIndex:index++];
}
[submenu setSpecial:tkHelpMenu];
}
@@ -496,8 +494,7 @@ TkpNewMenu(
* platform structure for. */
{
TKMenu *menu = [[TKMenu alloc] initWithTkMenu:menuPtr];
- menuPtr->platformData = (TkMenuPlatformData)
- TkMacOSXMakeUncollectable(menu);
+ menuPtr->platformData = (TkMenuPlatformData) menu;
CheckForSpecialMenu(menuPtr);
return TCL_OK;
}
@@ -522,7 +519,10 @@ void
TkpDestroyMenu(
TkMenu *menuPtr) /* The common menu structure */
{
- TkMacOSXMakeCollectableAndRelease(menuPtr->platformData);
+ NSMenu* nsmenu = (NSMenu*)(menuPtr->platformData);
+
+ [nsmenu release];
+ menuPtr->platformData = NULL;
}
/*
@@ -555,8 +555,7 @@ TkpMenuNewEntry(
} else {
menuItem = [menu newTkMenuItem:mePtr];
}
- mePtr->platformEntryData = (TkMenuPlatformEntryData)
- TkMacOSXMakeUncollectable(menuItem);
+ mePtr->platformEntryData = (TkMenuPlatformEntryData) menuItem;
/*
* Caller TkMenuEntry() already did this same insertion into the generic
@@ -684,6 +683,9 @@ TkpConfigureMenuEntry(
NSArray *itemArray = [submenu itemArray];
for (NSMenuItem *item in itemArray) {
TkMenuEntry *submePtr = menuRefPtr->menuPtr->entries[i];
+ /* Work around an apparent bug where itemArray can have
+ more items than the menu's entries[] array. */
+ if (i >= menuRefPtr->menuPtr->numEntries) break;
[item setEnabled: !(submePtr->state == ENTRY_DISABLED)];
i++;
}
@@ -717,16 +719,21 @@ void
TkpDestroyMenuEntry(
TkMenuEntry *mePtr)
{
+ NSMenuItem *menuItem;
+ TKMenu *menu;
+ NSInteger index;
+
if (mePtr->platformEntryData && mePtr->menuPtr->platformData) {
- TKMenu *menu = (TKMenu *) mePtr->menuPtr->platformData;
- NSMenuItem *menuItem = (NSMenuItem *) mePtr->platformEntryData;
- NSInteger index = [menu indexOfItem:menuItem];
+ menu = (TKMenu *) mePtr->menuPtr->platformData;
+ menuItem = (NSMenuItem *) mePtr->platformEntryData;
+ index = [menu indexOfItem:menuItem];
if (index > -1) {
[menu removeItemAtIndex:index];
}
+ [menuItem release];
+ mePtr->platformEntryData = NULL;
}
- TkMacOSXMakeCollectableAndRelease(mePtr->platformEntryData);
}
/*
@@ -754,11 +761,19 @@ TkpPostMenu(
* to be posted. */
int y) /* The global y-coordinate */
{
- NSWindow *win = [NSApp keyWindow];
- if (!win) {
+
+
+ /* Get the object that holds this Tk Window.*/
+ Tk_Window root;
+ root = Tk_MainWindow(interp);
+ if (root == NULL) {
return TCL_ERROR;
}
+ Drawable d = Tk_WindowId(root);
+ NSView *rootview = TkMacOSXGetRootControl(d);
+ NSWindow *win = [rootview window];
+
inPostMenu = 1;
int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
@@ -766,7 +781,7 @@ TkpPostMenu(
NSRect frame = NSMakeRect(x + 9, tkMacOSXZeroScreenHeight - y - 9, 1, 1);
frame.origin = [view convertPoint:
- [win convertScreenToBase:frame.origin] fromView:nil];
+ [win convertPointFromScreen:frame.origin] fromView:nil];
NSMenu *menu = (NSMenu *) menuPtr->platformData;
NSPopUpButtonCell *popUpButtonCell = [[NSPopUpButtonCell alloc]
@@ -819,11 +834,16 @@ TkpSetWindowMenuBar(
* Puts the menu associated with a window into the menubar. Should only
* be called when the window is in front.
*
+ * This is a no-op on all other platforms. On OS X it is a no-op when
+ * passed a NULL menuName or a nonexistent menuName, with an exception
+ * for the first call in a new interpreter. In that special case, passing a
+ * NULL menuName installs the default menu.
+ *
* Results:
* None.
*
* Side effects:
- * The menubar is changed.
+ * The menubar may be changed.
*
*----------------------------------------------------------------------
*/
@@ -832,8 +852,7 @@ void
TkpSetMainMenubar(
Tcl_Interp *interp, /* The interpreter of the application */
Tk_Window tkwin, /* The frame we are setting up */
- const char *menuName) /* The name of the menu to put in front. If
- * NULL, use the default menu bar. */
+ const char *menuName) /* The name of the menu to put in front. */
{
static Tcl_Interp *currentInterp = NULL;
TKMenu *menu = nil;
diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c
index d6e635a..a85e572 100644
--- a/macosx/tkMacOSXMenubutton.c
+++ b/macosx/tkMacOSXMenubutton.c
@@ -5,66 +5,70 @@
* menubutton widget.
*
* Copyright (c) 1996 by Sun Microsystems, Inc.
- * Copyright 2001-2009, Apple Inc.
- * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2001, Apple Computer, Inc.
+ * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2007 Revar Desmera.
+ * Copyright 2015 Kevin Walzer/WordTech Communications LLC.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
*/
#include "tkMacOSXPrivate.h"
+#include "tkMenu.h"
#include "tkMenubutton.h"
#include "tkMacOSXFont.h"
#include "tkMacOSXDebug.h"
-/*
-#ifdef TK_MAC_DEBUG
-#define TK_MAC_DEBUG_MENUBUTTON
-#endif
-*/
+#define FIRST_DRAW 2
+#define ACTIVE 4
-typedef struct MacMenuButton {
- TkMenuButton info;
- NSPopUpButton *button;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- int fix;
-#endif
-} MacMenuButton;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+typedef struct {
+ Tk_3DBorder border;
+ int relief;
+ GC gc;
+ int hasImageOrBitmap;
+} DrawParams;
+
/*
- * Use the following heuristic conversion constants to make NSButton-based
- * widget metrics match up with the old Carbon control buttons (for the
- * default Lucida Grande 13 font).
- * TODO: provide a scriptable way to turn this off and use the raw NSButton
- * metrics (will also need dynamic adjustment of the default padding,
- * c.f. tkMacOSXDefault.h).
+ * Declaration of Mac specific button structure.
*/
-typedef struct {
- int trimW, trimH, inset, shrinkW, offsetX, offsetY;
-} BoundsFix;
-
-#define fixForStyle(style) ( \
- style == NSRoundedBezelStyle ? 1 : \
- style == NSRegularSquareBezelStyle ? 2 : \
- style == NSShadowlessSquareBezelStyle ? 3 : \
- INT_MIN)
-
-static const BoundsFix boundsFixes[] = {
- [fixForStyle(NSRoundedBezelStyle)] = { 14, 10, -2, -1},
- [fixForStyle(NSRegularSquareBezelStyle)] = { 6, 13, -2, 1, 1},
- [fixForStyle(NSShadowlessSquareBezelStyle)] = { 15, 0, 2 },
-};
-
-#endif
+typedef struct MacMenuButton {
+ TkMenuButton info; /* Generic button info. */
+ int flags;
+ ThemeButtonKind btnkind;
+ HIThemeButtonDrawInfo drawinfo;
+ HIThemeButtonDrawInfo lastdrawinfo;
+ DrawParams drawParams;
+} MacMenuButton;
/*
* Forward declarations for procedures defined later in this file:
*/
static void MenuButtonEventProc(ClientData clientData, XEvent *eventPtr);
+static void MenuButtonBackgroundDrawCB ( MacMenuButton *ptr, SInt16 depth, Boolean isColorDev);
+static void MenuButtonContentDrawCB ( ThemeButtonKind kind, const HIThemeButtonDrawInfo * info, MacMenuButton *ptr, SInt16 depth, Boolean isColorDev);
+static void MenuButtonEventProc ( ClientData clientData, XEvent *eventPtr);
+static void TkMacOSXComputeMenuButtonParams (TkMenuButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo* drawinfo);
+static int TkMacOSXComputeMenuButtonDrawParams (TkMenuButton * butPtr, DrawParams * dpPtr);
+static void TkMacOSXDrawMenuButton (MacMenuButton *butPtr,
+ GC gc, Pixmap pixmap);
+static void DrawMenuButtonImageAndText(TkMenuButton* butPtr);
+
+/*
+ * The structure below defines menubutton class behavior by means of
+ * procedures that can be invoked from generic window code.
+ */
+
+Tk_ClassProcs tkpMenubuttonClass = {
+ sizeof(Tk_ClassProcs), /* size */
+ TkMenuButtonWorldChanged, /* worldChangedProc */
+};
/*
@@ -87,112 +91,94 @@ TkMenuButton *
TkpCreateMenuButton(
Tk_Window tkwin)
{
- MacMenuButton *macButtonPtr = ckalloc(sizeof(MacMenuButton));
+ MacMenuButton *mbPtr = (MacMenuButton *) ckalloc(sizeof(MacMenuButton));
- macButtonPtr->button = nil;
Tk_CreateEventHandler(tkwin, ActivateMask,
- MenuButtonEventProc, (ClientData) macButtonPtr);
- return (TkMenuButton *) macButtonPtr;
+ MenuButtonEventProc, (ClientData) mbPtr);
+ mbPtr->flags = FIRST_DRAW;
+ mbPtr->btnkind = kThemePopupButton;
+ bzero(&mbPtr->drawinfo, sizeof(mbPtr->drawinfo));
+ bzero(&mbPtr->lastdrawinfo, sizeof(mbPtr->lastdrawinfo));
+
+ return (TkMenuButton *) mbPtr;
}
/*
*----------------------------------------------------------------------
*
- * TkpDestroyMenuButton --
+ * TkpDisplayMenuButton --
*
- * Free data structures associated with the menubutton control.
+ * This procedure is invoked to display a menubutton widget.
*
* Results:
* None.
*
* Side effects:
- * Restores the default control state.
+ * Commands are output to X to display the menubutton in its
+ * current mode.
*
*----------------------------------------------------------------------
*/
void
-TkpDestroyMenuButton(
- TkMenuButton *mbPtr)
+TkpDisplayMenuButton(
+ ClientData clientData) /* Information about widget. */
{
- MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr;
+ MacMenuButton *mbPtr = (MacMenuButton *)clientData;
+ TkMenuButton *butPtr = (TkMenuButton *) clientData;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ DrawParams* dpPtr = &mbPtr->drawParams;
+
+ butPtr->flags &= ~REDRAW_PENDING;
+ if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
+ return;
+ }
+
+ pixmap = (Pixmap) Tk_WindowId(tkwin);
+
+ TkMacOSXComputeMenuButtonDrawParams(butPtr, dpPtr);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->button);
+ /*
+ * set up clipping region. Make sure the we are using the port
+ * for this button, or we will set the wrong window's clip.
+ */
+
+ TkMacOSXSetUpClippingRgn(pixmap);
+
+ /* Draw the native portion of the buttons. */
+ TkMacOSXDrawMenuButton(mbPtr, dpPtr->gc, pixmap);
+
+ /* Draw highlight border, if needed. */
+ if (butPtr->highlightWidth < 3) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ Tk_Draw3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin),
+ butPtr->highlightWidth, TK_RELIEF_SOLID);
+ }
+ }
}
/*
*----------------------------------------------------------------------
*
- * TkpDisplayMenuButton --
+ * TkpDestroyMenuButton --
*
- * This function is invoked to display a menubutton widget.
+ * Free data structures associated with the menubutton control.
*
* Results:
* None.
*
* Side effects:
- * Commands are output to X to display the menubutton in its current
- * mode.
+ * Restores the default control state.
*
*----------------------------------------------------------------------
*/
void
-TkpDisplayMenuButton(
- ClientData clientData) /* Information about widget. */
+TkpDestroyMenuButton(
+ TkMenuButton *mbPtr)
{
- TkMenuButton *mbPtr = (TkMenuButton *) clientData;
- MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr;
- NSPopUpButton *button = macButtonPtr->button;
- Tk_Window tkwin = mbPtr->tkwin;
- TkWindow *winPtr = (TkWindow *) tkwin;
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
- TkMacOSXDrawingContext dc;
- NSView *view = TkMacOSXDrawableView(macWin);
- CGFloat viewHeight = [view bounds].size.height;
- CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
- .ty = viewHeight};
- NSRect frame;
- int enabled;
-
- mbPtr->flags &= ~REDRAW_PENDING;
- if (!tkwin || !Tk_IsMapped(tkwin) || !view ||
- !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
- return;
- }
- CGContextConcatCTM(dc.context, t);
- Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, mbPtr->normalBorder, 0, 0,
- Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
- if ([button superview] != view) {
- [view addSubview:button];
- }
- enabled = !(mbPtr->state == STATE_DISABLED);
- [button setEnabled:enabled];
- if (enabled) {
- [[button cell] setHighlighted:(mbPtr->state == STATE_ACTIVE)];
- }
- frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin),
- Tk_Height(tkwin));
- frame = NSInsetRect(frame, mbPtr->inset, mbPtr->inset);
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- BoundsFix boundsFix = boundsFixes[macButtonPtr->fix];
- frame = NSOffsetRect(frame, boundsFix.offsetX, boundsFix.offsetY);
- frame.size.width -= boundsFix.shrinkW;
- frame = NSInsetRect(frame, boundsFix.inset, boundsFix.inset);
- }
-#endif
- frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
- if (!NSEqualRects(frame, [button frame])) {
- [button setFrame:frame];
- }
- [button displayRectIgnoringOpacity:[button bounds]];
- TkMacOSXRestoreDrawingContext(&dc);
-#ifdef TK_MAC_DEBUG_MENUBUTTON
- TKLog(@"menubutton %s frame %@ width %d height %d",
- ((TkWindow *)mbPtr->tkwin)->pathName, NSStringFromRect(frame),
- Tk_Width(tkwin), Tk_Height(tkwin));
-#endif
}
/*
@@ -200,7 +186,7 @@ TkpDisplayMenuButton(
*
* TkpComputeMenuButtonGeometry --
*
- * After changes in a menu button's text or bitmap, this function
+ * After changes in a menu button's text or bitmap, this procedure
* recomputes the menu button's geometry and passes this information
* along to the geometry manager for the window.
*
@@ -214,205 +200,504 @@ TkpDisplayMenuButton(
*/
void
-TkpComputeMenuButtonGeometry(
- TkMenuButton *mbPtr) /* Widget record for menu button. */
+TkpComputeMenuButtonGeometry(butPtr)
+ register TkMenuButton *butPtr; /* Widget record for menu button. */
{
- MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr;
- NSPopUpButton *button = macButtonPtr->button;
- NSPopUpButtonCell *cell;
- NSMenuItem *menuItem;
- NSBezelStyle style = NSRoundedBezelStyle;
- NSFont *font;
- NSRect bounds = NSZeroRect, titleRect = NSZeroRect;
- int haveImage = (mbPtr->image || mbPtr->bitmap != None), haveText = 0;
- int haveCompound = (mbPtr->compound != COMPOUND_NONE);
- int width, height;
-
- if (!button) {
- button = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:YES];
- macButtonPtr->button = TkMacOSXMakeUncollectable(button);
- cell = [button cell];
- [cell setUsesItemFromMenu:NO];
- menuItem = [[[NSMenuItem alloc] initWithTitle:@""
- action:NULL keyEquivalent:@""] autorelease];
- [cell setMenuItem:menuItem];
- } else {
- cell = [button cell];
- menuItem = [cell menuItem];
+ int width, height, avgWidth, haveImage = 0, haveText = 0;
+ MacMenuButton *mbPtr = (MacMenuButton*)butPtr;
+ int txtWidth, txtHeight;
+ Tk_FontMetrics fm;
+ DrawParams drawParams;
+ int paddingx = 0;
+ int paddingy = 0;
+
+ /*
+ * First figure out the size of the contents of the button.
+ */
+
+ width = 0;
+ height = 0;
+ txtWidth = 0;
+ txtHeight = 0;
+ avgWidth = 0;
+
+ TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
+
+ if (butPtr->image != NULL) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
}
- if (haveImage) {
- style = NSShadowlessSquareBezelStyle;
- } else if (!mbPtr->indicatorOn) {
- style = NSRegularSquareBezelStyle;
+
+ if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
+ Tk_FreeTextLayout(butPtr->textLayout);
+ butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
+ butPtr->text, -1, butPtr->wrapLength,
+ butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
+
+ txtWidth = butPtr->textWidth;
+ txtHeight = butPtr->textHeight;
+ avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
+ Tk_GetFontMetrics(butPtr->tkfont, &fm);
+ haveText = (txtWidth != 0 && txtHeight != 0);
}
- [button setBezelStyle:style];
- [cell setArrowPosition:(mbPtr->indicatorOn ? NSPopUpArrowAtBottom :
- NSPopUpNoArrow)];
-#if 0
- NSControlSize controlSize = NSRegularControlSize;
-
- if (mbPtr->borderWidth <= 2) {
- controlSize = NSMiniControlSize;
- } else if (mbPtr->borderWidth == 3) {
- controlSize = NSSmallControlSize;
+
+ /*
+ * If the button is compound (ie, it shows both an image and text),
+ * the new geometry is a combination of the image and text geometry.
+ * We only honor the compound bit if the button has both text and an
+ * image, because otherwise it is not really a compound button.
+ */
+
+ if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM: {
+ /*
+ * Image is above or below text
+ */
+
+ height += txtHeight + butPtr->padY;
+ width = (width > txtWidth ? width : txtWidth);
+ break;
+ }
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT: {
+ /*
+ * Image is left or right of text
+ */
+
+ width += txtWidth + butPtr->padX;
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ }
+ case COMPOUND_CENTER: {
+ /*
+ * Image and text are superimposed
+ */
+
+ width = (width > txtWidth ? width : txtWidth);
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ }
+ case COMPOUND_NONE: {break;}
+ }
+
+ if (butPtr->width > 0) {
+ width = butPtr->width;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height;
+ }
+
+ } else {
+ if (haveImage) {
+ if (butPtr->width > 0) {
+ width = butPtr->width;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height;
+ }
+ } else {
+ width = txtWidth;
+ height = txtHeight;
+ if (butPtr->width > 0) {
+ width = butPtr->width * avgWidth;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height * fm.linespace;
+ }
+ }
}
- [cell setControlSize:controlSize];
-#endif
-
- if (mbPtr->text && *(mbPtr->text) && (!haveImage || haveCompound)) {
- NSString *title = [[NSString alloc] initWithUTF8String:mbPtr->text];
- [button setTitle:title];
- [title release];
- haveText = 1;
+ width += 2 * butPtr->padX - 2;
+ height += 2 * butPtr->padY - 2;
+
+ /*Add padding for button arrows.*/
+ width += 22;
+
+ /*
+ * Now figure out the size of the border decorations for the button.
+ */
+
+ if (butPtr->highlightWidth < 0) {
+ butPtr->highlightWidth = 0;
}
- haveCompound = (haveCompound && haveImage && haveText);
- if (haveText) {
- NSTextAlignment alignment = NSNaturalTextAlignment;
-
- switch (mbPtr->justify) {
- case TK_JUSTIFY_LEFT:
- alignment = NSLeftTextAlignment;
- break;
- case TK_JUSTIFY_RIGHT:
- alignment = NSRightTextAlignment;
- break;
- case TK_JUSTIFY_CENTER:
- alignment = NSCenterTextAlignment;
- break;
- }
- [button setAlignment:alignment];
- } else {
- [button setTitle:@""];
+ butPtr->inset = 0;
+ butPtr->inset += butPtr->highlightWidth;
+
+ TkMacOSXComputeMenuButtonDrawParams(butPtr,&drawParams);
+
+ HIRect tmpRect;
+ HIRect contBounds;
+
+ tmpRect = CGRectMake(0, 0, width, height);
+
+ HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds);
+
+
+
+ /* If the content region has a minimum height, match it. */
+ if (height < contBounds.size.height) {
+ height = contBounds.size.height;
+ }
+
+ /* If the content region has a minimum width, match it. */
+ if (width < contBounds.size.width) {
+ width = contBounds.size.width;
+ }
+
+ /* Pad to fill difference between content bounds and button bounds. */
+ paddingx = tmpRect.origin.x - contBounds.origin.x;
+ paddingy = tmpRect.origin.y - contBounds.origin.y;
+
+ if (paddingx > 0) {
+ width += paddingx;
}
- font = TkMacOSXNSFontForFont(mbPtr->tkfont);
- if (font) {
- [button setFont:font];
+ if (paddingy > 0) {
+ height += paddingy;
}
- if (haveImage) {
- int width, height;
- NSImage *image;
- NSCellImagePosition pos = NSImageOnly;
-
- if (mbPtr->image) {
- Tk_SizeOfImage(mbPtr->image, &width, &height);
- image = TkMacOSXGetNSImageWithTkImage(mbPtr->display,
- mbPtr->image, width, height);
- } else {
- Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
- image = TkMacOSXGetNSImageWithBitmap(mbPtr->display,
- mbPtr->bitmap, mbPtr->normalTextGC, width, height);
- }
- if (haveCompound) {
- switch ((enum compound) mbPtr->compound) {
- case COMPOUND_TOP:
- pos = NSImageAbove;
- break;
- case COMPOUND_BOTTOM:
- pos = NSImageBelow;
- break;
- case COMPOUND_LEFT:
- pos = NSImageLeft;
- break;
- case COMPOUND_RIGHT:
- pos = NSImageRight;
- break;
- case COMPOUND_CENTER:
- pos = NSImageOverlaps;
- break;
- case COMPOUND_NONE:
- pos = NSImageOnly;
- break;
- }
- }
- [button setImagePosition:pos];
- [menuItem setImage:image];
- bounds.size = cell ? [cell cellSize] : NSZeroSize;
- if (bounds.size.height < height + 8) { /* workaround AppKit sizing bug */
- bounds.size.height = height + 8;
- }
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (!mbPtr->indicatorOn && tkMacOSXUseCompatibilityMetrics) {
- bounds.size.width -= 16;
- }
-#endif
- } else {
- bounds.size = cell ? [cell cellSize] : NSZeroSize;
+
+ width += butPtr->inset*2;
+ height += butPtr->inset*2;
+
+
+ Tk_GeometryRequest(butPtr->tkwin, width, height);
+ Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawMenuButtonImageAndText --
+ *
+ * Draws the image and text associated witha button or label.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The image and text are drawn.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+DrawMenuButtonImageAndText(
+ TkMenuButton* butPtr)
+{
+ MacMenuButton *mbPtr = (MacMenuButton*)butPtr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ int haveImage = 0;
+ int haveText = 0;
+ int imageWidth = 0;
+ int imageHeight = 0;
+ int imageXOffset = 0;
+ int imageYOffset = 0;
+ int textXOffset = 0;
+ int textYOffset = 0;
+ int width = 0;
+ int height = 0;
+ int fullWidth = 0;
+ int fullHeight = 0;
+ int pressed;
+
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- if (haveText) {
- titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect;
- if (mbPtr->wrapLength > 0 &&
- titleRect.size.width > mbPtr->wrapLength) {
- if (style == NSRoundedBezelStyle) {
- [button setBezelStyle:(style = NSRegularSquareBezelStyle)];
- bounds.size = cell ? [cell cellSize] : NSZeroSize;
- titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect;
- }
- bounds.size.width -= titleRect.size.width - mbPtr->wrapLength;
- bounds.size.height = 40000.0;
- [cell setWraps:YES];
- bounds.size = cell ? [cell cellSizeForBounds:bounds] : NSZeroSize;
-#ifdef TK_MAC_DEBUG_MENUBUTTON
- titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect;
-#endif
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- bounds.size.height += 3;
- }
-#endif
- }
+
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+
+ if (butPtr->image != None) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
}
- width = lround(bounds.size.width);
- height = lround(bounds.size.height);
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- macButtonPtr->fix = fixForStyle(style);
- width -= boundsFixes[macButtonPtr->fix].trimW;
- height -= boundsFixes[macButtonPtr->fix].trimH;
+
+ imageWidth = width;
+ imageHeight = height;
+
+ if (mbPtr->drawinfo.state == kThemeStatePressed) {
+ /* Offset bitmaps by a bit when the button is pressed. */
+ pressed = 1;
}
-#endif
- if (haveImage || haveCompound) {
- if (mbPtr->width > 0) {
- width = mbPtr->width;
- }
- if (mbPtr->height > 0) {
- height = mbPtr->height;
+ haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
+ if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
+ int x = 0;
+ int y = 0;
+ textXOffset = 0;
+ textYOffset = 0;
+ fullWidth = 0;
+ fullHeight = 0;
+
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM: {
+ /* Image is above or below text */
+ if (butPtr->compound == COMPOUND_TOP) {
+ textYOffset = height + butPtr->padY;
+ } else {
+ imageYOffset = butPtr->textHeight + butPtr->padY;
+ }
+ fullHeight = height + butPtr->textHeight + butPtr->padY;
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ break;
+ }
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT: {
+ /*
+ * Image is left or right of text
+ */
+
+ if (butPtr->compound == COMPOUND_LEFT) {
+ textXOffset = width + butPtr->padX - 2;
+ } else {
+ imageXOffset = butPtr->textWidth + butPtr->padX;
+ }
+ fullWidth = butPtr->textWidth + butPtr->padX + width;
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
+ }
+ case COMPOUND_CENTER: {
+ /*
+ * Image and text are superimposed
+ */
+
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
+ }
+ case COMPOUND_NONE: {break;}
}
+
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ fullWidth, fullHeight, &x, &y);
+ imageXOffset += x;
+ imageYOffset += y;
+ textYOffset -= 1;
+
+ if (butPtr->image != NULL) {
+ Tk_RedrawImage(butPtr->image, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc,
+ imageXOffset, imageYOffset);
+ XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width, (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+
+ Tk_DrawTextLayout(butPtr->display, pixmap,
+ dpPtr->gc, butPtr->textLayout,
+ x + textXOffset, y + textYOffset, 0, -1);
+ Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout,
+ x + textXOffset, y + textYOffset,
+ butPtr->underline);
} else {
- if (mbPtr->width > 0) {
- int avgWidth = Tk_TextWidth(mbPtr->tkfont, "0", 1);
- width = mbPtr->width * avgWidth;
+ if (haveImage) {
+ int x = 0;
+ int y;
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ width, height, &x, &y);
+ imageXOffset += x;
+ imageYOffset += y;
+
+ if (butPtr->image != NULL) {
+ Tk_RedrawImage(butPtr->image, 0, 0, width, height,
+ pixmap, imageXOffset, imageYOffset);
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc, x, y);
+ XCopyPlane(butPtr->display, butPtr->bitmap,
+ pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width,
+ (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+ } else {
+ /*Move x back by eight pixels to give the menubutton arrows room.*/
+ int x = 0;
+ int y;
+ textXOffset = 8;
+ TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
+ butPtr->textWidth, butPtr->textHeight, &x, &y);
+ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout, x - textXOffset, y, 0, -1);
+ y += butPtr->textHeight/2;
+ }
+ }
+}
+
+
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TkMacOSXDrawMenuButton --
+ *
+ * This function draws the tk menubutton using Mac controls
+ * In addition, this code may apply custom colors passed
+ * in the TkMenubutton.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+TkMacOSXDrawMenuButton(
+ MacMenuButton *mbPtr, /* Mac menubutton. */
+ GC gc, /* The GC we are drawing into - needed for
+ * the bevel button */
+ Pixmap pixmap) /* The pixmap we are drawing into - needed
+ * for the bevel button */
+
+{
+ TkMenuButton * butPtr = ( TkMenuButton *)mbPtr;
+ TkWindow * winPtr;
+ HIRect cntrRect;
+ TkMacOSXDrawingContext dc;
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ int useNewerHITools = 1;
+
+ winPtr = (TkWindow *)butPtr->tkwin;
+
+ TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
+
+ cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin),Tk_Height(butPtr->tkwin));
+
+ cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset);
+
+
+ if (useNewerHITools == 1) {
+ HIRect contHIRec;
+ static HIThemeButtonDrawInfo hiinfo;
+
+ MenuButtonBackgroundDrawCB((MacMenuButton*) mbPtr, 32, true);
+
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
}
- if (mbPtr->height > 0) {
- Tk_FontMetrics fm;
- Tk_GetFontMetrics(mbPtr->tkfont, &fm);
- height = mbPtr->height * fm.linespace;
+
+ hiinfo.version = 0;
+ hiinfo.state = mbPtr->drawinfo.state;
+ hiinfo.kind = mbPtr->btnkind;
+ hiinfo.value = mbPtr->drawinfo.value;
+ hiinfo.adornment = mbPtr->drawinfo.adornment;
+ hiinfo.animation.time.current = CFAbsoluteTimeGetCurrent();
+ if (hiinfo.animation.time.start == 0) {
+ hiinfo.animation.time.start = hiinfo.animation.time.current;
+ }
+
+ HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec);
+
+ TkMacOSXRestoreDrawingContext(&dc);
+
+ MenuButtonContentDrawCB( mbPtr->btnkind, &mbPtr->drawinfo, (MacMenuButton *)mbPtr, 32, true);
+ } else {
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
}
+
+
+ TkMacOSXRestoreDrawingContext(&dc);
}
- if (!haveImage || haveCompound) {
- width += 2*mbPtr->padX;
- height += 2*mbPtr->padY;
- }
- if (mbPtr->highlightWidth < 0) {
- mbPtr->highlightWidth = 0;
+ mbPtr->lastdrawinfo = mbPtr->drawinfo;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * MenuButtonBackgroundDrawCB --
+ *
+ * This function draws the background that
+ * lies under checkboxes and radiobuttons.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The background gets updated to the current color.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+MenuButtonBackgroundDrawCB (
+ MacMenuButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
+{
+ TkMenuButton* butPtr = (TkMenuButton*)ptr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- if (haveImage) {
- mbPtr->inset = mbPtr->highlightWidth;
- width += 2*mbPtr->borderWidth;
- height += 2*mbPtr->borderWidth;
- } else {
- mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth;
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * MenuButtonContentDrawCB --
+ *
+ * This function draws the label and image for the button.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The content of the button gets updated.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+MenuButtonContentDrawCB (
+ ThemeButtonKind kind,
+ const HIThemeButtonDrawInfo *drawinfo,
+ MacMenuButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
+{
+ TkMenuButton *butPtr = (TkMenuButton *)ptr;
+ Tk_Window tkwin = butPtr->tkwin;
+
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- Tk_GeometryRequest(mbPtr->tkwin, width + 2 * mbPtr->inset,
- height + 2 * mbPtr->inset);
- Tk_SetInternalBorder(mbPtr->tkwin, mbPtr->inset);
-#ifdef TK_MAC_DEBUG_MENUBUTTON
- TKLog(@"menubutton %s bounds %@ titleRect %@ width %d height %d inset %d borderWidth %d",
- ((TkWindow *)mbPtr->tkwin)->pathName, NSStringFromRect(bounds),
- NSStringFromRect(titleRect), width, height, mbPtr->inset,
- mbPtr->borderWidth);
-#endif
+
+ DrawMenuButtonImageAndText( butPtr);
}
/*
@@ -427,7 +712,7 @@ TkpComputeMenuButtonGeometry(
* None.
*
* Side effects:
- * When activation state changes, it is redisplayed.
+ * When it gets exposed, it is redisplayed.
*
*--------------------------------------------------------------
*/
@@ -437,27 +722,124 @@ MenuButtonEventProc(
ClientData clientData, /* Information about window. */
XEvent *eventPtr) /* Information about event. */
{
- TkMenuButton *mbPtr = (TkMenuButton *) clientData;
+ TkMenuButton *buttonPtr = (TkMenuButton *) clientData;
+ MacMenuButton *mbPtr = (MacMenuButton *) clientData;
- if (!mbPtr->tkwin || !Tk_IsMapped(mbPtr->tkwin)) {
- return;
+ if (eventPtr->type == ActivateNotify
+ || eventPtr->type == DeactivateNotify) {
+ if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) {
+ return;
+ }
+ if (eventPtr->type == ActivateNotify) {
+ mbPtr->flags |= ACTIVE;
+ } else {
+ mbPtr->flags &= ~ACTIVE;
+ }
+ if ((buttonPtr->flags & REDRAW_PENDING) == 0) {
+ Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) buttonPtr);
+ buttonPtr->flags |= REDRAW_PENDING;
+ }
}
- switch (eventPtr->type) {
- case ActivateNotify:
- case DeactivateNotify:
- if (!(mbPtr->flags & REDRAW_PENDING)) {
- Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr);
- mbPtr->flags |= REDRAW_PENDING;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXComputeMenuButtonParams --
+ *
+ * This procedure computes the various parameters used
+ * when creating a Carbon Appearance control.
+ * These are determined by the various tk button parameters
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Sets the btnkind and drawinfo parameters
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+TkMacOSXComputeMenuButtonParams(TkMenuButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo *drawinfo)
+{
+ MacMenuButton *mbPtr = (MacMenuButton *)butPtr;
+
+ if (butPtr->image || butPtr->bitmap) {
+ /* TODO: allow for Small and Mini menubuttons. */
+ *btnkind = kThemePopupButton;
+ } else {
+ if (!butPtr->text || !*butPtr->text) {
+ *btnkind = kThemeArrowButton;
+ } else {
+ *btnkind = kThemePopupButton;
+ }
+ }
+
+ drawinfo->value = kThemeButtonOff;
+
+ if ((mbPtr->flags & FIRST_DRAW) != 0) {
+ mbPtr->flags &= ~FIRST_DRAW;
+ if (Tk_MacOSXIsAppInFront()) {
+ mbPtr->flags |= ACTIVE;
}
- break;
}
+
+ drawinfo->state = kThemeStateInactive;
+ if ((mbPtr->flags & ACTIVE) == 0) {
+ if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailableInactive;
+ } else {
+ drawinfo->state = kThemeStateInactive;
+ }
+ } else if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailable;
+ } else {
+ drawinfo->state = kThemeStateActive;
+ }
+
+ drawinfo->adornment = kThemeAdornmentNone;
+ if (butPtr->highlightWidth >= 3) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ drawinfo->adornment |= kThemeAdornmentFocus;
+ }
+ }
+ drawinfo->adornment |= kThemeAdornmentArrowDoubleArrow;
}
/*
- * Local Variables:
- * mode: objc
- * c-basic-offset: 4
- * fill-column: 79
- * coding: utf-8
- * End:
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXComputeMenuButtonDrawParams --
+ *
+ * This procedure computes the various parameters used
+ * when drawing a button
+ * These are determined by the various tk button parameters
+ *
+ * Results:
+ * 1 if control will be used, 0 otherwise.
+ *
+ * Side effects:
+ * Sets the button draw parameters
+ *
+ *----------------------------------------------------------------------
*/
+
+static int
+TkMacOSXComputeMenuButtonDrawParams(TkMenuButton * butPtr, DrawParams * dpPtr)
+{
+ dpPtr->hasImageOrBitmap = ((butPtr->image != NULL)
+ || (butPtr->bitmap != None));
+ dpPtr->border = butPtr->normalBorder;
+ if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
+ dpPtr->gc = butPtr->disabledGC;
+ } else if (butPtr->state == STATE_ACTIVE) {
+ dpPtr->gc = butPtr->activeTextGC;
+ dpPtr->border = butPtr->activeBorder;
+ } else {
+ dpPtr->gc = butPtr->normalTextGC;
+ }
+
+ return 1;
+}
+
diff --git a/macosx/tkMacOSXMenus.c b/macosx/tkMacOSXMenus.c
index 881bf75..68b2c00 100644
--- a/macosx/tkMacOSXMenus.c
+++ b/macosx/tkMacOSXMenus.c
@@ -145,10 +145,9 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
SEL action = [anItem action];
if (sel_isEqual(action, @selector(preferences:))) {
- Tcl_CmdInfo dummy;
- return (_eventInterp && Tcl_GetCommandInfo(_eventInterp,
- "::tk::mac::ShowPreferences", &dummy));
+ return (_eventInterp && Tcl_FindCommand(_eventInterp,
+ "::tk::mac::ShowPreferences", NULL, 0));
} else if (sel_isEqual(action, @selector(tkDemo:))) {
BOOL haveDemo = NO;
@@ -169,10 +168,8 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
- (void) orderFrontStandardAboutPanel: (id) sender
{
- Tcl_CmdInfo dummy;
-
- if (!_eventInterp || !Tcl_GetCommandInfo(_eventInterp, "tkAboutDialog",
- &dummy) || (GetCurrentEventKeyModifiers() & optionKey)) {
+ if (!_eventInterp || !Tcl_FindCommand(_eventInterp, "tkAboutDialog",
+ NULL, 0) || (GetCurrentEventKeyModifiers() & optionKey)) {
TkAboutDlg();
} else {
int code = Tcl_EvalEx(_eventInterp, "tkAboutDialog", -1,
@@ -187,10 +184,8 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
- (void) showHelp: (id) sender
{
- Tcl_CmdInfo dummy;
-
- if (!_eventInterp || !Tcl_GetCommandInfo(_eventInterp,
- "::tk::mac::ShowHelp", &dummy)) {
+ if (!_eventInterp || !Tcl_FindCommand(_eventInterp,
+ "::tk::mac::ShowHelp", NULL, 0)) {
[super showHelp:sender];
} else {
int code = Tcl_EvalEx(_eventInterp, "::tk::mac::ShowHelp", -1,
diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c
index 90d2d00..c4197f7 100644
--- a/macosx/tkMacOSXMouseEvent.c
+++ b/macosx/tkMacOSXMouseEvent.c
@@ -26,13 +26,22 @@ typedef struct {
static int GenerateButtonEvent(MouseEventData *medPtr);
static unsigned int ButtonModifiers2State(UInt32 buttonState,
- UInt32 keyModifiers);
+ UInt32 keyModifiers);
#pragma mark TKApplication(TKMouseEvent)
enum {
NSWindowWillMoveEventType = 20
};
+/*
+ * In OS X 10.6 an NSEvent of type NSMouseMoved would always have a non-Nil
+ * window attribute pointing to the active window. As of 10.8 this behavior
+ * had changed. The new behavior was that if the mouse were ever moved outside
+ * of a window, all subsequent NSMouseMoved NSEvents would have a Nil window
+ * attribute. To work around this the TKApplication remembers the last non-Nil
+ * window that it received in a mouse event. If it receives an NSEvent with a
+ * Nil window attribute then the saved window is used.
+ */
@implementation TKApplication(TKMouseEvent)
- (NSEvent *) tkProcessMouseEvent: (NSEvent *) theEvent
@@ -40,80 +49,72 @@ enum {
#ifdef TK_MAC_DEBUG_EVENTS
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent);
#endif
- id win;
- NSEventType type = [theEvent type];
+ NSWindow* eventWindow = [theEvent window];
+ NSEventType eventType = [theEvent type];
#if 0
NSTrackingArea *trackingArea = nil;
NSInteger eventNumber, clickCount, buttonNumber;
#endif
-
- switch (type) {
+ switch (eventType) {
case NSMouseEntered:
case NSMouseExited:
case NSCursorUpdate:
-#if 0
- trackingArea = [theEvent trackingArea];
-#endif
- /* fall through */
case NSLeftMouseDown:
case NSLeftMouseUp:
case NSRightMouseDown:
case NSRightMouseUp:
case NSOtherMouseDown:
case NSOtherMouseUp:
-
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSOtherMouseDragged:
-
case NSMouseMoved:
-#if 0
- eventNumber = [theEvent eventNumber];
- if (!trackingArea) {
- clickCount = [theEvent clickCount];
- buttonNumber = [theEvent buttonNumber];
- }
-#endif
-
case NSTabletPoint:
case NSTabletProximity:
-
case NSScrollWheel:
- win = [self windowWithWindowNumber:[theEvent windowNumber]];
break;
-
- default:
+ default: /* Unrecognized mouse event. */
return theEvent;
- break;
}
- NSPoint global, local = [theEvent locationInWindow];
+ /* Remember the window in case we need it next time. */
+ if (eventWindow && eventWindow != _windowWithMouse) {
+ if (_windowWithMouse) {
+ [_windowWithMouse release];
+ }
+ _windowWithMouse = eventWindow;
+ [_windowWithMouse retain];
+ }
- if (win) {
- global = [win convertBaseToScreen:local];
- local.y = [win frame].size.height - local.y;
+ /* Create an Xevent to add to the Tk queue. */
+ NSPoint global, local = [theEvent locationInWindow];
+ if (eventWindow) { /* local will be in window coordinates. */
+ global = [eventWindow convertPointToScreen: local];
+ local.y = [eventWindow frame].size.height - local.y;
global.y = tkMacOSXZeroScreenHeight - global.y;
- } else {
- local.y = tkMacOSXZeroScreenHeight - local.y;
- global = local;
+ } else { /* local will be in screen coordinates. */
+ if (_windowWithMouse ) {
+ eventWindow = _windowWithMouse;
+ global = local;
+ local = [eventWindow convertPointFromScreen: local];
+ local.y = [eventWindow frame].size.height - local.y;
+ global.y = tkMacOSXZeroScreenHeight - global.y;
+ } else { /* We have no window. Use the screen???*/
+ local.y = tkMacOSXZeroScreenHeight - local.y;
+ global = local;
+ }
}
- Window window = TkMacOSXGetXWindow(win);
+ Window window = TkMacOSXGetXWindow(eventWindow);
Tk_Window tkwin = window ? Tk_IdToWindow(TkGetDisplayList()->display,
window) : NULL;
if (!tkwin) {
tkwin = TkMacOSXGetCapture();
}
if (!tkwin) {
- return theEvent;
+ return theEvent; /* Give up. No window for this event. */
}
- /*
- MacDrawable *macWin = (MacDrawable *) window;
- NSView *view = TkMacOSXDrawableView(macWin);
- local = [view convertPoint:local fromView:nil];
- local.y = NSHeight([view bounds]) - local.y;
- */
TkWindow *winPtr = (TkWindow *) tkwin;
local.x -= winPtr->wmInfoPtr->xInParent;
local.y -= winPtr->wmInfoPtr->yInParent;
@@ -127,12 +128,12 @@ enum {
EventRef eventRef = (EventRef)[theEvent eventRef];
UInt32 buttons;
OSStatus err = GetEventParameter(eventRef, kEventParamMouseChord,
- typeUInt32, NULL, sizeof(UInt32), NULL, &buttons);
+ typeUInt32, NULL, sizeof(UInt32), NULL, &buttons);
if (err == noErr) {
- state |= (buttons & ((1<<5) - 1)) << 8;
+ state |= (buttons & ((1<<5) - 1)) << 8;
} else if (button < 5) {
- switch (type) {
+ switch (eventType) {
case NSLeftMouseDown:
case NSRightMouseDown:
case NSLeftMouseDragged:
@@ -169,12 +170,12 @@ enum {
state |= Mod4Mask;
}
- if (type != NSScrollWheel) {
+ if (eventType != NSScrollWheel) {
#ifdef TK_MAC_DEBUG_EVENTS
TKLog(@"UpdatePointer %p x %f.0 y %f.0 %d", tkwin, global.x, global.y, state);
#endif
Tk_UpdatePointer(tkwin, global.x, global.y, state);
- } else {
+ } else { /* handle scroll wheel event */
CGFloat delta;
int coarseDelta;
XEvent xEvent;
@@ -190,7 +191,8 @@ enum {
delta = [theEvent deltaY];
if (delta != 0.0) {
- coarseDelta = (delta > -1.0 && delta < 1.0) ? (signbit(delta) ? -1 : 1) : lround(delta);
+ coarseDelta = (delta > -1.0 && delta < 1.0) ?
+ (signbit(delta) ? -1 : 1) : lround(delta);
xEvent.xbutton.state = state;
xEvent.xkey.keycode = coarseDelta;
xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
@@ -198,14 +200,14 @@ enum {
}
delta = [theEvent deltaX];
if (delta != 0.0) {
- coarseDelta = (delta > -1.0 && delta < 1.0) ? (signbit(delta) ? -1 : 1) : lround(delta);
+ coarseDelta = (delta > -1.0 && delta < 1.0) ?
+ (signbit(delta) ? -1 : 1) : lround(delta);
xEvent.xbutton.state = state | ShiftMask;
xEvent.xkey.keycode = coarseDelta;
xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
}
}
-
return theEvent;
}
@end
@@ -370,7 +372,7 @@ XQueryPointer(
if (win) {
NSPoint local;
- local = [win convertScreenToBase:global];
+ local = [win convertPointFromScreen:global];
local.y = [win frame].size.height - local.y;
if (macWin->winPtr && macWin->winPtr->wmInfoPtr) {
local.x -= macWin->winPtr->wmInfoPtr->xInParent;
@@ -468,7 +470,7 @@ TkGenerateButtonEvent(
if (win) {
NSPoint local = NSMakePoint(x, tkMacOSXZeroScreenHeight - y);
- local = [win convertScreenToBase:local];
+ local = [win convertPointFromScreen:local];
local.y = [win frame].size.height - local.y;
if (macWin->winPtr && macWin->winPtr->wmInfoPtr) {
local.x -= macWin->winPtr->wmInfoPtr->xInParent;
@@ -554,19 +556,18 @@ TkpWarpPointer(
}
/*
- * Tell the OSX core to generate the events to make it happen. This is
- * fairly ugly, but means that under most circumstances we'll register all
- * the events that would normally be generated correctly. If we use
- * CGWarpMouseCursorPosition instead, strange things happen.
+ * Tell the OSX core to generate the events to make it happen.
*/
- buttonState = (GetCurrentEvent() && Tk_MacOSXIsAppInFront())
- ? GetCurrentEventButtonState() : GetCurrentButtonState();
-
- CGPostMouseEvent(pt, 1 /* generate motion events */, 5,
- buttonState&1 ? 1 : 0, buttonState&2 ? 1 : 0,
- buttonState&4 ? 1 : 0, buttonState&8 ? 1 : 0,
- buttonState&16 ? 1 : 0);
+ buttonState = [NSEvent pressedMouseButtons];
+ CGEventType type = kCGEventMouseMoved;
+ CGEventRef theEvent = CGEventCreateMouseEvent(NULL,
+ type,
+ pt,
+ buttonState);
+ CGWarpMouseCursorPosition(pt);
+ CGEventPost(kCGHIDEventTap, theEvent);
+ CFRelease(theEvent);
}
/*
diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c
index 3e0dfde..1455688 100644
--- a/macosx/tkMacOSXNotify.c
+++ b/macosx/tkMacOSXNotify.c
@@ -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 2015 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -18,9 +19,9 @@
#include <pthread.h>
#import <objc/objc-auto.h>
+/* This is not used for anything at the moment. */
typedef struct ThreadSpecificData {
- int initialized, sendEventNestingLevel;
- NSEvent *currentEvent;
+ int initialized;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
@@ -34,6 +35,7 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags);
#pragma mark TKApplication(TKNotify)
@interface NSApplication(TKNotify)
+/* We need to declare this hidden method. */
- (void) _modalSession: (NSModalSession) session sendEvent: (NSEvent *) event;
@end
@@ -48,41 +50,27 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags);
@end
@implementation TKApplication(TKNotify)
+/* Display all windows each time an event is removed from the queue.*/
- (NSEvent *) nextEventMatchingMask: (NSUInteger) mask
untilDate: (NSDate *) expiration inMode: (NSString *) mode
dequeue: (BOOL) deqFlag
{
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
-
+ NSEvent *event = [super nextEventMatchingMask:mask
+ untilDate:expiration
+ inMode:mode
+ dequeue:deqFlag];
+ /* Retain this event for later use. Must be released.*/
+ [event retain];
[NSApp makeWindowsPerform:@selector(tkDisplayIfNeeded) inOrder:NO];
-
- int oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
- NSEvent *event = [[super nextEventMatchingMask:mask untilDate:expiration
- inMode:mode dequeue:deqFlag] retain];
-
- Tcl_SetServiceMode(oldMode);
- if (event) {
- TSD_INIT();
- if (tsdPtr->sendEventNestingLevel) {
- if (![NSApp tkProcessEvent:event]) {
- [event release];
- event = nil;
- }
- }
- }
- [pool drain];
- return [event autorelease];
+ return event;
}
+/*
+ * Call super then check the pasteboard.
+ */
- (void) sendEvent: (NSEvent *) theEvent
{
- TSD_INIT();
- int oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
-
- tsdPtr->sendEventNestingLevel++;
[super sendEvent:theEvent];
- tsdPtr->sendEventNestingLevel--;
- Tcl_SetServiceMode(oldMode);
[NSApp tkCheckPasteboard];
}
@end
@@ -161,7 +149,8 @@ Tk_MacOSXSetupTkNotifier(void)
"first [load] of TkAqua has to occur in the main thread!");
}
Tcl_CreateEventSource(TkMacOSXEventsSetupProc,
- TkMacOSXEventsCheckProc, GetMainEventQueue());
+ TkMacOSXEventsCheckProc,
+ GetMainEventQueue());
TkCreateExitHandler(TkMacOSXNotifyExitHandler, NULL);
Tcl_SetServiceMode(TCL_SERVICE_ALL);
TclMacOSXNotifierAddRunLoopMode(NSEventTrackingRunLoopMode);
@@ -194,7 +183,8 @@ TkMacOSXNotifyExitHandler(
TSD_INIT();
Tcl_DeleteEventSource(TkMacOSXEventsSetupProc,
- TkMacOSXEventsCheckProc, GetMainEventQueue());
+ TkMacOSXEventsCheckProc,
+ GetMainEventQueue());
tsdPtr->initialized = 0;
}
@@ -203,16 +193,19 @@ TkMacOSXNotifyExitHandler(
*
* TkMacOSXEventsSetupProc --
*
- * This procedure implements the setup part of the TkAqua Events event
- * source. It is invoked by Tcl_DoOneEvent before entering the notifier
- * to check for events.
+ * This procedure implements the setup part of the MacOSX event
+ * source. It is invoked by Tcl_DoOneEvent before calling
+ * TkMacOSXEventsProc to process all queued NSEvents. In our
+ * case, all we need to do is to set the Tcl MaxBlockTime to
+ * 0 before starting the loop to process all queued NSEvents.
*
* Results:
* None.
*
* Side effects:
- * If TkAqua events are queued, then the maximum block time will be set
- * to 0 to ensure that the notifier returns control to Tcl.
+ *
+ * If NSEvents are queued, then the maximum block time will be set
+ * to 0 to ensure that control returns immediately to Tcl.
*
*----------------------------------------------------------------------
*/
@@ -222,24 +215,20 @@ TkMacOSXEventsSetupProc(
ClientData clientData,
int flags)
{
- if (flags & TCL_WINDOW_EVENTS &&
- ![[NSRunLoop currentRunLoop] currentMode]) {
+ NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode];
+ /* runloopMode will be nil if we are in the Tcl event loop. */
+ if (flags & TCL_WINDOW_EVENTS && !runloopMode) {
static const Tcl_Time zeroBlockTime = { 0, 0 };
- TSD_INIT();
-
- if (!tsdPtr->currentEvent) {
- NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
- untilDate:[NSDate distantPast]
- inMode:GetRunLoopMode(TkMacOSXGetModalSession())
- dequeue:YES];
-
- if (currentEvent) {
- tsdPtr->currentEvent =
- TkMacOSXMakeUncollectableAndRetain(currentEvent);
+ /* Call this with dequeue=NO -- just checking if the queue is empty. */
+ NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantPast]
+ inMode:GetRunLoopMode(TkMacOSXGetModalSession())
+ dequeue:NO];
+ if (currentEvent) {
+ if (currentEvent.type > 0) {
+ Tcl_SetMaxBlockTime(&zeroBlockTime);
}
- }
- if (tsdPtr->currentEvent) {
- Tcl_SetMaxBlockTime(&zeroBlockTime);
+ [currentEvent release];
}
}
}
@@ -249,69 +238,69 @@ TkMacOSXEventsSetupProc(
*
* TkMacOSXEventsCheckProc --
*
- * This procedure processes events sitting in the TkAqua event queue.
+ * This procedure loops through all NSEvents waiting in the
+ * TKApplication event queue, generating X events from them.
*
* Results:
* None.
*
* Side effects:
- * Moves applicable queued TkAqua events onto the Tcl event queue.
+ * NSevents are used to generate X events, which are added to the
+ * Tcl event queue.
*
*----------------------------------------------------------------------
*/
-
static void
TkMacOSXEventsCheckProc(
ClientData clientData,
int flags)
{
- if (flags & TCL_WINDOW_EVENTS &&
- ![[NSRunLoop currentRunLoop] currentMode]) {
+ NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode];
+ /* runloopMode will be nil if we are in the Tcl event loop. */
+ if (flags & TCL_WINDOW_EVENTS && !runloopMode) {
NSEvent *currentEvent = nil;
- NSAutoreleasePool *pool = nil;
+ NSEvent *testEvent = nil;
NSModalSession modalSession;
- TSD_INIT();
- if (tsdPtr->currentEvent) {
- currentEvent = TkMacOSXMakeCollectableAndAutorelease(
- tsdPtr->currentEvent);
- }
do {
+ [NSApp _resetAutoreleasePool];
modalSession = TkMacOSXGetModalSession();
- if (!currentEvent) {
- currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
- untilDate:[NSDate distantPast]
- inMode:GetRunLoopMode(modalSession) dequeue:YES];
- }
- if (!currentEvent) {
+ testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantPast]
+ inMode:GetRunLoopMode(modalSession)
+ dequeue:NO];
+ /* We must not steal any events during LiveResize. */
+ if (testEvent && [[testEvent window] inLiveResize]) {
break;
}
- [currentEvent retain];
- pool = [NSAutoreleasePool new];
- if (tkMacOSXGCEnabled) {
- objc_clear_stack(0);
- }
- if (![NSApp tkProcessEvent:currentEvent]) {
- [currentEvent release];
- currentEvent = nil;
- }
+
+ currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantPast]
+ inMode:GetRunLoopMode(modalSession)
+ dequeue:YES];
if (currentEvent) {
+ /* Generate Xevents. */
+ int oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
+ NSEvent *processedEvent = [NSApp tkProcessEvent:currentEvent];
+ Tcl_SetServiceMode(oldServiceMode);
+ if (processedEvent) { /* Should always be non-NULL. */
#ifdef TK_MAC_DEBUG_EVENTS
- TKLog(@" event: %@", currentEvent);
+ TKLog(@" event: %@", currentEvent);
#endif
- if (modalSession) {
- [NSApp _modalSession:modalSession sendEvent:currentEvent];
- } else {
- [NSApp sendEvent:currentEvent];
+ if (modalSession) {
+ [NSApp _modalSession:modalSession sendEvent:currentEvent];
+ } else {
+ [NSApp sendEvent:currentEvent];
+ }
}
[currentEvent release];
- currentEvent = nil;
+ } else {
+ break;
}
- [pool drain];
- pool = nil;
} while (1);
}
}
+
/*
* Local Variables:
diff --git a/macosx/tkMacOSXPort.h b/macosx/tkMacOSXPort.h
index 1576ec7..0c3b347 100644
--- a/macosx/tkMacOSXPort.h
+++ b/macosx/tkMacOSXPort.h
@@ -141,18 +141,10 @@
/*
* This macro stores a representation of the window handle in a string.
- * This should perhaps use the real size of an XID.
*/
#define TkpPrintWindowId(buf,w) \
- sprintf((buf), "0x%x", (unsigned int) (w))
-
-/*
- * TkpScanWindowId is just an alias for Tcl_GetInt on Unix.
- */
-
-#define TkpScanWindowId(i,s,wp) \
- Tcl_GetInt((i),(s),(int *) (wp))
+ sprintf((buf), "0x%lx", (unsigned long) (w))
/*
* Turn off Tk double-buffering as Aqua windows are already double-buffered.
diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h
index 034c450..2a411f6 100644
--- a/macosx/tkMacOSXPrivate.h
+++ b/macosx/tkMacOSXPrivate.h
@@ -144,23 +144,6 @@
}
/*
- * Macros for GC
- */
-
-#define TkMacOSXMakeUncollectable(x) ({ id o = (id)(x); \
- if (o) { if(tkMacOSXGCEnabled) CFRetain(o); } o; })
-#define TkMacOSXMakeUncollectableAndRetain(x) ({ id o = (id)(x); \
- if (o) { if(tkMacOSXGCEnabled) CFRetain(o); else [o retain]; } o; })
-#define TkMacOSXMakeCollectable(x) ({ id o = (id)(x); \
- if (o) { x = nil; if (tkMacOSXGCEnabled) CFRelease(o); } o; })
-#define TkMacOSXMakeCollectableAndRelease(x) ({ id o = (id)(x); \
- if (o) { x = nil; if (tkMacOSXGCEnabled) CFRelease(o); \
- else [o release]; } o; })
-#define TkMacOSXMakeCollectableAndAutorelease(x) ({ id o = (id)(x); \
- if (o) { x = nil; if (tkMacOSXGCEnabled) CFRelease(o); \
- else [o autorelease]; } o; })
-
-/*
* Structure encapsulating current drawing environment.
*/
@@ -178,11 +161,7 @@ typedef struct TkMacOSXDrawingContext {
MODULE_SCOPE CGFloat tkMacOSXZeroScreenHeight;
MODULE_SCOPE CGFloat tkMacOSXZeroScreenTop;
-MODULE_SCOPE int tkMacOSXGCEnabled;
MODULE_SCOPE long tkMacOSXMacOSXVersion;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-MODULE_SCOPE int tkMacOSXUseCompatibilityMetrics;
-#endif
/*
* Prototypes for TkMacOSXRegion.c.
@@ -230,6 +209,8 @@ 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,
+ int x, int y, unsigned int width, unsigned int height);
MODULE_SCOPE int TkMacOSXSetupDrawingContext(Drawable d, GC gc,
int useCG, TkMacOSXDrawingContext *dcPtr);
MODULE_SCOPE void TkMacOSXRestoreDrawingContext(
@@ -293,10 +274,14 @@ VISIBILITY_HIDDEN
TKMenu *_defaultMainMenu, *_defaultApplicationMenu;
NSArray *_defaultApplicationMenuItems, *_defaultWindowsMenuItems;
NSArray *_defaultHelpMenuItems;
+ NSWindow *_windowWithMouse;
+ NSAutoreleasePool *_mainPool;
}
+@property BOOL poolProtected;
@end
@interface TKApplication(TKInit)
- (NSString *)tkFrameworkImagePath:(NSString*)image;
+- (void)_resetAutoreleasePool;
@end
@interface TKApplication(TKEvent)
- (NSEvent *)tkProcessEvent:(NSEvent *)theEvent;
@@ -314,13 +299,34 @@ VISIBILITY_HIDDEN
- (void)tkProvidePasteboard:(TkDisplay *)dispPtr;
- (void)tkCheckPasteboard;
@end
+@interface TKApplication(TKHLEvents)
+- (void) terminate: (id) sender;
+- (void) preferences: (id) sender;
+- (void) handleQuitApplicationEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent;
+- (void) handleOpenApplicationEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent;
+- (void) handleReopenApplicationEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent;
+- (void) handleShowPreferencesEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent;
+- (void) handleOpenDocumentsEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent;
+- (void) handlePrintDocumentsEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent;
+- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event
+ withReplyEvent: (NSAppleEventDescriptor *)replyEvent;
+@end
VISIBILITY_HIDDEN
@interface TKContentView : NSView <NSTextInput> {
@private
+ /*Remove private API calls.*/
+#if 0
id _savedSubviews;
BOOL _subviewsSetAside;
- NSString *_workingText;
+#endif
+ NSString *privateWorkingText;
}
@end
@@ -328,10 +334,27 @@ VISIBILITY_HIDDEN
- (void) deleteWorkingText;
@end
+@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;
+- (BOOL) wantsDefaultClipping;
+- (BOOL) acceptsFirstResponder;
+- (void) keyDown: (NSEvent *) theEvent;
+@end
+
VISIBILITY_HIDDEN
@interface TKWindow : NSWindow
@end
+@interface NSWindow(TKWm)
+- (NSPoint) convertPointToScreen:(NSPoint)point;
+- (NSPoint) convertPointFromScreen:(NSPoint)point;
+@end
+
#pragma mark NSMenu & NSMenuItem Utilities
@interface NSMenu(TKUtils)
@@ -360,9 +383,4 @@ VISIBILITY_HIDDEN
keyEquivalentModifierMask:(NSUInteger)keyEquivalentModifierMask;
@end
-/* From WebKit/WebKit/mac/WebCoreSupport/WebChromeClient.mm: */
-@interface NSWindow(TKGrowBoxRect)
-- (NSRect)_growBoxRect;
-@end
-
#endif /* _TKMACPRIV */
diff --git a/macosx/tkMacOSXRegion.c b/macosx/tkMacOSXRegion.c
index 8432299..0f2a74a 100644
--- a/macosx/tkMacOSXRegion.c
+++ b/macosx/tkMacOSXRegion.c
@@ -158,6 +158,29 @@ TkUnionRectWithRegion(
/*
*----------------------------------------------------------------------
*
+ * TkMacOSXIsEmptyRegion --
+ *
+ * Return native region for given tk region.
+ *
+ * Results:
+ * 1 if empty, 0 otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkMacOSXIsEmptyRegion(
+ TkRegion r)
+{
+ return HIShapeIsEmpty((HIMutableShapeRef) r) ? 1 : 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TkRectInRegion --
*
* Implements the equivelent of the X window function XRectInRegion. See
@@ -181,12 +204,14 @@ TkRectInRegion(
unsigned int width,
unsigned int height)
{
- int result;
- const CGRect r = CGRectMake(x, y, width, height);
-
- result = HIShapeIntersectsRect((HIShapeRef) region, &r) ?
+ if ( TkMacOSXIsEmptyRegion(region) ) {
+ return RectangleOut;
+ }
+ else {
+ const CGRect r = CGRectMake(x, y, width, height);
+ return HIShapeIntersectsRect((HIShapeRef) region, &r) ?
RectanglePart : RectangleOut;
- return result;
+ }
}
/*
@@ -332,12 +357,11 @@ TkpReleaseRegion(
{
CFRelease(r);
}
-#if 0
/*
*----------------------------------------------------------------------
*
- * TkMacOSXEmtpyRegion --
+ * TkMacOSXSetEmptyRegion --
*
* Set region to emtpy.
*
@@ -351,7 +375,7 @@ TkpReleaseRegion(
*/
void
-TkMacOSXEmtpyRegion(
+TkMacOSXSetEmptyRegion(
TkRegion r)
{
ChkErr(HIShapeSetEmpty, (HIMutableShapeRef) r);
@@ -360,30 +384,6 @@ TkMacOSXEmtpyRegion(
/*
*----------------------------------------------------------------------
*
- * TkMacOSXIsEmptyRegion --
- *
- * Return native region for given tk region.
- *
- * Results:
- * 1 if empty, 0 otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkMacOSXIsEmptyRegion(
- TkRegion r)
-{
- return HIShapeIsEmpty((HIMutableShapeRef) r) ? 1 : 0;
-}
-#endif
-
-/*
- *----------------------------------------------------------------------
- *
* TkMacOSXGetNativeRegion --
*
* Return native region for given tk region.
diff --git a/macosx/tkMacOSXScale.c b/macosx/tkMacOSXScale.c
index 0bca521..c5a6f76 100644
--- a/macosx/tkMacOSXScale.c
+++ b/macosx/tkMacOSXScale.c
@@ -145,7 +145,7 @@ TkpDisplayScale(
Tk_Window tkwin = scalePtr->tkwin;
Tcl_Interp *interp = scalePtr->interp;
int result;
- char string[PRINT_CHARS];
+ char string[TCL_DOUBLE_SPACE];
MacScale *macScalePtr = (MacScale *) clientData;
Rect r;
WindowRef windowRef;
diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c
index ac71d8e..91cf112 100644
--- a/macosx/tkMacOSXScrlbr.c
+++ b/macosx/tkMacOSXScrlbr.c
@@ -7,51 +7,41 @@
* Copyright (c) 1996 by Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
- *
+ * Copyright (c) 2015 Kevin Walzer/WordTech Commununications LLC.
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#include "tkMacOSXPrivate.h"
+#include "tkInt.h"
#include "tkScrollbar.h"
+#include "tkMacOSXPrivate.h"
-/*
-#ifdef TK_MAC_DEBUG
-#define TK_MAC_DEBUG_SCROLLBAR
-#endif
-*/
-/*
- * Declaration of Mac specific scrollbar structure.
- */
+#define MIN_SCROLLBAR_VALUE 0
-typedef struct MacScrollbar {
- TkScrollbar info;
- NSScroller *scroller;
- int variant;
-} MacScrollbar;
+/*Borrowed from ttkMacOSXTheme.c to provide appropriate scaling of scrollbar values.*/
+#ifdef __LP64__
+#define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum))
+#else
+#define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum))
+#endif /* __LP64__ */
-typedef struct ScrollbarMetrics {
- SInt32 width, minThumbHeight;
- int minHeight, topArrowHeight, bottomArrowHeight;
- NSControlSize controlSize;
-} ScrollbarMetrics;
-
-static ScrollbarMetrics metrics[2] = {
- {15, 54, 26, 14, 14, NSRegularControlSize}, /* kThemeScrollBarMedium */
- {11, 40, 20, 10, 10, NSSmallControlSize}, /* kThemeScrollBarSmall */
-};
+#define MOUNTAIN_LION_STYLE (NSAppKitVersionNumber < 1138)
/*
- * Declarations for functions defined in this file.
+ * Declaration of Mac specific scrollbar structure.
*/
-static void UpdateScrollbarMetrics(void);
-static void ScrollbarEventProc(ClientData clientData,
- XEvent *eventPtr);
+typedef struct MacScrollbar {
+ TkScrollbar information; /* Generic scrollbar info. */
+ GC troughGC; /* For drawing trough. */
+ GC copyGC; /* Used for copying from pixmap onto screen. */
+} MacScrollbar;
/*
- * The class procedure table for the scrollbar widget.
+ * The class procedure table for the scrollbar widget. All fields except size
+ * are left initialized to NULL, which should happen automatically since the
+ * variable is declared at this scope.
*/
const Tk_ClassProcs tkpScrollbarProcs = {
@@ -60,151 +50,37 @@ const Tk_ClassProcs tkpScrollbarProcs = {
NULL, /* createProc */
NULL /* modalProc */
};
-
-#pragma mark TKApplication(TKScrlbr)
-#define NSAppleAquaScrollBarVariantChanged @"AppleAquaScrollBarVariantChanged"
-@implementation TKApplication(TKScrlbr)
-- (void) tkScroller: (NSScroller *) scroller
-{
- NSScrollerPart hitPart = [scroller hitPart];
- TkScrollbar *scrollPtr = (TkScrollbar *)[scroller tag];
- Tcl_DString cmdString;
- Tcl_Interp *interp;
- int result;
-
- if (!scrollPtr || !scrollPtr->command || !scrollPtr->commandSize ||
- hitPart == NSScrollerNoPart) {
- return;
- }
-
- Tcl_DStringInit(&cmdString);
- Tcl_DStringAppend(&cmdString, scrollPtr->command,
- scrollPtr->commandSize);
- switch (hitPart) {
- case NSScrollerKnob:
- case NSScrollerKnobSlot: {
- char valueString[TCL_DOUBLE_SPACE];
-
- Tcl_PrintDouble(NULL, [scroller doubleValue] *
- (1.0 - [scroller knobProportion]), valueString);
- Tcl_DStringAppendElement(&cmdString, "moveto");
- Tcl_DStringAppendElement(&cmdString, valueString);
- break;
- }
- case NSScrollerDecrementLine:
- case NSScrollerIncrementLine:
- Tcl_DStringAppendElement(&cmdString, "scroll");
- Tcl_DStringAppendElement(&cmdString,
- (hitPart == NSScrollerDecrementLine) ? "-1" : "1");
- Tcl_DStringAppendElement(&cmdString, "unit");
- break;
- case NSScrollerDecrementPage:
- case NSScrollerIncrementPage:
- Tcl_DStringAppendElement(&cmdString, "scroll");
- Tcl_DStringAppendElement(&cmdString,
- (hitPart == NSScrollerDecrementPage) ? "-1" : "1");
- Tcl_DStringAppendElement(&cmdString, "page");
- break;
- }
- interp = scrollPtr->interp;
- Tcl_Preserve(interp);
- Tcl_Preserve(scrollPtr);
- result = Tcl_EvalEx(interp, Tcl_DStringValue(&cmdString),
- Tcl_DStringLength(&cmdString), TCL_EVAL_GLOBAL);
- if (result != TCL_OK && result != TCL_CONTINUE && result != TCL_BREAK) {
- Tcl_AddErrorInfo(interp, "\n (scrollbar command)");
- Tcl_BackgroundException(interp, result);
- }
- Tcl_Release(scrollPtr);
- Tcl_Release(interp);
- Tcl_DStringFree(&cmdString);
-#ifdef TK_MAC_DEBUG_SCROLLBAR
- TKLog(@"scroller %s value %f knobProportion %f",
- ((TkWindow *)scrollPtr->tkwin)->pathName, [scroller doubleValue],
- [scroller knobProportion]);
-#endif
-}
-
-- (void) scrollBarVariantChanged: (NSNotification *) notification
-{
-#ifdef TK_MAC_DEBUG_NOTIFICATIONS
- TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
-#endif
- UpdateScrollbarMetrics();
-}
+/*Information on scrollbar layout, metrics, and draw info.*/
+typedef struct ScrollbarMetrics {
+ SInt32 width, minThumbHeight;
+ int minHeight, topArrowHeight, bottomArrowHeight;
+ NSControlSize controlSize;
+} ScrollbarMetrics;
-- (void) _setupScrollBarNotifications
-{
- NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+static ScrollbarMetrics metrics[2] = {
+ {15, 54, 26, 14, 14, NSRegularControlSize}, /* kThemeScrollBarMedium */
+ {11, 40, 20, 10, 10, NSSmallControlSize}, /* kThemeScrollBarSmall */
+};
-#define observe(n, s) [nc addObserver:self selector:@selector(s) name:(n) object:nil]
- observe(NSAppleAquaScrollBarVariantChanged, scrollBarVariantChanged:);
-#undef observe
+HIThemeTrackDrawInfo info = {
+ .version = 0,
+ .min = 0.0,
+ .max = 100.0,
+ .attributes = kThemeTrackShowThumb,
+ .kind = kThemeScrollBarMedium,
+};
- UpdateScrollbarMetrics();
-}
-@end
-#pragma mark -
-
/*
- *----------------------------------------------------------------------
- *
- * UpdateScrollbarMetrics --
- *
- * This function retrieves the current system metrics for a scrollbar.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Updates the geometry cache info for all scrollbars.
- *
- *----------------------------------------------------------------------
+ * Forward declarations for procedures defined later in this file:
*/
-static void
-UpdateScrollbarMetrics(void)
-{
- const short height = 100, width = 50;
- HIThemeTrackDrawInfo info = {
- .version = 0,
- .bounds = {{0, 0}, {width, height}},
- .min = 0,
- .max = 1,
- .value = 0,
- .attributes = kThemeTrackShowThumb,
- .enableState = kThemeTrackActive,
- .trackInfo.scrollbar = {.viewsize = 1, .pressState = 0},
- };
- CGRect bounds;
-
- ChkErr(GetThemeMetric, kThemeMetricScrollBarWidth, &metrics[0].width);
- ChkErr(GetThemeMetric, kThemeMetricScrollBarMinThumbHeight,
- &metrics[0].minThumbHeight);
- info.kind = kThemeScrollBarMedium;
- ChkErr(HIThemeGetTrackDragRect, &info, &bounds);
- metrics[0].topArrowHeight = bounds.origin.y;
- metrics[0].bottomArrowHeight = height - (bounds.origin.y +
- bounds.size.height);
- metrics[0].minHeight = metrics[0].minThumbHeight +
- metrics[0].topArrowHeight + metrics[0].bottomArrowHeight;
- ChkErr(GetThemeMetric, kThemeMetricSmallScrollBarWidth, &metrics[1].width);
- ChkErr(GetThemeMetric, kThemeMetricSmallScrollBarMinThumbHeight,
- &metrics[1].minThumbHeight);
- info.kind = kThemeScrollBarSmall;
- ChkErr(HIThemeGetTrackDragRect, &info, &bounds);
- metrics[1].topArrowHeight = bounds.origin.y;
- metrics[1].bottomArrowHeight = height - (bounds.origin.y +
- bounds.size.height);
- metrics[1].minHeight = metrics[1].minThumbHeight +
- metrics[1].topArrowHeight + metrics[1].bottomArrowHeight;
-
- sprintf(tkDefScrollbarWidth, "%d", (int)(metrics[0].width));
-}
-
+static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr);
+static int ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr);
+static void UpdateControlValues(TkScrollbar *scrollPtr);
+
/*
*----------------------------------------------------------------------
*
@@ -223,41 +99,17 @@ UpdateScrollbarMetrics(void)
TkScrollbar *
TkpCreateScrollbar(
- Tk_Window tkwin)
+ Tk_Window tkwin)
{
- MacScrollbar *scrollPtr = ckalloc(sizeof(MacScrollbar));
- scrollPtr->scroller = nil;
- Tk_CreateEventHandler(tkwin, StructureNotifyMask|FocusChangeMask|
- ActivateMask|ExposureMask, ScrollbarEventProc, scrollPtr);
- return (TkScrollbar *) scrollPtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkpDestroyScrollbar --
- *
- * Free data structures associated with the scrollbar control.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
+ MacScrollbar *scrollPtr = (MacScrollbar *)ckalloc(sizeof(MacScrollbar));
-void
-TkpDestroyScrollbar(
- TkScrollbar *scrollPtr)
-{
- MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
- NSScroller *scroller = macScrollPtr->scroller;
- [scroller setTag:(NSInteger)0];
+ scrollPtr->troughGC = None;
+ scrollPtr->copyGC = None;
+
+ Tk_CreateEventHandler(tkwin,ExposureMask|StructureNotifyMask|FocusChangeMask|ButtonPressMask|VisibilityChangeMask, ScrollbarEventProc, scrollPtr);
- TkMacOSXMakeCollectableAndRelease(macScrollPtr->scroller);
+ return (TkScrollbar *) scrollPtr;
}
/*
@@ -266,8 +118,8 @@ TkpDestroyScrollbar(
* TkpDisplayScrollbar --
*
* This procedure redraws the contents of a scrollbar window. It is
- * invoked as a do-when-idle handler, so it only runs when there's nothing
- * else for the application to do.
+ * invoked as a do-when-idle handler, so it only runs when there's
+ * nothing else for the application to do.
*
* Results:
* None.
@@ -280,91 +132,68 @@ TkpDestroyScrollbar(
void
TkpDisplayScrollbar(
- ClientData clientData) /* Information about window. */
+ ClientData clientData) /* Information about window. */
{
- TkScrollbar *scrollPtr = clientData;
- MacScrollbar *macScrollPtr = clientData;
- NSScroller *scroller = macScrollPtr->scroller;
- Tk_Window tkwin = scrollPtr->tkwin;
+ register TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
+ register Tk_Window tkwin = scrollPtr->tkwin;
TkWindow *winPtr = (TkWindow *) tkwin;
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
TkMacOSXDrawingContext dc;
- NSView *view = TkMacOSXDrawableView(macWin);
- CGFloat viewHeight = [view bounds].size.height;
- CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
- .ty = viewHeight};
- NSRect frame;
- double knobProportion = scrollPtr->lastFraction - scrollPtr->firstFraction;
scrollPtr->flags &= ~REDRAW_PENDING;
- if (!scrollPtr->tkwin || !Tk_IsMapped(tkwin) || !view ||
- !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
- return;
+
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
+ }
+
+ MacDrawable *macWin = (MacDrawable *) winPtr->window;
+ NSView *view = TkMacOSXDrawableView(macWin);
+ if (!view ||
+ macWin->flags & TK_DO_NOT_DRAW ||
+ !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
+ return;
}
+
+ CGFloat viewHeight = [view bounds].size.height;
+ CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
+ .ty = viewHeight};
CGContextConcatCTM(dc.context, t);
+
+ /*Draw Unix-style scroll trough to provide rect for native scrollbar.*/
if (scrollPtr->highlightWidth != 0) {
- GC fgGC, bgGC;
-
- bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin);
- if (scrollPtr->flags & GOT_FOCUS) {
- fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin);
- } else {
- fgGC = bgGC;
- }
- TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth,
- (Pixmap) macWin);
+ GC fgGC, bgGC;
+
+ bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin);
+ if (scrollPtr->flags & GOT_FOCUS) {
+ fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin);
+ } else {
+ fgGC = bgGC;
+ }
+ TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth,
+ (Pixmap) macWin);
}
+
Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder,
- scrollPtr->highlightWidth, scrollPtr->highlightWidth,
- Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
- Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
- scrollPtr->borderWidth, scrollPtr->relief);
+ scrollPtr->highlightWidth, scrollPtr->highlightWidth,
+ Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
+ Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
+ scrollPtr->borderWidth, scrollPtr->relief);
Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder,
- scrollPtr->inset, scrollPtr->inset,
- Tk_Width(tkwin) - 2*scrollPtr->inset,
- Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT);
- if ([scroller superview] != view) {
- [view addSubview:scroller];
- }
- frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin),
- Tk_Height(tkwin));
- frame = NSInsetRect(frame, scrollPtr->inset, scrollPtr->inset);
- frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
-
- NSWindow *w = [view window];
-
- if ([w showsResizeIndicator]) {
- NSRect growBox = [view convertRect:[w _growBoxRect] fromView:nil];
-
- if (NSIntersectsRect(growBox, frame)) {
- if (scrollPtr->vertical) {
- CGFloat y = frame.origin.y;
-
- frame.origin.y = growBox.origin.y + growBox.size.height;
- frame.size.height -= frame.origin.y - y;
- } else {
- frame.size.width = growBox.origin.x - frame.origin.x;
- }
- TkMacOSXSetScrollbarGrow(winPtr, true);
- }
- }
- if (!NSEqualRects(frame, [scroller frame])) {
- [scroller setFrame:frame];
+ scrollPtr->inset, scrollPtr->inset,
+ Tk_Width(tkwin) - 2*scrollPtr->inset,
+ Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT);
+
+ /*Update values and draw in native rect.*/
+ UpdateControlValues(scrollPtr);
+ if (MOUNTAIN_LION_STYLE) {
+ HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationInverted);
+ } else {
+ HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal);
}
- [scroller setEnabled:(knobProportion < 1.0 &&
- (scrollPtr->vertical ? frame.size.height : frame.size.width) >
- metrics[macScrollPtr->variant].minHeight)];
- [scroller setDoubleValue:scrollPtr->firstFraction / (1.0 - knobProportion)];
- [scroller setKnobProportion:knobProportion];
- [scroller displayRectIgnoringOpacity:[scroller bounds]];
TkMacOSXRestoreDrawingContext(&dc);
-#ifdef TK_MAC_DEBUG_SCROLLBAR
- TKLog(@"scroller %s frame %@ width %d height %d",
- ((TkWindow *)scrollPtr->tkwin)->pathName, NSStringFromRect(frame),
- Tk_Width(tkwin), Tk_Height(tkwin));
-#endif
+
+ scrollPtr->flags &= ~REDRAW_PENDING;
}
-
+
/*
*----------------------------------------------------------------------
*
@@ -383,123 +212,107 @@ TkpDisplayScrollbar(
*----------------------------------------------------------------------
*/
-void
+extern void
TkpComputeScrollbarGeometry(
- register TkScrollbar *scrollPtr)
- /* Scrollbar whose geometry may have
- * changed. */
+ register TkScrollbar *scrollPtr)
+/* Scrollbar whose geometry may have
+ * changed. */
{
- MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
- NSScroller *scroller = macScrollPtr->scroller;
- int width, height, variant, fieldLength;
+
+ int variant, fieldLength;
if (scrollPtr->highlightWidth < 0) {
- scrollPtr->highlightWidth = 0;
+ scrollPtr->highlightWidth = 0;
}
scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
- width = Tk_Width(scrollPtr->tkwin) - 2 * scrollPtr->inset;
- height = Tk_Height(scrollPtr->tkwin) - 2 * scrollPtr->inset;
- variant = ((scrollPtr->vertical ? width : height) < metrics[0].width) ?
- 1 : 0;
- macScrollPtr->variant = variant;
- if (scroller) {
- NSSize size = [scroller frame].size;
-
- if ((size.width > size.height) ^ !scrollPtr->vertical) {
- /*
- * Orientation changed, need new scroller.
- */
-
- if ([scroller superview]) {
- [scroller removeFromSuperviewWithoutNeedingDisplay];
- }
- TkMacOSXMakeCollectableAndRelease(scroller);
- }
- }
- if (!scroller) {
- if ((width > height) ^ !scrollPtr->vertical) {
- /* -[NSScroller initWithFrame:] determines horizonalness for the
- * lifetime of the scroller via isHoriz = (width > height) */
- if (scrollPtr->vertical) {
- width = height;
- } else if (width > 1) {
- height = width - 1;
- } else {
- height = 1;
- width = 2;
- }
- }
- scroller = [[NSScroller alloc] initWithFrame:
- NSMakeRect(0, 0, width, height)];
- macScrollPtr->scroller = TkMacOSXMakeUncollectable(scroller);
- [scroller setAction:@selector(tkScroller:)];
- [scroller setTarget:NSApp];
- [scroller setTag:(NSInteger)scrollPtr];
- }
- [[scroller cell] setControlSize:metrics[variant].controlSize];
-
+ variant = ((scrollPtr->vertical ? Tk_Width(scrollPtr->tkwin) :
+ Tk_Height(scrollPtr->tkwin)) - 2 * scrollPtr->inset
+ < metrics[0].width) ? 1 : 0;
scrollPtr->arrowLength = (metrics[variant].topArrowHeight +
- metrics[variant].bottomArrowHeight) / 2;
+ metrics[variant].bottomArrowHeight) / 2;
fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
- : Tk_Width(scrollPtr->tkwin))
- - 2 * (scrollPtr->arrowLength + scrollPtr->inset);
+ : Tk_Width(scrollPtr->tkwin))
+ - 2 * (scrollPtr->arrowLength + scrollPtr->inset);
if (fieldLength < 0) {
- fieldLength = 0;
+ fieldLength = 0;
}
scrollPtr->sliderFirst = fieldLength * scrollPtr->firstFraction;
scrollPtr->sliderLast = fieldLength * scrollPtr->lastFraction;
/*
- * Adjust the slider so that some piece of it is always displayed in the
- * scrollbar and so that it has at least a minimal width (so it can be
- * grabbed with the mouse).
+ * Adjust the slider so that some piece of it is always
+ * displayed in the scrollbar and so that it has at least
+ * a minimal width (so it can be grabbed with the mouse).
*/
if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) {
- scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
+ scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
}
if (scrollPtr->sliderFirst < 0) {
- scrollPtr->sliderFirst = 0;
+ scrollPtr->sliderFirst = 0;
}
if (scrollPtr->sliderLast < (scrollPtr->sliderFirst +
- metrics[variant].minThumbHeight)) {
- scrollPtr->sliderLast = scrollPtr->sliderFirst +
- metrics[variant].minThumbHeight;
+ metrics[variant].minThumbHeight)) {
+ scrollPtr->sliderLast = scrollPtr->sliderFirst +
+ metrics[variant].minThumbHeight;
}
if (scrollPtr->sliderLast > fieldLength) {
- scrollPtr->sliderLast = fieldLength;
+ scrollPtr->sliderLast = fieldLength;
+ }
+ if (!(MOUNTAIN_LION_STYLE)) {
+ scrollPtr->sliderFirst += scrollPtr->inset +
+ metrics[variant].topArrowHeight;
+ scrollPtr->sliderLast += scrollPtr->inset +
+ metrics[variant].bottomArrowHeight;
}
- scrollPtr->sliderFirst += scrollPtr->inset +
- metrics[variant].topArrowHeight;
- scrollPtr->sliderLast += scrollPtr->inset +
- metrics[variant].bottomArrowHeight;
-
/*
- * 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.
+ * 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.
*/
if (scrollPtr->vertical) {
- Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width +
- 2 * scrollPtr->inset, 2 * (scrollPtr->arrowLength +
- scrollPtr->borderWidth + scrollPtr->inset) +
- metrics[variant].minThumbHeight);
+ Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width + 2 * scrollPtr->inset, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics[variant].minThumbHeight);
} else {
- Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength +
- scrollPtr->borderWidth + scrollPtr->inset) +
- metrics[variant].minThumbHeight, scrollPtr->width +
- 2 * scrollPtr->inset);
+ Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics[variant].minThumbHeight, scrollPtr->width + 2 * scrollPtr->inset);
}
Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset);
-#ifdef TK_MAC_DEBUG_SCROLLBAR
- TKLog(@"scroller %s bounds %@ width %d height %d inset %d borderWidth %d",
- ((TkWindow *)scrollPtr->tkwin)->pathName,
- NSStringFromRect([scroller bounds]),
- width, height, scrollPtr->inset, scrollPtr->borderWidth);
-#endif
+
}
-
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpDestroyScrollbar --
+ *
+ * Free data structures associated with the scrollbar control.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Frees the GCs associated with the scrollbar.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpDestroyScrollbar(
+ TkScrollbar *scrollPtr)
+{
+ MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr;
+
+ if (macScrollPtr->troughGC != None) {
+ Tk_FreeGC(scrollPtr->display, macScrollPtr->troughGC);
+ }
+ if (macScrollPtr->copyGC != None) {
+ Tk_FreeGC(scrollPtr->display, macScrollPtr->copyGC);
+ }
+
+ macScrollPtr=NULL;
+}
+
/*
*----------------------------------------------------------------------
*
@@ -513,19 +326,20 @@ TkpComputeScrollbarGeometry(
* None.
*
* Side effects:
- * None.
+ * Configuration info may get changed.
*
*----------------------------------------------------------------------
*/
void
TkpConfigureScrollbar(
- register TkScrollbar *scrollPtr)
- /* Information about widget; may or may not
- * already have values for some fields. */
+ register TkScrollbar *scrollPtr)
+/* Information about widget; may or may not
+ * already have values for some fields. */
{
+
}
-
+
/*
*--------------------------------------------------------------
*
@@ -550,30 +364,174 @@ TkpScrollbarPosition(
/* Scrollbar widget record. */
int x, int y) /* Coordinates within scrollPtr's window. */
{
- NSScroller *scroller = ((MacScrollbar *) scrollPtr)->scroller;
- MacDrawable *macWin = (MacDrawable *)
- ((TkWindow *) scrollPtr->tkwin)->window;
- NSView *view = TkMacOSXDrawableView(macWin);
- switch ([scroller testPart:NSMakePoint(macWin->xOff + x,
- [view bounds].size.height - (macWin->yOff + y))]) {
- case NSScrollerDecrementLine:
- return TOP_ARROW;
- case NSScrollerDecrementPage:
+ /*
+ * Using code from tkUnixScrlbr.c because Unix scroll bindings are
+ * driving the display at the script level. All the Mac scrollbar
+ * has to do is re-draw itself.
+ */
+
+ int length, fieldlength, width, tmp;
+ register const int inset = scrollPtr->inset;
+ register const int arrowSize = scrollPtr->arrowLength + inset;
+
+ if (scrollPtr->vertical) {
+ 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);
+ }
+ fieldlength = fieldlength < 0 ? 0 : fieldlength;
+
+ if (x<inset || x>=width-inset || y<inset || y>=length-inset) {
+ return OUTSIDE;
+ }
+
+ /*
+ * All of the calculations in this procedure mirror those in
+ * TkpDisplayScrollbar. Be sure to keep the two consistent.
+ */
+
+ if (y < scrollPtr->sliderFirst) {
return TOP_GAP;
- case NSScrollerKnob:
+ }
+ if (y < scrollPtr->sliderLast) {
return SLIDER;
- case NSScrollerIncrementPage:
+ }
+ if (y < fieldlength){
return BOTTOM_GAP;
- case NSScrollerIncrementLine:
- return BOTTOM_ARROW;
- case NSScrollerKnobSlot:
- case NSScrollerNoPart:
- default:
- return OUTSIDE;
}
+ if (y < fieldlength + arrowSize) {
+ return TOP_ARROW;
+ }
+ return BOTTOM_ARROW;
}
-
+
+/*
+ *--------------------------------------------------------------
+ *
+ * UpdateControlValues --
+ *
+ * This procedure updates the Macintosh scrollbar control to
+ * display the values defined by the Tk scrollbar. This is the
+ * key interface to the Mac-native * scrollbar; the Unix bindings
+ * drive scrolling in the Tk window and all the Mac scrollbar has
+ * to do is redraw itself.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The Macintosh control is updated.
+ *
+ *--------------------------------------------------------------
+ */
+
+static void
+UpdateControlValues(
+ TkScrollbar *scrollPtr) /* Scrollbar data struct. */
+{
+ Tk_Window tkwin = scrollPtr->tkwin;
+ MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin);
+ double dViewSize;
+ HIRect contrlRect;
+ int variant;
+ short width, height;
+
+ NSView *view = TkMacOSXDrawableView(macWin);
+ CGFloat viewHeight = [view bounds].size.height;
+ NSRect frame;
+ frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin),
+ Tk_Height(tkwin));
+ frame = NSInsetRect(frame, scrollPtr->inset, scrollPtr->inset);
+ frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
+
+ contrlRect = NSRectToCGRect(frame);
+ info.bounds = contrlRect;
+
+ width = contrlRect.size.width;
+ height = contrlRect.size.height;
+
+ variant = contrlRect.size.width < metrics[0].width ? 1 : 0;
+
+ /*
+ * Ensure we set scrollbar control bounds only once all size adjustments
+ * have been computed.
+ */
+
+ info.bounds = contrlRect;
+ if (scrollPtr->vertical) {
+ info.attributes &= ~kThemeTrackHorizontal;
+ } else {
+ info.attributes |= kThemeTrackHorizontal;
+ }
+
+ /*
+ * Given the Tk parameters for the fractions of the start and end of the
+ * thumb, the following calculation determines the location for the
+ * Macintosh thumb. The Aqua scroll control works as follows. The
+ * scrollbar's value is the position of the left (or top) side of the view
+ * area in the content area being scrolled. The maximum value of the
+ * control is therefore the dimension of the content area less the size of
+ * the view area.
+ */
+
+ double maximum = 100, factor;
+ factor = RangeToFactor(maximum);
+ dViewSize = (scrollPtr->lastFraction - scrollPtr->firstFraction)
+ * factor;
+ info.max = MIN_SCROLLBAR_VALUE +
+ factor - dViewSize;
+ info.trackInfo.scrollbar.viewsize = dViewSize;
+ if (scrollPtr->vertical) {
+ if (MOUNTAIN_LION_STYLE) {
+ info.value = factor * scrollPtr->firstFraction;
+ } else {
+ info.value = info.max - factor * scrollPtr->firstFraction;
+ }
+ } else {
+ info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction;
+ }
+
+ if((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0)
+ || height <= metrics[variant].minHeight) {
+ info.enableState = kThemeTrackHideTrack;
+ } else {
+ info.enableState = kThemeTrackActive;
+ info.attributes = kThemeTrackShowThumb | kThemeTrackThumbRgnIsNotGhost;
+ }
+
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ScrollbarPress --
+ *
+ * This procedure is invoked in response to <ButtonPress> events.
+ * Enters a modal loop to handle scrollbar interactions.
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr)
+{
+
+ if (eventPtr->type == ButtonPress) {
+ UpdateControlValues(scrollPtr);
+ }
+ return TCL_OK;
+}
+
+
+
/*
*--------------------------------------------------------------
*
@@ -594,8 +552,8 @@ TkpScrollbarPosition(
static void
ScrollbarEventProc(
- ClientData clientData, /* Information about window. */
- XEvent *eventPtr) /* Information about event. */
+ ClientData clientData, /* Information about window. */
+ XEvent *eventPtr) /* Information about event. */
{
TkScrollbar *scrollPtr = clientData;
@@ -607,16 +565,10 @@ ScrollbarEventProc(
case DeactivateNotify:
TkScrollbarEventuallyRedraw(scrollPtr);
break;
+ case ButtonPress:
+ ScrollbarPress(clientData, eventPtr);
+ break;
default:
TkScrollbarEventProc(clientData, eventPtr);
}
}
-
-/*
- * Local Variables:
- * mode: objc
- * c-basic-offset: 4
- * fill-column: 79
- * coding: utf-8
- * End:
- */
diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c
index 18276fb..f026318 100644
--- a/macosx/tkMacOSXSubwindows.c
+++ b/macosx/tkMacOSXSubwindows.c
@@ -149,8 +149,11 @@ XMapWindow(
if (Tk_IsTopLevel(macWin->winPtr)) {
if (!Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *win = TkMacOSXDrawableWindow(window);
-
- [win makeKeyAndOrderFront:NSApp];
+ [NSApp activateIgnoringOtherApps:YES];
+ if ( [win canBecomeKeyWindow] ) {
+ [win makeKeyAndOrderFront:NSApp];
+ }
+ /* Why do we need this? (It is used by Carbon)*/
[win windowRef];
TkMacOSXApplyWindowAttributes(macWin->winPtr, win);
}
@@ -310,7 +313,6 @@ XResizeWindow(
unsigned int height)
{
MacDrawable *macWin = (MacDrawable *) window;
-
display->request++;
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
@@ -357,7 +359,6 @@ XMoveResizeWindow(
display->request++;
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
-
if (w) {
NSRect r = NSMakeRect(x + macWin->winPtr->wmInfoPtr->xInParent,
tkMacOSXZeroScreenHeight - (y +
@@ -398,7 +399,6 @@ XMoveWindow(
display->request++;
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
-
if (w) {
[w setFrameTopLeftPoint:NSMakePoint(x, tkMacOSXZeroScreenHeight - y)];
}
@@ -649,9 +649,68 @@ XConfigureWindow(
/*
*----------------------------------------------------------------------
*
+ * TkMacOSXSetDrawingEnabled --
+ *
+ * This function sets the TK_DO_NOT_DRAW flag for a given window and
+ * all of its children.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The clipping regions for the window and its children are cleared.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkMacOSXSetDrawingEnabled(
+ TkWindow *winPtr,
+ int flag)
+{
+ TkWindow *childPtr;
+ MacDrawable *macWin = winPtr->privatePtr;
+
+ if (macWin) {
+ if (flag ) {
+ macWin->flags &= ~TK_DO_NOT_DRAW;
+ } else {
+ macWin->flags |= TK_DO_NOT_DRAW;
+ }
+ }
+
+ /*
+ * Set the flag for all children & their descendants, excluding
+ * Toplevels. (??? Do we need to exclude Toplevels?)
+ */
+
+ childPtr = winPtr->childList;
+ while (childPtr) {
+ if (!Tk_IsTopLevel(childPtr)) {
+ TkMacOSXSetDrawingEnabled(childPtr, flag);
+ }
+ childPtr = childPtr->nextPtr;
+ }
+
+ /*
+ * If the window is a container, set the flag for its embedded window.
+ */
+
+ if (Tk_IsContainer(winPtr)) {
+ childPtr = TkpGetOtherWindow(winPtr);
+
+ if (childPtr) {
+ TkMacOSXSetDrawingEnabled(childPtr, flag);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TkMacOSXUpdateClipRgn --
*
- * This function updates the cliping regions for a given window and all of
+ * This function updates the clipping regions for a given window and all of
* its children. Once updated the TK_CLIP_INVALID flag in the subwindow
* data structure is unset. The TK_CLIP_INVALID flag should always be
* unset before any drawing is attempted.
@@ -738,17 +797,6 @@ TkMacOSXUpdateClipRgn(
/*
* TODO: Here we should handle out of process embedding.
*/
- } else if (winPtr->wmInfoPtr->attributes &
- kWindowResizableAttribute) {
- NSWindow *w = TkMacOSXDrawableWindow(winPtr->window);
-
- if (w) {
- bounds = NSRectToCGRect([w _growBoxRect]);
- bounds.origin.y = [w contentRectForFrameRect:
- [w frame]].size.height - bounds.size.height -
- bounds.origin.y;
- ChkErr(TkMacOSHIShapeDifferenceWithRect, rgn, &bounds);
- }
}
macWin->aboveVisRgn = HIShapeCreateCopy(rgn);
@@ -825,7 +873,7 @@ TkMacOSXUpdateClipRgn(
*
* TkMacOSXVisableClipRgn --
*
- * This function returns the Macintosh cliping region for the given
+ * This function returns the Macintosh clipping region for the given
* window. The caller is responsible for disposing of the returned
* region via TkDestroyRegion().
*
@@ -920,7 +968,7 @@ TkMacOSXInvalidateWindow(
* TK_PARENT_WINDOW */
{
#ifdef TK_MAC_DEBUG_CLIP_REGIONS
- TkMacOSXDbgMsg("%s", winPtr->pathName);
+ TkMacOSXDbgMsg("%s", macWin->winPtr->pathName);
#endif
if (macWin->flags & TK_CLIP_INVALID) {
TkMacOSXUpdateClipRgn(macWin->winPtr);
@@ -1078,7 +1126,7 @@ TkMacOSXGetRootControl(
* None.
*
* Side effects:
- * The cliping regions for the window and its children are mark invalid.
+ * The clipping regions for the window and its children are marked invalid.
* (Make sure they are valid before drawing.)
*
*----------------------------------------------------------------------
@@ -1097,6 +1145,10 @@ TkMacOSXInvalClipRgns(
* be marked.
*/
+#ifdef TK_MAC_DEBUG_CLIP_REGIONS
+ TkMacOSXDbgMsg("%s", winPtr->pathName);
+#endif
+
if (!macWin || macWin->flags & TK_CLIP_INVALID) {
return;
}
@@ -1277,7 +1329,7 @@ UpdateOffsets(
* Returns a handle to a new pixmap.
*
* Side effects:
- * Allocates a new Macintosh GWorld.
+ * Allocates a new CGBitmapContext.
*
*----------------------------------------------------------------------
*/
@@ -1323,7 +1375,7 @@ Tk_GetPixmap(
* None.
*
* Side effects:
- * Deletes the Macintosh GWorld created by Tk_GetPixmap.
+ * Deletes the CGBitmapContext created by Tk_GetPixmap.
*
*----------------------------------------------------------------------
*/
diff --git a/macosx/tkMacOSXTest.c b/macosx/tkMacOSXTest.c
index 7d2b24e..1882ce6 100644
--- a/macosx/tkMacOSXTest.c
+++ b/macosx/tkMacOSXTest.c
@@ -18,8 +18,8 @@
* Forward declarations of procedures defined later in this file:
*/
-static int DebuggerCmd (ClientData dummy, Tcl_Interp *interp,
- int argc, const char **argv);
+static int DebuggerObjCmd (ClientData dummy, Tcl_Interp *interp,
+ int objc, Tcl_Obj *const objv[]);
/*
*----------------------------------------------------------------------
@@ -46,7 +46,7 @@ TkplatformtestInit(
* Add commands for platform specific tests on MacOS here.
*/
- Tcl_CreateCommand(interp, "debugger", DebuggerCmd,
+ Tcl_CreateObjCommand(interp, "debugger", DebuggerObjCmd,
(ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
return TCL_OK;
@@ -55,7 +55,7 @@ TkplatformtestInit(
/*
*----------------------------------------------------------------------
*
- * DebuggerCmd --
+ * DebuggerObjCmd --
*
* This procedure simply calls the low level debugger.
*
@@ -69,11 +69,11 @@ TkplatformtestInit(
*/
static int
-DebuggerCmd(
+DebuggerObjCmd(
ClientData clientData, /* Not used. */
Tcl_Interp *interp, /* Not used. */
- int argc, /* Not used. */
- const char **argv) /* Not used. */
+ int objc, /* Not used. */
+ Tcl_Obj *const objv[]) /* Not used. */
{
Debugger();
return TCL_OK;
diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c
index 9402cbb..461a94c 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -6,6 +6,8 @@
*
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright (c) 2015 Kevin Walzer/WordTech Communications LLC.
+ * Copyright (c) 2015 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -27,7 +29,7 @@
* Declaration of functions used only in this file
*/
-static int GenerateUpdates(HIMutableShapeRef updateRgn,
+static int GenerateUpdates(HIShapeRef updateRgn,
CGRect *updateBounds, TkWindow *winPtr);
static int GenerateActivateEvents(TkWindow *winPtr,
int activeFlag);
@@ -46,7 +48,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
#endif
#endif
-extern NSString *opaqueTag;
+extern BOOL opaqueTag;
@implementation TKApplication(TKWindowEvent)
@@ -163,6 +165,10 @@ extern NSString *opaqueTag;
if (winPtr) {
TkGenWMDestroyEvent((Tk_Window) winPtr);
+ if (_windowWithMouse == w) {
+ _windowWithMouse = nil;
+ [w release];
+ }
}
/*
@@ -266,9 +272,8 @@ extern NSString *opaqueTag;
const char *cmd = ([[notification name] isEqualToString:
NSApplicationDidUnhideNotification] ?
"::tk::mac::OnShow" : "::tk::mac::OnHide");
- Tcl_CmdInfo dummy;
- if (_eventInterp && Tcl_GetCommandInfo(_eventInterp, cmd, &dummy)) {
+ if (_eventInterp && Tcl_FindCommand(_eventInterp, cmd, NULL, 0)) {
int code = Tcl_EvalEx(_eventInterp, cmd, -1, TCL_EVAL_GLOBAL);
if (code != TCL_OK) {
@@ -314,7 +319,7 @@ extern NSString *opaqueTag;
static int
GenerateUpdates(
- HIMutableShapeRef updateRgn,
+ HIShapeRef updateRgn,
CGRect *updateBounds,
TkWindow *winPtr)
{
@@ -357,11 +362,12 @@ GenerateUpdates(
event.xexpose.width = damageBounds.size.width;
event.xexpose.height = damageBounds.size.height;
event.xexpose.count = 0;
- Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
-#ifdef TK_MAC_DEBUG_DRAWING
- TKLog(@"Expose %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x,
+ Tk_HandleEvent(&event);
+
+ #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
@@ -743,15 +749,16 @@ TkWmProtocolEventProc(
int
Tk_MacOSXIsAppInFront(void)
{
- OSStatus err;
- ProcessSerialNumber frontPsn, ourPsn = {0, kCurrentProcess};
Boolean isFrontProcess = true;
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+ ProcessSerialNumber frontPsn, ourPsn = {0, kCurrentProcess};
- err = ChkErr(GetFrontProcess, &frontPsn);
- if (err == noErr) {
- ChkErr(SameProcess, &frontPsn, &ourPsn, &isFrontProcess);
+ if (noErr == GetFrontProcess(&frontPsn)){
+ SameProcess(&frontPsn, &ourPsn, &isFrontProcess);
}
-
+#else
+ isFrontProcess = [NSRunningApplication currentApplication].active;
+#endif
return (isFrontProcess == true);
}
@@ -760,27 +767,25 @@ Tk_MacOSXIsAppInFront(void)
#import <ApplicationServices/ApplicationServices.h>
/*
- * Custom content view for Tk NSWindows, containing standard NSView subviews.
- * The goal is to emulate X11-style drawing in response to Expose events:
- * during the normal AppKit drawing cycle, we supress drawing of all subviews
- * (using a technique adapted from WebKit's WebHTMLView) and instead send
- * Expose events about the subviews that would be redrawn. Tk Expose event
- * handling and drawing handlers then draw the subviews manually via their
- * -displayRectIgnoringOpacity:
+ * Custom content view for use in Tk NSWindows.
+ *
+ * Since Tk handles all drawing of widgets, we only use the AppKit event loop
+ * as a source of input events. To do this, we overload the NSView drawRect
+ * method with a method which generates Expose events for Tk but does no
+ * drawing. The redrawing operations are then done when Tk processes these
+ * events.
+ *
+ * Earlier versions of Mac Tk used subclasses of NSView, e.g. NSButton, as the
+ * basis for Tk widgets. These would then appear as subviews of the
+ * TKContentView. To prevent the AppKit from redrawing and corrupting the Tk
+ * Widgets it was necessary to use Apple private API calls. In order to avoid
+ * using private API calls, the NSView-based widgets have been replaced with
+ * normal Tk widgets which draw themselves as native widgets by using the
+ * HITheme API.
+ *
*/
-@interface TKContentView(TKWindowEvent)
-- (void) drawRect: (NSRect) rect;
-- (void) generateExposeEvents: (HIMutableShapeRef) shape;
-- (BOOL) isOpaque;
-- (BOOL) wantsDefaultClipping;
-- (BOOL) acceptsFirstResponder;
-- (void) keyDown: (NSEvent *) theEvent;
-@end
-
-@implementation TKContentView
-@end
-
+/*Restrict event processing to Expose events.*/
static Tk_RestrictAction
ExposeRestrictProc(
ClientData arg,
@@ -790,6 +795,15 @@ ExposeRestrictProc(
? TK_PROCESS_EVENT : TK_DEFER_EVENT);
}
+/*Restrict event processing to ConfigureNotify events.*/
+static Tk_RestrictAction
+ConfigureRestrictProc(
+ ClientData arg,
+ XEvent *eventPtr)
+{
+ return (eventPtr->type==ConfigureNotify ? TK_PROCESS_EVENT : TK_DEFER_EVENT);
+}
+
@implementation TKContentView(TKWindowEvent)
- (void) drawRect: (NSRect) rect
@@ -798,6 +812,7 @@ ExposeRestrictProc(
NSInteger rectsBeingDrawnCount;
[self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount];
+
#ifdef TK_MAC_DEBUG_DRAWING
TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, NSStringFromRect(rect));
[[NSColor colorWithDeviceRed:0.0 green:1.0 blue:0.0 alpha:.1] setFill];
@@ -805,73 +820,135 @@ ExposeRestrictProc(
NSCompositeSourceOver);
#endif
- NSWindow *w = [self window];
-
- if ([self isOpaque] && [w showsResizeIndicator]) {
- NSRect bounds = [self convertRect:[w _growBoxRect] fromView:nil];
-
- if ([self needsToDrawRect:bounds]) {
- NSEraseRect(bounds);
- }
- }
-
CGFloat height = [self bounds].size.height;
HIMutableShapeRef drawShape = HIShapeCreateMutable();
while (rectsBeingDrawnCount--) {
CGRect r = NSRectToCGRect(*rectsBeingDrawn++);
-
r.origin.y = height - (r.origin.y + r.size.height);
HIShapeUnionWithRect(drawShape, &r);
}
if (CFRunLoopGetMain() == CFRunLoopGetCurrent()) {
- [self generateExposeEvents:drawShape];
+ [self generateExposeEvents:(HIShapeRef)drawShape];
} else {
[self performSelectorOnMainThread:@selector(generateExposeEvents:)
withObject:(id)drawShape waitUntilDone:NO
modes:[NSArray arrayWithObjects:NSRunLoopCommonModes,
+
NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode,
nil]];
}
+
CFRelease(drawShape);
}
-- (void) generateExposeEvents: (HIMutableShapeRef) shape
+-(void) setFrameSize: (NSSize)newsize
+{
+ [super setFrameSize: newsize];
+ if ([self inLiveResize]) {
+ NSWindow *w = [self window];
+ TkWindow *winPtr = TkMacOSXGetTkWindow(w);
+ Tk_Window tkwin = (Tk_Window) winPtr;
+ unsigned int width = (unsigned int)newsize.width;
+ unsigned int height=(unsigned int)newsize.height;
+ ClientData oldArg;
+ Tk_RestrictProc *oldProc;
+
+ /* This can be called from outside the Tk event loop.
+ * Since it calls Tcl_DoOneEvent, we need to make sure we
+ * don't clobber the AutoreleasePool set up by the caller.
+ */
+ [NSApp setPoolProtected:YES];
+
+ /*
+ * Try to prevent flickers and flashes.
+ */
+ [w disableFlushWindow];
+ NSDisableScreenUpdates();
+
+ /* Disable Tk drawing until the window has been completely configured.*/
+ TkMacOSXSetDrawingEnabled(winPtr, 0);
+
+ /* Generate and handle a ConfigureNotify event for the new size.*/
+ TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height,
+ TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY);
+ oldProc = Tk_RestrictEvents(ConfigureRestrictProc, NULL, &oldArg);
+ while (Tk_DoOneEvent(TK_X_EVENTS|TK_DONT_WAIT)) {}
+ Tk_RestrictEvents(oldProc, oldArg, &oldArg);
+
+ /* Now that Tk has configured all subwindows we can create the clip regions. */
+ TkMacOSXSetDrawingEnabled(winPtr, 1);
+ TkMacOSXInvalClipRgns(tkwin);
+ TkMacOSXUpdateClipRgn(winPtr);
+
+ /* Finally, generate and process expose events to redraw the window. */
+ HIRect bounds = NSRectToCGRect([self bounds]);
+ HIShapeRef shape = HIShapeCreateWithRect(&bounds);
+ [self generateExposeEvents: shape];
+ while (Tk_DoOneEvent(TK_ALL_EVENTS|TK_DONT_WAIT)) {}
+ [w enableFlushWindow];
+ [w flushWindowIfNeeded];
+ NSEnableScreenUpdates();
+ [NSApp setPoolProtected:NO];
+ }
+}
+
+/*
+ * As insurance against bugs that might cause layout glitches during a live
+ * resize, we redraw the window one more time at the end of the resize
+ * operation.
+ */
+
+- (void)viewDidEndLiveResize
+{
+ HIRect bounds = NSRectToCGRect([self bounds]);
+ HIShapeRef shape = HIShapeCreateWithRect(&bounds);
+ [super viewDidEndLiveResize];
+ [self generateExposeEvents: shape];
+}
+
+/* Core method of this class: generates expose events for redrawing. If the
+ * Tcl_ServiceMode is set to TCL_SERVICE_ALL then the expose events will be
+ * immediately removed from the Tcl event loop and processed. Typically, they
+ * should be queued, however.
+ */
+- (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;
if (!winPtr) {
- return;
+ return;
}
+
+ /* Generate Tk Expose events. */
HIShapeGetBounds(shape, &updateBounds);
+ /* All of these events will share the same serial number. */
serial = LastKnownRequestProcessed(Tk_Display(winPtr));
- if (GenerateUpdates(shape, &updateBounds, winPtr) &&
- ![[NSRunLoop currentRunLoop] currentMode] &&
- Tcl_GetServiceMode() != TCL_SERVICE_NONE) {
- /*
- * Ensure there are no pending idle-time redraws that could prevent the
- * just posted Expose events from generating new redraws.
- */
-
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
-
- /*
- * For smoother drawing, process Expose events and resulting redraws
- * immediately instead of at idle time.
- */
+ updatesNeeded = GenerateUpdates(shape, &updateBounds, winPtr);
+ /* Process the Expose events if the service mode is TCL_SERVICE_ALL */
+ if (updatesNeeded && Tcl_GetServiceMode() == TCL_SERVICE_ALL) {
ClientData oldArg;
- Tk_RestrictProc *oldProc = Tk_RestrictEvents(ExposeRestrictProc,
- UINT2PTR(serial), &oldArg);
-
- while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {}
- Tk_RestrictEvents(oldProc, oldArg, &oldArg);
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
+ Tk_RestrictProc *oldProc = Tk_RestrictEvents(ExposeRestrictProc,
+ UINT2PTR(serial), &oldArg);
+ while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {}
+ Tk_RestrictEvents(oldProc, oldArg, &oldArg);
}
}
+/*
+ * This is no-op on 10.7 and up because Apple has removed this widget,
+ * but we are leaving it here for backwards compatibility.
+ */
- (void) tkToolbarButton: (id) sender
{
#ifdef TK_MAC_DEBUG_EVENTS
@@ -881,7 +958,6 @@ ExposeRestrictProc(
int x, y;
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
Tk_Window tkwin = (Tk_Window) winPtr;
-
bzero(&event, sizeof(XVirtualEvent));
event.type = VirtualEvent;
event.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
@@ -899,27 +975,11 @@ ExposeRestrictProc(
Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
}
-#ifdef TK_MAC_DEBUG_DRAWING
-- (void) setFrameSize: (NSSize) newSize
-{
- TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd,
- NSStringFromSize(newSize));
- [super setFrameSize:newSize];
-}
-
-- (void) setNeedsDisplayInRect: (NSRect) invalidRect
-{
- TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd,
- NSStringFromRect(invalidRect));
- [super setNeedsDisplayInRect:invalidRect];
-}
-#endif
-
- (BOOL) isOpaque
{
NSWindow *w = [self window];
- if (opaqueTag != NULL) {
+ if (opaqueTag) {
return YES;
} else {
@@ -947,153 +1007,6 @@ ExposeRestrictProc(
@end
-#pragma mark TKContentViewPrivate
-
-/*
- * Technique adapted from WebKit/WebKit/mac/WebView/WebHTMLView.mm to supress
- * normal AppKit subview drawing and make all drawing go through us.
- * Overrides NSView internals.
- */
-
-@interface TKContentView(TKContentViewPrivate)
-- (id) initWithFrame: (NSRect) frame;
-- (void) _setAsideSubviews;
-- (void) _restoreSubviews;
-@end
-
-@interface NSView(TKContentViewPrivate)
-- (void) _recursiveDisplayRectIfNeededIgnoringOpacity: (NSRect) rect
- isVisibleRect: (BOOL) isVisibleRect
- rectIsVisibleRectForView: (NSView *) visibleView
- topView: (BOOL) topView;
-- (void) _recursiveDisplayAllDirtyWithLockFocus: (BOOL) needsLockFocus
- visRect: (NSRect) visRect;
-- (void) _recursive: (BOOL) recurse
- displayRectIgnoringOpacity: (NSRect) displayRect
- inContext: (NSGraphicsContext *) context topView: (BOOL) topView;
-- (void) _lightWeightRecursiveDisplayInRect: (NSRect) visRect;
-- (BOOL) _drawRectIfEmpty;
-- (void) _drawRect: (NSRect) inRect clip: (BOOL) clip;
-- (void) _setDrawsOwnDescendants: (BOOL) drawsOwnDescendants;
-@end
-
-@implementation TKContentView(TKContentViewPrivate)
-
-- (id) initWithFrame: (NSRect) frame
-{
- self = [super initWithFrame:frame];
- if (self) {
- _savedSubviews = nil;
- _subviewsSetAside = NO;
- [self _setDrawsOwnDescendants:YES];
- }
- return self;
-}
-
-- (void) _setAsideSubviews
-{
-#ifdef TK_MAC_DEBUG
- if (_subviewsSetAside || _savedSubviews) {
- Tcl_Panic("TKContentView _setAsideSubviews called incorrectly");
- }
-#endif
- _savedSubviews = _subviews;
- _subviews = nil;
- _subviewsSetAside = YES;
-}
-
-- (void) _restoreSubviews
-{
-#ifdef TK_MAC_DEBUG
- if (!_subviewsSetAside || _subviews) {
- Tcl_Panic("TKContentView _restoreSubviews called incorrectly");
- }
-#endif
- _subviews = _savedSubviews;
- _savedSubviews = nil;
- _subviewsSetAside = NO;
-}
-
-- (void) _recursiveDisplayRectIfNeededIgnoringOpacity: (NSRect) rect
- isVisibleRect: (BOOL) isVisibleRect
- rectIsVisibleRectForView: (NSView *) visibleView
- topView: (BOOL) topView
-{
- [self _setAsideSubviews];
- [super _recursiveDisplayRectIfNeededIgnoringOpacity:rect
- isVisibleRect:isVisibleRect rectIsVisibleRectForView:visibleView
- topView:topView];
- [self _restoreSubviews];
-}
-
-- (void) _recursiveDisplayAllDirtyWithLockFocus: (BOOL) needsLockFocus
- visRect: (NSRect) visRect
-{
- BOOL needToSetAsideSubviews = !_subviewsSetAside;
-
- if (needToSetAsideSubviews) {
- [self _setAsideSubviews];
- }
- [super _recursiveDisplayAllDirtyWithLockFocus:needsLockFocus
- visRect:visRect];
- if (needToSetAsideSubviews) {
- [self _restoreSubviews];
- }
-}
-
-- (void) _recursive: (BOOL) recurse
- displayRectIgnoringOpacity: (NSRect) displayRect
- inContext: (NSGraphicsContext *) context topView: (BOOL) topView
-{
- [self _setAsideSubviews];
- [super _recursive:recurse
- displayRectIgnoringOpacity:displayRect inContext:context
- topView:topView];
- [self _restoreSubviews];
-}
-
-- (void) _lightWeightRecursiveDisplayInRect: (NSRect) visRect
-{
- BOOL needToSetAsideSubviews = !_subviewsSetAside;
-
- if (needToSetAsideSubviews) {
- [self _setAsideSubviews];
- }
- [super _lightWeightRecursiveDisplayInRect:visRect];
- if (needToSetAsideSubviews) {
- [self _restoreSubviews];
- }
-}
-
-- (BOOL) _drawRectIfEmpty
-{
- /*
- * Our -drawRect manages subview drawing directly, so it needs to be called
- * even if the area to be redrawn is completely obscured by subviews.
- */
-
- return YES;
-}
-
-- (void) _drawRect: (NSRect) inRect clip: (BOOL) clip
-{
-#ifdef TK_MAC_DEBUG_DRAWING
- TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd,
- NSStringFromRect(inRect));
-#endif
- BOOL subviewsWereSetAside = _subviewsSetAside;
-
- if (subviewsWereSetAside) {
- [self _restoreSubviews];
- }
- [super _drawRect:inRect clip:clip];
- if (subviewsWereSetAside) {
- [self _setAsideSubviews];
- }
-}
-
-@end
-
/*
* Local Variables:
* mode: objc
diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c
index 370c86a..3ea2f51 100644
--- a/macosx/tkMacOSXWm.c
+++ b/macosx/tkMacOSXWm.c
@@ -21,6 +21,8 @@
#include "tkMacOSXEvent.h"
#include "tkMacOSXDebug.h"
+#define DEBUG_ZOMBIES 0
+
/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_WINDOWS
@@ -53,7 +55,7 @@
/*Objects for use in setting background color and opacity of window.*/
NSColor *colorName = NULL;
-NSString *opaqueTag = NULL;
+BOOL opaqueTag = FALSE;
static const struct {
const UInt64 validAttrs, defaultAttrs, forceOnAttrs, forceOffAttrs;
@@ -194,6 +196,48 @@ static int tkMacOSXWmAttrNotifyVal = 0;
static Tcl_HashTable windowTable;
static int windowHashInit = false;
+
+
+#pragma mark NSWindow(TKWm)
+
+/*
+ * Conversion of coordinates between window and screen.
+ */
+
+@implementation NSWindow(TKWm)
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+- (NSPoint) convertPointToScreen: (NSPoint) point
+{
+ return [self convertBaseToScreen:point];
+}
+- (NSPoint) convertPointFromScreen: (NSPoint)point
+{
+ return [self convertScreenToBase:point];
+}
+@end
+#else
+- (NSPoint) convertPointToScreen: (NSPoint) point
+{
+ NSRect pointrect;
+ pointrect.origin = point;
+ pointrect.size.width = 0;
+ pointrect.size.height = 0;
+ return [self convertRectToScreen:pointrect].origin;
+}
+- (NSPoint) convertPointFromScreen: (NSPoint)point
+{
+ NSRect pointrect;
+ pointrect.origin = point;
+ pointrect.size.width = 0;
+ pointrect.size.height = 0;
+ return [self convertRectFromScreen:pointrect].origin;
+}
+@end
+#endif
+
+#pragma mark -
+
+
/*
* Forward declarations for procedures defined in this file:
*/
@@ -342,6 +386,7 @@ static void RemapWindows(TkWindow *winPtr,
@end
@implementation TKWindow(TKWm)
+
- (BOOL) canBecomeKeyWindow
{
TkWindow *winPtr = TkMacOSXGetTkWindow(self);
@@ -350,6 +395,59 @@ static void RemapWindows(TkWindow *winPtr,
kHelpWindowClass || winPtr->wmInfoPtr->attributes &
kWindowNoActivatesAttribute)) ? NO : YES;
}
+
+#if DEBUG_ZOMBIES
+- (id) retain
+{
+ id result = [super retain];
+ const char *title = [[self title] UTF8String];
+ if (title == nil) {
+ title = "unnamed window";
+ }
+ if (DEBUG_ZOMBIES > 1){
+ printf("Retained <%s>. Count is: %lu\n", title, [self retainCount]);
+ }
+ return result;
+}
+
+- (id) autorelease
+{
+ static int xcount = 0;
+ id result = [super autorelease];
+ const char *title = [[self title] UTF8String];
+ if (title == nil) {
+ title = "unnamed window";
+ }
+ if (DEBUG_ZOMBIES > 1){
+ printf("Autoreleased <%s>. Count is %lu\n", title, [self retainCount]);
+ }
+ return result;
+}
+
+- (oneway void) release {
+ const char *title = [[self title] UTF8String];
+ if (title == nil) {
+ title = "unnamed window";
+ }
+ if (DEBUG_ZOMBIES > 1){
+ printf("Releasing <%s>. Count is %lu\n", title, [self retainCount]);
+ }
+ [super release];
+}
+
+- (void) dealloc {
+ const char *title = [[self title] UTF8String];
+ if (title == nil) {
+ title = "unnamed window";
+ }
+ if (DEBUG_ZOMBIES > 0){
+ printf(">>>> Freeing <%s>. Count is %lu\n", title, [self retainCount]);
+ }
+ [super dealloc];
+}
+
+
+#endif
@end
#pragma mark -
@@ -463,25 +561,16 @@ FrontWindowAtPoint(
int x, int y)
{
NSPoint p = NSMakePoint(x, tkMacOSXZeroScreenHeight - y);
- NSWindow *win = nil;
- NSInteger windowCount;
- NSInteger *windowNumbers;
-
- NSCountWindows(&windowCount);
- if (windowCount) {
- windowNumbers = ckalloc(windowCount * sizeof(NSInteger));
- NSWindowList(windowCount, windowNumbers);
- for (NSInteger index = 0; index < windowCount; index++) {
- NSWindow *w = [NSApp windowWithWindowNumber:windowNumbers[index]];
+ NSArray *windows = [NSApp orderedWindows];
+ TkWindow *front = NULL;
+ for (NSWindow *w in windows) {
if (w && NSMouseInRect(p, [w frame], NO)) {
- win = w;
+ front = TkMacOSXGetTkWindow(w);
break;
}
}
- ckfree(windowNumbers);
- }
- return (win ? TkMacOSXGetTkWindow(win) : NULL);
+ return front;
}
/*
@@ -677,6 +766,7 @@ TkWmMapWindow(
*/
XMapWindow(winPtr->display, winPtr->window);
+
}
/*
@@ -699,7 +789,7 @@ TkWmMapWindow(
void
TkWmUnmapWindow(
TkWindow *winPtr) /* Top-level window that's about to be
- * mapped. */
+ * unmapped. */
{
XUnmapWindow(winPtr->display, winPtr->window);
}
@@ -783,15 +873,42 @@ TkWmDeadWindow(
NSWindow *window = wmPtr->window;
if (window && !Tk_IsEmbedded(winPtr) ) {
- [[window parentWindow] removeChildWindow:window];
+ NSWindow *parent = [window parentWindow];
+ if (parent) {
+ [parent removeChildWindow:window];
+ }
[window close];
TkMacOSXUnregisterMacWindow(window);
- if (winPtr->window) {
- ((MacDrawable *) winPtr->window)->view = nil;
+ if (winPtr->window) {
+ ((MacDrawable *) winPtr->window)->view = nil;
+ }
+#if DEBUG_ZOMBIES > 0
+ {
+ const char *title = [[window title] UTF8String];
+ if (title == nil) {
+ title = "unnamed window";
+ }
+ printf(">>>> Closing <%s>. Count is: %lu\n", title, [window retainCount]);
}
- TkMacOSXMakeCollectableAndRelease(wmPtr->window);
- }
+#endif
+ [window release];
+ wmPtr->window = NULL;
+
+ /* 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];
+ }
+ }
+ [NSApp _resetAutoreleasePool];
+#if DEBUG_ZOMBIES > 0
+ fprintf(stderr, "================= Pool dump ===================\n");
+ [NSAutoreleasePool showPools];
+#endif
+ }
ckfree(wmPtr);
winPtr->wmInfoPtr = NULL;
}
@@ -1655,8 +1772,8 @@ WmForgetCmd(
if (Tk_IsTopLevel(frameWin)) {
MacDrawable *macWin;
- Tk_MakeWindowExist(winPtr);
- Tk_MakeWindowExist(winPtr->parentPtr);
+ Tk_MakeWindowExist(frameWin);
+ Tk_MakeWindowExist((Tk_Window)winPtr->parentPtr);
macWin = (MacDrawable *) winPtr->window;
@@ -5116,7 +5233,7 @@ TkUnsupported1ObjCmd(
colorName = [NSColor clearColor]; //use systemTransparent in Tk scripts to match
}
if (Tcl_StringMatch(Tcl_GetString(objv[i]), "*opacity*")) {
- opaqueTag = @"YES";
+ opaqueTag = YES;
}
}
@@ -5444,7 +5561,6 @@ TkMacOSXMakeRealWindowExist(
* TODO: Here we should handle out of process embedding.
*/
}
-
WindowClass macClass = wmPtr->macClass;
wmPtr->attributes &= (tkAlwaysValidAttributes |
macClassAttrs[macClass].validAttrs);
@@ -5478,11 +5594,10 @@ TkMacOSXMakeRealWindowExist(
NSWindow *window = [[winClass alloc] initWithContentRect:contentRect
styleMask:styleMask backing:NSBackingStoreBuffered defer:YES];
if (!window) {
- Tcl_Panic("couldn't allocate new Mac window");
+ Tcl_Panic("couldn't allocate new Mac window");
}
- TkMacOSXMakeUncollectable(window);
TKContentView *contentView = [[TKContentView alloc]
- initWithFrame:NSZeroRect];
+ initWithFrame:NSZeroRect];
[window setContentView:contentView];
[contentView release];
[window setDelegate:NSApp];
@@ -5507,7 +5622,7 @@ TkMacOSXMakeRealWindowExist(
[window setBackgroundColor: colorName];
}
- if (opaqueTag != NULL) {
+ if (opaqueTag) {
#ifdef TK_GOT_AT_LEAST_SNOW_LEOPARD
[window setOpaque: opaqueTag];
#else
@@ -5517,7 +5632,7 @@ TkMacOSXMakeRealWindowExist(
[window setDocumentEdited:NO];
wmPtr->window = window;
- macWin->view = contentView;
+ macWin->view = window.contentView;
TkMacOSXApplyWindowAttributes(winPtr, window);
NSRect geometry = InitialWindowBounds(winPtr, window);
@@ -5526,7 +5641,6 @@ TkMacOSXMakeRealWindowExist(
geometry.origin.y = tkMacOSXZeroScreenHeight - (geometry.origin.y +
geometry.size.height);
[window setFrame:geometry display:NO];
-
TkMacOSXRegisterOffScreenWindow((Window) macWin, window);
macWin->flags |= TK_HOST_EXISTS;
}
@@ -5915,15 +6029,21 @@ TkpChangeFocus(
* didn't originally belong to topLevelPtr's
* application. */
{
- /*
- * We don't really need to do anything on the Mac. Tk will keep all this
- * state for us.
- */
-
if (winPtr->atts.override_redirect) {
return 0;
}
+ if (Tk_IsTopLevel(winPtr) && !Tk_IsEmbedded(winPtr) ){
+ NSWindow *win = TkMacOSXDrawableWindow(winPtr->window);
+ TkWmRestackToplevel(winPtr, Above, NULL);
+ if (force ) {
+ [NSApp activateIgnoringOtherApps:YES];
+ }
+ if ( win && [win canBecomeKeyWindow] ) {
+ [win makeKeyAndOrderFront:NSApp];
+ }
+ }
+
/*
* Remember the current serial number for the X server and issue a dummy
* server request. This marks the position at which we changed the focus,
@@ -5940,7 +6060,7 @@ TkpChangeFocus(
* WmStackorderToplevelWrapperMap --
*
* This procedure will create a table that maps the reparent wrapper X id
- * for a toplevel to the TkWindow structure that is wraps. Tk keeps track
+ * for a toplevel to the TkWindow structure that it wraps. Tk keeps track
* of a mapping from the window X id to the TkWindow structure but that
* does us no good here since we only get the X id of the wrapper window.
* Only those toplevel windows that are mapped have a position in the
@@ -6003,8 +6123,6 @@ TkWmStackorderToplevel(
Tcl_HashTable table;
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
- NSInteger windowCount;
- NSInteger *windowNumbers;
/*
* Map mac windows to a TkWindow of the wrapped toplevel.
@@ -6031,31 +6149,26 @@ TkWmStackorderToplevel(
goto done;
}
- NSCountWindows(&windowCount);
+ NSArray *macWindows = [NSApp orderedWindows];
+ NSInteger windowCount = [macWindows count];
+
if (!windowCount) {
ckfree(windows);
windows = NULL;
} else {
windowPtr = windows + table.numEntries;
*windowPtr-- = NULL;
- windowNumbers = ckalloc(windowCount * sizeof(NSInteger));
- NSWindowList(windowCount, windowNumbers);
- for (NSInteger index = 0; index < windowCount; index++) {
- NSWindow *w = [NSApp windowWithWindowNumber:windowNumbers[index]];
-
- if (w) {
- hPtr = Tcl_FindHashEntry(&table, (char*) w);
- if (hPtr != NULL) {
- childWinPtr = Tcl_GetHashValue(hPtr);
- *windowPtr-- = childWinPtr;
- }
+ for (NSWindow *w in macWindows) {
+ hPtr = Tcl_FindHashEntry(&table, (char*) w);
+ if (hPtr != NULL) {
+ childWinPtr = Tcl_GetHashValue(hPtr);
+ *windowPtr-- = childWinPtr;
}
}
if (windowPtr != windows-1) {
Tcl_Panic("num matched toplevel windows does not equal num "
- "children");
+ "children");
}
- ckfree(windowNumbers);
}
done:
@@ -6614,7 +6727,6 @@ RemapWindows(
MacDrawable *parentWin)
{
TkWindow *childPtr;
-
/*
* Remove the OS specific window. It will get rebuilt when the window gets
* Mapped.
diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c
index 848b49c..5d6ffb9 100644
--- a/macosx/tkMacOSXXStubs.c
+++ b/macosx/tkMacOSXXStubs.c
@@ -9,6 +9,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 2014 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -141,7 +142,7 @@ TkpOpenDisplay(
static NSRect maxBounds = {{0, 0}, {0, 0}};
static char vendor[25] = "";
NSArray *cgVers;
- NSAutoreleasePool *pool;
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
if (gMacDisplay != NULL) {
if (strcmp(gMacDisplay->display->display_name, display_name) == 0) {
@@ -165,7 +166,6 @@ TkpOpenDisplay(
display->default_screen = 0;
display->display_name = (char *) macScreenName;
- pool = [NSAutoreleasePool new];
cgVers = [[[NSBundle bundleWithIdentifier:@"com.apple.CoreGraphics"]
objectForInfoDictionaryKey:@"CFBundleShortVersionString"]
componentsSeparatedByString:@"."];
@@ -176,12 +176,25 @@ TkpOpenDisplay(
display->proto_minor_version = [[cgVers objectAtIndex:2] integerValue];
}
if (!vendor[0]) {
- snprintf(vendor, sizeof(vendor), "Apple AppKit %s %g",
- ([NSGarbageCollector defaultCollector] ? "GC" : "RR"),
+ snprintf(vendor, sizeof(vendor), "Apple AppKit %g",
NSAppKitVersionNumber);
}
display->vendor = vendor;
- Gestalt(gestaltSystemVersion, (SInt32 *) &display->release);
+ {
+ int major, minor, patch;
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 10100
+ Gestalt(gestaltSystemVersionMajor, (SInt32*)&major);
+ Gestalt(gestaltSystemVersionMinor, (SInt32*)&minor);
+ Gestalt(gestaltSystemVersionBugFix, (SInt32*)&patch);
+#else
+ NSOperatingSystemVersion systemVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
+ major = systemVersion.majorVersion;
+ minor = systemVersion.minorVersion;
+ patch = systemVersion.patchVersion;
+#endif
+ display->release = major << 16 | minor << 8 | patch;
+ }
/*
* These screen bits never change
@@ -782,7 +795,6 @@ XCreateImage(
int bytes_per_line)
{
XImage *ximage;
-
display->request++;
ximage = ckalloc(sizeof(XImage));
@@ -792,6 +804,7 @@ XCreateImage(
ximage->xoffset = offset;
ximage->format = format;
ximage->data = data;
+ ximage->obdata = NULL;
if (format == ZPixmap) {
ximage->bits_per_pixel = 32;
@@ -823,7 +836,6 @@ XCreateImage(
ximage->red_mask = 0x00FF0000;
ximage->green_mask = 0x0000FF00;
ximage->blue_mask = 0x000000FF;
- ximage->obdata = NULL;
ximage->f.create_image = NULL;
ximage->f.destroy_image = DestroyImage;
ximage->f.get_pixel = ImageGetPixel;
@@ -842,8 +854,9 @@ XCreateImage(
* This function copies data from a pixmap or window into an XImage.
*
* Results:
- * Returns a newly allocated image containing the data from the given
- * rectangle of the given drawable.
+ * 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.
*
* Side effects:
* None.
@@ -862,60 +875,84 @@ XGetImage(
unsigned long plane_mask,
int format)
{
- MacDrawable *macDraw = (MacDrawable *) d;
- XImage * imagePtr = NULL;
- Pixmap pixmap = (Pixmap) NULL;
- Tk_Window win = (Tk_Window) macDraw->winPtr;
- GC gc;
- char * data = NULL;
- int depth = 32;
- int offset = 0;
- int bitmap_pad = 0;
- int bytes_per_line = 0;
-
+ 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;
+ TkMacOSXDbgMsg("XGetImage");
if (format == ZPixmap) {
- if (width > 0 && height > 0) {
- /*
- * Tk_GetPixmap fails for zero width or height.
- */
-
- pixmap = Tk_GetPixmap(display, d, width, height, depth);
+ if (width == 0 || height == 0) {
+ /* This happens all the time.
+ TkMacOSXDbgMsg("XGetImage: empty image requested");
+ */
+ return NULL;
}
- if (win) {
- XGCValues values;
- gc = Tk_GetGC(win, 0, &values);
- } else {
- gc = XCreateGC(display, pixmap, 0, 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;
}
- if (pixmap) {
- CGContextRef context;
-
- XCopyArea(display, d, pixmap, gc, x, y, width, height, 0, 0);
- context = ((MacDrawable *) pixmap)->context;
- if (context) {
- data = CGBitmapContextGetData(context);
- bytes_per_line = CGBitmapContextGetBytesPerRow(context);
+
+ 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];
+ size = bytes_per_row*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<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<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 (data) {
+ if (bitmap) {
imagePtr = XCreateImage(display, NULL, depth, format, offset,
- data, width, height, bitmap_pad, bytes_per_line);
-
- /*
- * Track Pixmap underlying the XImage in the unused obdata field
- * so that we can treat XImages coming from XGetImage specially.
- */
-
- imagePtr->obdata = (XPointer) pixmap;
- } else if (pixmap) {
- Tk_FreePixmap(display, pixmap);
- }
- if (!win) {
- XFreeGC(display, gc);
+ (char*)bitmap, width, height, bitmap_pad, bytes_per_row);
+ [ns_image removeRepresentation:bitmap_rep]; /*releases the rep*/
+ [ns_image release];
}
} else {
- TkMacOSXDbgMsg("Invalid image format");
+ TkMacOSXDbgMsg("Could not extract image from drawable.");
}
return imagePtr;
}
@@ -941,9 +978,7 @@ DestroyImage(
XImage *image)
{
if (image) {
- if (image->obdata) {
- Tk_FreePixmap((Display*) gMacDisplay, (Pixmap) image->obdata);
- } else if (image->data) {
+ if (image->data) {
ckfree(image->data);
}
ckfree(image);
diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c
index 5752fb1..4753a40 100644
--- a/macosx/ttkMacOSXTheme.c
+++ b/macosx/ttkMacOSXTheme.c
@@ -294,14 +294,13 @@ static Ttk_StateTable TabPositionTable[] = {
* TP30000359-TPXREF116>
*/
-static const int TAB_HEIGHT = 10;
-static const int TAB_OVERLAP = 10;
-
static void TabElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
- *heightPtr = TAB_HEIGHT + TAB_OVERLAP - 1;
+ *heightPtr = GetThemeMetric(kThemeMetricLargeTabHeight, heightPtr);
+ *paddingPtr = Ttk_MakePadding(0, 0, 0, 2);
+
}
static void TabElementDraw(
@@ -319,7 +318,6 @@ static void TabElementDraw(
.position = Ttk_StateTableLookup(TabPositionTable, state),
};
- bounds.size.height += TAB_OVERLAP;
BEGIN_DRAWING(d)
ChkErr(HIThemeDrawTab, &bounds, &info, dc.context, HIOrientation, NULL);
END_DRAWING
@@ -357,8 +355,8 @@ static void PaneElementDraw(
.adornment = kHIThemeTabPaneAdornmentNormal,
};
- bounds.origin.y -= TAB_OVERLAP;
- bounds.size.height += TAB_OVERLAP;
+ bounds.origin.y -= kThemeMetricTabFrameOverlap;
+ bounds.size.height += kThemeMetricTabFrameOverlap;
BEGIN_DRAWING(d)
ChkErr(HIThemeDrawTabPane, &bounds, &info, dc.context, HIOrientation);
END_DRAWING
@@ -520,6 +518,10 @@ static Ttk_ElementSpec ComboboxElementSpec = {
ComboboxElementDraw
};
+
+
+
+
/*----------------------------------------------------------------------
* +++ Spinbuttons.
*
@@ -592,6 +594,7 @@ static TrackElementData ScaleData = {
kThemeSlider, kThemeMetricHSliderHeight
};
+
typedef struct {
Tcl_Obj *fromObj; /* minimum value */
Tcl_Obj *toObj; /* maximum value */
@@ -653,6 +656,7 @@ static void TrackElementDraw(
info.trackInfo.slider.thumbDir = kThemeThumbPlain;
}
+
BEGIN_DRAWING(d)
ChkErr(HIThemeDrawTrack, &info, NULL, dc.context, HIOrientation);
END_DRAWING