summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorculler <culler>2024-07-08 02:07:57 (GMT)
committerculler <culler>2024-07-08 02:07:57 (GMT)
commit365059dd56e66d2056e28432b1420bfe676c260b (patch)
treec9226ff6937df277c893bfd24c4968fd3bfe4693
parentc2f8aeaa3b5abbf7ce84a9f4476a5592c0932ddf (diff)
parentd516c14a8643ea0b488683bd1b4b0e34c9a91f64 (diff)
downloadtk-365059dd56e66d2056e28432b1420bfe676c260b.zip
tk-365059dd56e66d2056e28432b1420bfe676c260b.tar.gz
tk-365059dd56e66d2056e28432b1420bfe676c260b.tar.bz2
Merge with cgimage_with_crossing branch.
-rw-r--r--generic/tkFont.c11
-rw-r--r--generic/tkFrame.c2
-rw-r--r--generic/tkTextDisp.c2
-rw-r--r--generic/tkWindow.c53
-rw-r--r--library/demos/mac_styles.tcl12
-rw-r--r--library/palette.tcl27
-rw-r--r--macosx/README6
-rw-r--r--macosx/tkMacOSXClipboard.c4
-rw-r--r--macosx/tkMacOSXColor.c52
-rw-r--r--macosx/tkMacOSXDraw.c185
-rw-r--r--macosx/tkMacOSXEmbed.c10
-rw-r--r--macosx/tkMacOSXEvent.c16
-rw-r--r--macosx/tkMacOSXFileTypes.c6
-rw-r--r--macosx/tkMacOSXHLEvents.c90
-rw-r--r--macosx/tkMacOSXImage.c102
-rw-r--r--macosx/tkMacOSXInit.c78
-rw-r--r--macosx/tkMacOSXKeyEvent.c22
-rw-r--r--macosx/tkMacOSXKeyboard.c4
-rw-r--r--macosx/tkMacOSXMenu.c11
-rw-r--r--macosx/tkMacOSXMenubutton.c236
-rw-r--r--macosx/tkMacOSXMenus.c20
-rw-r--r--macosx/tkMacOSXMouseEvent.c9
-rw-r--r--macosx/tkMacOSXNotify.c32
-rw-r--r--macosx/tkMacOSXPrint.c208
-rw-r--r--macosx/tkMacOSXPrivate.h21
-rw-r--r--macosx/tkMacOSXScale.c8
-rw-r--r--macosx/tkMacOSXSubwindows.c139
-rw-r--r--macosx/tkMacOSXSysTray.c30
-rw-r--r--macosx/tkMacOSXTest.c63
-rw-r--r--macosx/tkMacOSXWindowEvent.c287
-rw-r--r--macosx/tkMacOSXWm.c293
-rw-r--r--macosx/ttkMacOSXTheme.c104
-rw-r--r--macosx/ttkMacOSXTheme.h2
-rw-r--r--tests/event.test319
-rw-r--r--tests/focus.test6
-rw-r--r--tests/font.test13
-rw-r--r--tests/image.test4
-rw-r--r--tests/pack.test14
-rw-r--r--tests/raise.test1
-rw-r--r--tests/textDisp.test12
-rw-r--r--tests/ttk/ttk.test11
-rw-r--r--tests/unixWm.test60
-rw-r--r--tests/window.test3
-rw-r--r--tests/winfo.test2
-rw-r--r--tests/wm.test2
-rw-r--r--tests/xmfbox.test7
-rw-r--r--win/tkWinWm.c36
47 files changed, 1592 insertions, 1043 deletions
diff --git a/generic/tkFont.c b/generic/tkFont.c
index 1918d78..6a90add 100644
--- a/generic/tkFont.c
+++ b/generic/tkFont.c
@@ -887,17 +887,6 @@ TheWorldHasChanged(
{
TkFontInfo *fiPtr = (TkFontInfo *)clientData;
- /*
- * On macOS it is catastrophic to recompute all widgets while the
- * [NSView drawRect] method is drawing. The best that we can do in
- * that situation is to abort the recomputation and hope for the best.
- * This is ignored on other platforms.
- */
-
- if (TkpWillDrawWidget(NULL)) {
- return;
- }
-
fiPtr->updatePending = 0;
RecomputeWidgets(fiPtr->mainPtr->winPtr);
}
diff --git a/generic/tkFrame.c b/generic/tkFrame.c
index 302542c..d49292b 100644
--- a/generic/tkFrame.c
+++ b/generic/tkFrame.c
@@ -1478,6 +1478,8 @@ DisplayFrame(
Tk_Depth(tkwin));
#else
pixmap = Tk_WindowId(tkwin);
+ Tk_ClipDrawableToRect(Tk_Display(tkwin), pixmap, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin));
#endif /* TK_NO_DOUBLE_BUFFERING */
if (framePtr->type != TYPE_LABELFRAME) {
diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c
index 905a4c6..027efc8 100644
--- a/generic/tkTextDisp.c
+++ b/generic/tkTextDisp.c
@@ -24,7 +24,7 @@
#include "tkMacOSXInt.h"
#endif
-#define OK_TO_LOG (!TkpWillDrawWidget(textPtr->tkwin))
+#define OK_TO_LOG 1
/*
* "Calculations of line pixel heights and the size of the vertical
diff --git a/generic/tkWindow.c b/generic/tkWindow.c
index 68f3406..9d36e9f 100644
--- a/generic/tkWindow.c
+++ b/generic/tkWindow.c
@@ -215,6 +215,17 @@ static int Initialize(Tcl_Interp *interp);
static int NameWindow(Tcl_Interp *interp, TkWindow *winPtr,
TkWindow *parentPtr, const char *name);
static void UnlinkWindow(TkWindow *winPtr);
+
+/*
+ * This static variable only makes sense for macOS and Windows, which never
+ * have more than one display. It is set by TkCloseDisplay, and when set
+ * prevents sending Enter and Leave events when all of the windows in the
+ * display are being destroyed. Tk does not send those events on X11; that
+ * job is handled by the X server.
+ */
+
+static int displayBeingClosed = 0;
+
/*
*----------------------------------------------------------------------
@@ -239,6 +250,7 @@ static void
TkCloseDisplay(
TkDisplay *dispPtr)
{
+ displayBeingClosed = 1;
TkClipCleanup(dispPtr);
if (dispPtr->name != NULL) {
@@ -1334,6 +1346,39 @@ Tk_CreateWindowFromPath(
*--------------------------------------------------------------
*/
+#if defined(MAC_OSX_TK) || defined(_WIN32)
+static void SendEnterLeaveForDestroy(
+ Tk_Window tkwin)
+{
+ int x, y;
+ unsigned int state;
+ Tk_Window pointerWin;
+ TkWindow *containerPtr;
+
+ if (displayBeingClosed) {
+ return;
+ }
+ XQueryPointer(Tk_Display(tkwin), None, NULL, NULL, &x, &y,
+ NULL, NULL, &state);
+ pointerWin = Tk_CoordsToWindow(x, y, tkwin);
+ if (pointerWin == tkwin) {
+ if (!Tk_IsTopLevel(tkwin)) {
+ containerPtr = TkGetContainer((TkWindow *)pointerWin);
+ Tk_UpdatePointer((Tk_Window) containerPtr, x, y, state);
+ }
+ }
+
+ if (pointerWin && (tkwin == Tk_Parent(pointerWin))) {
+ Tk_UpdatePointer(Tk_Parent(tkwin), x, y, state);
+ }
+}
+#else
+static void SendEnterLeaveForDestroy(
+ TCL_UNUSED(Tk_Window))
+{
+}
+#endif
+
void
Tk_DestroyWindow(
Tk_Window tkwin) /* Window to destroy. */
@@ -1353,6 +1398,10 @@ Tk_DestroyWindow(
return;
}
+ if ((winPtr->flags & TK_DONT_DESTROY_WINDOW) == 0) {
+ SendEnterLeaveForDestroy(tkwin);
+ }
+
winPtr->flags |= TK_ALREADY_DEAD;
/*
@@ -1523,7 +1572,7 @@ Tk_DestroyWindow(
* Cleanup the data structures associated with this window.
*/
- if (winPtr->flags & TK_WIN_MANAGED) {
+ if (winPtr->wmInfoPtr && (winPtr->flags & TK_WIN_MANAGED)) {
TkWmDeadWindow(winPtr);
} else if (winPtr->flags & TK_WM_COLORMAP_WINDOW) {
TkWmRemoveFromColormapWindows(winPtr);
@@ -2612,7 +2661,7 @@ Tk_RestackWindow(
TkWindow *otherPtr = (TkWindow *) other;
/*
- * Special case: if winPtr is a top-level window then just find the
+ * Special case: if winPtr is a toplevel window then just find the
* top-level ancestor of otherPtr and restack winPtr above otherPtr
* without changing any of Tk's childLists.
*/
diff --git a/library/demos/mac_styles.tcl b/library/demos/mac_styles.tcl
index 3fff03c..804b5c0 100644
--- a/library/demos/mac_styles.tcl
+++ b/library/demos/mac_styles.tcl
@@ -245,16 +245,16 @@ if { [wm attributes $w -isdark] } {
}
proc beLight {f w} {
wm attributes $w -appearance aqua
- $f.dark state !selected
- $f.light state selected
- after 10 $f.light state !hover
+ # A small delay is needed for the appearance change to complete.
+ after 10 [list $f.dark state !selected]
+ after 10 [list $f.light state selected]
}
proc beDark {f w} {
wm attributes $w -appearance darkaqua
- $f.light state !selected
- $f.dark state selected
- after 10 $f.dark state !hover
+ # A small delay is needed for the appearance change to complete.
+ after 10 [list $f.light state !selected]
+ after 10 [list $f.dark state selected]
}
$w.notebook add $appearanceFrame -text "Appearance"
diff --git a/library/palette.tcl b/library/palette.tcl
index 90b499b..d07f894 100644
--- a/library/palette.tcl
+++ b/library/palette.tcl
@@ -189,6 +189,9 @@ proc ::tk_setPalette {args} {
# which contains color information. Each element
# is named after a widget configuration option, and
# each value is the value for that option.
+# Return Value:
+# A list of commands which can be run to update
+# the defaults database when exec'ed.
proc ::tk::RecolorTree {w colors} {
upvar $colors c
@@ -200,11 +203,14 @@ proc ::tk::RecolorTree {w colors} {
foreach dbOption [array names c] {
set option -[string tolower $dbOption]
set class [string replace $dbOption 0 0 [string toupper \
- [string index $dbOption 0]]]
+ [string index $dbOption 0]]]
+ # Make sure this option is valid for this window.
if {![catch {$w configure $option} value]} {
- # if the option database has a preference for this
- # dbOption, then use it, otherwise use the defaults
- # for the widget.
+ # Update the option for this window.
+ $w configure $option $c($dbOption)
+ # Retrieve a default value for this option. First check
+ # the option database. If it is not in the database use
+ # the value for the temporary prototype widget.
set defaultcolor [option get $w $dbOption $class]
if {$defaultcolor eq "" || \
([info exists prototype] && \
@@ -214,16 +220,15 @@ proc ::tk::RecolorTree {w colors} {
if {$defaultcolor ne ""} {
set defaultcolor [winfo rgb . $defaultcolor]
}
- set chosencolor [lindex $value 4]
- if {$chosencolor ne ""} {
- set chosencolor [winfo rgb . $chosencolor]
+ # If the color requested for this option differs from
+ # the default, append a command to update the default.
+ set requestcolor [lindex $value 4]
+ if {$requestcolor ne ""} {
+ set requestcolor [winfo rgb . $requestcolor]
}
- if {[string match $defaultcolor $chosencolor]} {
- # Change the option database so that future windows will get
- # the same colors.
+ if {![string match $defaultcolor $requestcolor]} {
append result ";\noption add [list \
*[winfo class $w].$dbOption $c($dbOption) 60]"
- $w configure $option $c($dbOption)
}
}
}
diff --git a/macosx/README b/macosx/README
index 64be140..c6159a6 100644
--- a/macosx/README
+++ b/macosx/README
@@ -477,9 +477,9 @@ https://developer.apple.com/library/mac/documentation/Cocoa/\
Reference/ApplicationKit/Classes/NSApplication_Class)
void NSApplicationMain(int argc, char *argv[]) {
- [NSApplication sharedApplication];
- [NSBundle loadNibNamed:@"myMain" owner:NSApp];
- [NSApp run];
+ [NSApplication sharedApplication];
+ [NSBundle loadNibNamed:@"myMain" owner:NSApp];
+ [NSApp run];
}
Here NSApp is a standard global variable, initialized by the OS, which
points to an object in a subclass of NSApplication (called
diff --git a/macosx/tkMacOSXClipboard.c b/macosx/tkMacOSXClipboard.c
index f16ab0d..8d5f727 100644
--- a/macosx/tkMacOSXClipboard.c
+++ b/macosx/tkMacOSXClipboard.c
@@ -126,8 +126,8 @@ TkSelGetSelection(
([[NSPasteboard generalPasteboard] changeCount] != changeCount);
if (dispPtr && (haveExternalClip || dispPtr->clipboardActive)
- && selection == dispPtr->clipboardAtom
- && (target == XA_STRING || target == dispPtr->utf8Atom)) {
+ && selection == dispPtr->clipboardAtom
+ && (target == XA_STRING || target == dispPtr->utf8Atom)) {
NSString *string = nil;
NSPasteboard *pb = [NSPasteboard generalPasteboard];
NSString *type = [pb availableTypeFromArray:[NSArray arrayWithObject:
diff --git a/macosx/tkMacOSXColor.c b/macosx/tkMacOSXColor.c
index 978b9d6..ffaadd9 100644
--- a/macosx/tkMacOSXColor.c
+++ b/macosx/tkMacOSXColor.c
@@ -52,7 +52,7 @@ static void initColorTable()
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
if (@available(macOS 10.14, *)) {
darkAqua = [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
- lightAqua = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
+ lightAqua = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
}
#endif
@@ -103,7 +103,7 @@ static void initColorTable()
name = (char *)ckalloc(length + 1);
strcpy(name, key.UTF8String);
name[0] = (char)toupper(UCHAR(name[0]));
- if (!strcmp(name, "WindowBackgroundColor")) {
+ if (!strcmp(name, "WindowBackgroundColor")) {
/*
* Avoid black windows on old systems.
@@ -192,8 +192,8 @@ TkMacOSXRGBPixel(
MacPixel p = {0};
p.pixel.colortype = rgbColor;
p.pixel.value = (unsigned int)(((red & 0xff) << 16) |
- ((green & 0xff) << 8) |
- (blue & 0xff));
+ ((green & 0xff) << 8) |
+ (blue & 0xff));
return p.ulong;
}
@@ -436,7 +436,7 @@ TkMacOSXInDarkMode(Tk_Window tkwin)
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
if (@available(macOS 10.14, *)) {
- TkWindow *winPtr = (TkWindow*) tkwin;
+ TkWindow *winPtr = (TkWindow*) tkwin;
NSAppearanceName name;
NSView *view = nil;
if (winPtr && winPtr->privatePtr) {
@@ -611,6 +611,7 @@ TkpGetColor(
XColor color;
Colormap colormap = tkwin ? Tk_Colormap(tkwin) : noColormap;
NSView *view = nil;
+ Bool haveValidXColor = False;
static Bool initialized = NO;
if (!initialized) {
@@ -638,16 +639,22 @@ TkpGetColor(
p.pixel.colortype = entry->type;
p.pixel.value = (unsigned int)entry->index;
color.pixel = p.ulong;
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
+ NSAppearance *windowAppearance;
+ if (@available(macOS 10.14, *)) {
+ if (view) {
+ windowAppearance = [view effectiveAppearance];
+ } else {
+ windowAppearance = [NSApp effectiveAppearance];
+ }
+ }
+#endif
+
if (entry->type == semantic) {
CGFloat rgba[4];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
if (@available(macOS 10.14, *)) {
- NSAppearance *windowAppearance;
- if (view) {
- windowAppearance = [view effectiveAppearance];
- } else {
- windowAppearance = [NSApp effectiveAppearance];
- }
if ([windowAppearance name] == NSAppearanceNameDarkAqua) {
colormap = darkColormap;
} else {
@@ -671,13 +678,13 @@ TkpGetColor(
} else {
GetRGBA(entry, p.ulong, rgba);
}
-#else
+#else //MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
GetRGBA(entry, p.ulong, rgba);
-#endif
color.red = (unsigned short)(rgba[0] * 65535.0);
color.green = (unsigned short)(rgba[1] * 65535.0);
color.blue = (unsigned short)(rgba[2] * 65535.0);
- goto validXColor;
+#endif //MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
+ haveValidXColor = True;
} else if (SetCGColorComponents(entry, 0, &c)) {
const size_t n = CGColorGetNumberOfComponents(c);
const CGFloat *rgba = CGColorGetComponents(c);
@@ -695,15 +702,26 @@ TkpGetColor(
Tcl_Panic("CGColor with %d components", (int) n);
}
CGColorRelease(c);
- goto validXColor;
+ haveValidXColor = True;
+ }
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
+ if (@available(macOS 10.14, *)) {
+ // Not sure whether colormap should also be set for non-semantic color
+ if (haveValidXColor && entry->type == semantic) {
+ if ([windowAppearance name] == NSAppearanceNameDarkAqua) {
+ colormap = darkColormap;
+ } else {
+ colormap = lightColormap;
+ }
+ }
}
+#endif
}
}
- if (TkParseColor(display, colormap, name, &color) == 0) {
+ if (!haveValidXColor && TkParseColor(display, colormap, name, &color) == 0) {
return NULL;
}
-validXColor:
tkColPtr = (TkColor *)ckalloc(sizeof(TkColor));
tkColPtr->colormap = colormap;
tkColPtr->color = color;
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c
index ff35da3..8ebdde4 100644
--- a/macosx/tkMacOSXDraw.c
+++ b/macosx/tkMacOSXDraw.c
@@ -264,7 +264,8 @@ Tk_MacOSXGetCGContextForDrawable(
colorspace = CGColorSpaceCreateDeviceRGB();
bitmapInfo |= kCGImageAlphaPremultipliedFirst;
}
- macDraw->context = CGBitmapContextCreate(NULL, (unsigned)macDraw->size.width,
+ macDraw->context = CGBitmapContextCreate(NULL,
+ (unsigned)macDraw->size.width,
(unsigned)macDraw->size.height, bitsPerComponent, 0,
colorspace, bitmapInfo);
if (macDraw->context) {
@@ -283,7 +284,8 @@ Tk_MacOSXGetCGContextForDrawable(
*
* TkMacOSXDrawCGImage --
*
- * Draw CG image into drawable.
+ * Draw CG image into drawable. The entire image is used, and will
+ * be rescaled if its dimensions do not equal dstBounds.size.
*
* Results:
* None.
@@ -302,25 +304,11 @@ TkMacOSXDrawCGImage(
CGImageRef image,
unsigned long imageForeground,
unsigned long imageBackground,
- CGRect imageBounds,
- CGRect srcBounds,
CGRect dstBounds)
{
MacDrawable *macDraw = (MacDrawable *)d;
if (macDraw && context && image) {
- CGImageRef subImage = NULL;
-
- if (!CGRectEqualToRect(imageBounds, srcBounds)) {
- if (!CGRectContainsRect(imageBounds, srcBounds)) {
- TkMacOSXDbgMsg("Mismatch of sub CGImage bounds");
- }
- subImage = CGImageCreateWithImageInRect(image, CGRectOffset(
- srcBounds, -imageBounds.origin.x, -imageBounds.origin.y));
- if (subImage) {
- image = subImage;
- }
- }
dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff);
if (CGImageIsMask(image)) {
if (macDraw->flags & TK_IS_BW_PIXMAP) {
@@ -369,9 +357,6 @@ TkMacOSXDrawCGImage(
CGContextDrawImage(context, dstBounds, image);
CGContextRestoreGState(context);
#endif /* TK_MAC_DEBUG_IMAGE_DRAWING */
- if (subImage) {
- CFRelease(subImage);
- }
} else {
TkMacOSXDbgMsg("Drawing of empty CGImage requested");
}
@@ -434,16 +419,16 @@ XDrawLines(
}
}
- /*
- * In the case of closed polylines, the first and last points are the
- * same. We want miter or bevel join be rendered also at this point,
- * this needs telling CoreGraphics that the path is closed.
- */
+ /*
+ * In the case of closed polylines, the first and last points are the
+ * same. We want miter or bevel join be rendered also at this point,
+ * this needs telling CoreGraphics that the path is closed.
+ */
- if ((points[0].x == points[npoints-1].x) &&
- (points[0].y == points[npoints-1].y)) {
- CGContextClosePath(dc.context);
- }
+ if ((points[0].x == points[npoints-1].x) &&
+ (points[0].y == points[npoints-1].y)) {
+ CGContextClosePath(dc.context);
+ }
CGContextStrokePath(dc.context);
}
TkMacOSXRestoreDrawingContext(&dc);
@@ -1093,6 +1078,23 @@ XFillArcs(
* Results:
* Returns 0 if the scroll generated no additional damage. Otherwise, sets
* the region that needs to be repainted after scrolling and returns 1.
+ * When drawRect was in use, this function used the now deprecated
+ * scrollRect method of NSView. With the current updateLayer
+ * implementation, using a CGImage as the view's backing layer, we are
+ * able to use XCopyArea. But both implementations are incomplete.
+ * They return a damage area which is just the source rectangle minus
+ * destination rectangle. Other platforms, e.g. Windows, where
+ * this function is essentially provided by the windowing system,
+ * are able to add to the damage region the bounding rectangles of
+ * all subwindows which meet the source rectangle, even if they are
+ * contained in the destination rectangle. The information needed
+ * to do that is not available in this module, as far as I know.
+ *
+ * In fact, the Text widget is the only one which calls this
+ * function, and textDisp.c compensates for this defect by using
+ * macOS-specific code. This is possible because access to the
+ * list of all embedded windows in a Text widget is available in
+ * that module.
*
* Side effects:
* Scrolls the bits in the window.
@@ -1103,36 +1105,21 @@ XFillArcs(
int
TkScrollWindow(
Tk_Window tkwin, /* The window to be scrolled. */
- TCL_UNUSED(GC), /* GC for window to be scrolled. */
+ GC gc, /* GC for window to be scrolled. */
int x, int y, /* Position rectangle to be scrolled. */
int width, int height,
int dx, int dy, /* Distance rectangle should be moved. */
Region damageRgn) /* Region to accumulate damage in. */
{
Drawable drawable = Tk_WindowId(tkwin);
- MacDrawable *macDraw = (MacDrawable *)drawable;
- TKContentView *view = (TKContentView *)TkMacOSXGetNSViewForDrawable(macDraw);
HIShapeRef srcRgn, dstRgn;
HIMutableShapeRef dmgRgn = HIShapeCreateMutable();
- NSRect bounds, viewSrcRect, srcRect, dstRect;
+ NSRect srcRect, dstRect;
int result = 0;
- if (view) {
-
- /*
- * Get the scroll area in NSView coordinates (origin at bottom left).
- */
-
- bounds = [view bounds];
- viewSrcRect = NSMakeRect(macDraw->xOff + x,
- bounds.size.height - height - (macDraw->yOff + y),
- width, height);
-
- /*
- * Scroll the rectangle.
- */
-
- [view scrollRect:viewSrcRect by:NSMakeSize(dx, -dy)];
+ // Should behave more like TkScrollWindow on other platforms
+ if (XCopyArea(Tk_Display(tkwin), drawable, drawable, gc, x, y,
+ (unsigned)width, (unsigned)height, x+dx, y+dy) == Success) {
/*
* Compute the damage region, using Tk coordinates (origin at top left).
@@ -1237,14 +1224,19 @@ TkMacOSXSetupDrawingContext(
* Intersect the drawable's clipping region with the region stored in the
* X GC. If the resulting region is empty, don't do any drawing.
*/
-
+//#if 0 // disable clipping (almost works, but windows can open up blank)
dc.clipRgn = TkMacOSXGetClipRgn(d);
ClipToGC(d, gc, &dc.clipRgn);
if (dc.clipRgn && HIShapeIsEmpty(dc.clipRgn)) {
+ /*
+ * Things are probably not set up for drawing yet. Request a call to
+ * updateLayer and return failure.
+ */
canDraw = false;
+ [view setNeedsDisplay:YES];
goto end;
}
-
+//#endif //disable clipping
/*
* If the drawable already has a CGContext, use it. Otherwise, we must be
* drawing to a window and we use the current context of its ContentView.
@@ -1252,53 +1244,67 @@ TkMacOSXSetupDrawingContext(
dc.context = TkMacOSXGetCGContextForDrawable(d);
if (!dc.context) {
- NSRect drawingBounds, currentBounds;
dc.view = view;
- dc.context = GET_CGCONTEXT;
+ dc.context = view.tkLayerBitmapContext;
if (dc.clipRgn) {
CGRect clipBounds;
CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
.ty = [view bounds].size.height};
HIShapeGetBounds(dc.clipRgn, &clipBounds);
clipBounds = CGRectApplyAffineTransform(clipBounds, t);
- drawingBounds = NSRectFromCGRect(clipBounds);
- } else {
- drawingBounds = [view bounds];
}
/*
- * We can only draw into the NSView which is the current focusView.
- * When the current [NSView focusView] is nil, the CGContext for
- * [NSGraphicsContext currentContext] is nil. Otherwise the current
- * CGContext draws into the current focusView. An NSView is guaranteed
- * to be the focusView when its drawRect or setFrame methods are
- * running. Prior to OSX 10.14 it was also possible to call the
- * lockFocus method to force an NSView to become the current focusView.
- * But that method was deprecated in 10.14 and so is no longer used by
- * Tk. Instead, if the view is not the current focusView then we add
- * the drawing bounds to its dirty rectangle and return false. The
- * part of the view inside the drawing bounds will get redrawn during
- * the next call to its drawRect method.
+ * Mark the view as needing to be redisplayed, since we are drawing
+ * to its backing layer.
*/
- if (view != [NSView focusView]) {
- [view addTkDirtyRect:drawingBounds];
- canDraw = false;
- goto end;
- }
+ [view setTkNeedsDisplay:YES];
/*
- * Drawing will also fail when the view is the current focusView but
- * the clipping rectangle set by drawRect does not contain the clipping
- * region of our drawing context. (See bug [2a61eca3a8].) If part of
- * the drawing bounds will be clipped then we draw whatever we can, but
- * we also add the drawing bounds to the view's dirty rectangle so it
- * will get redrawn in the next call to its drawRect method.
+ * Workaround for an Apple bug.
+ *
+ * Without the block below, ttk frames, labelframes and labels do not
+ * get the correct background color on macOS 12.5 after the appearance
+ * changes. This function is only called when drawing, so we know that
+ * our view is the focus view. Even though the effective appearance of
+ * the view has been changed, the currentAppearance, i.e. the
+ * appearance that will be used for drawing, may not have been changed
+ * to match.
+ *
+ * Prior to macOS 12.0 the currentAppearance property of NSAppearance
+ * was settable. In macOS 12.0 currentAppearance was deprecated and
+ * replaced by the read-only property currentDrawingAppearance. The
+ * ttk color issues are fixed by setting the currentAppearance to
+ * the effectiveAppearance of the view. So we are forced to use this
+ * deprecated function until Apple fixes this.
+ *
+ * It is a mystery why this only affects the ttk widgets. A possible
+ * clue is that when drawing a ttk widget this function is called with
+ * a NULL gc, whereas the gc is non-null when it is called for drawing
+ * a Tk widget. This means that the CGContext setup below is not done
+ * for ttk widgets. Perhaps that setup triggers an update of the
+ * currentAppearance property, but that has not been verified.
*/
- currentBounds = NSRectFromCGRect(CGContextGetClipBoundingBox(dc.context));
- if (!NSContainsRect(currentBounds, drawingBounds)) {
- [view addTkDirtyRect:drawingBounds];
+ if (@available(macOS 12.0, *)) {
+ NSAppearance *current = NSAppearance.currentDrawingAppearance;
+ NSAppearance *effective = view.effectiveAppearance;
+ if( current != effective) {
+ // printf("Appearances are out of sync!\n");
+ // Deprecations be damned!
+ NSAppearance.currentAppearance = effective;
+ }
+ } else {
+ /*
+ *It is not clear if this is a problem before macos 12.0, but
+ * we might as well do the update anyway.
+ */
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
+/* currentAppearance is not deprecated. */
+ NSAppearance.currentAppearance = view.effectiveAppearance;
+#endif
}
}
@@ -1324,6 +1330,7 @@ TkMacOSXSetupDrawingContext(
};
CGContextConcatCTM(dc.context, t);
}
+//#if 0 // disable clipping
if (dc.clipRgn) {
#ifdef TK_MAC_DEBUG_DRAWING
@@ -1369,6 +1376,8 @@ TkMacOSXSetupDrawingContext(
CGContextClipToRect(dc.context, r);
}
}
+//#endif //disable clipping
+
if (gc) {
static const CGLineCap cgCap[] = {
[CapNotLast] = kCGLineCapButt,
@@ -1438,6 +1447,8 @@ end:
dc.clipRgn = NULL;
}
*dcPtr = dc;
+ // The goal is to allow immediate drawing; canDraw == 0 should happen far less often.
+ if (0) fprintf(stderr, "tkmacosxsdc canDraw %d\n", canDraw);
return canDraw;
}
@@ -1524,10 +1535,13 @@ TkMacOSXGetClipRgn(
}
if (macDraw->drawRgn) {
+ // The drawRgn is the visRgn intersected with a rectangle which
+ // may be smaller than the widget bounds.
clipRgn = HIShapeCreateCopy(macDraw->drawRgn);
} else if (macDraw->visRgn) {
clipRgn = HIShapeCreateCopy(macDraw->visRgn);
}
+ // A NULL clipRgn does not allow any drawing at all.
return clipRgn;
}
@@ -1537,7 +1551,9 @@ TkMacOSXGetClipRgn(
* Tk_ClipDrawableToRect --
*
* Clip all drawing into the drawable d to the given rectangle. If width
- * or height are negative, reset to no clipping.
+ * or height are negative, reset to no clipping.bThis is called by the
+ * Text widget to display each DLine, and by the Canvas widget when it
+ * is updating a sub rectangle in the canvas.
*
* Results:
* None.
@@ -1566,7 +1582,10 @@ Tk_ClipDrawableToRect(
width, height);
HIShapeRef drawRgn = HIShapeCreateWithRect(&clipRect);
- if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) {
+ // When drawing a Text widget we can reuse the
+ // clipping region for different DLines, so we don't want to
+ // update unless necessary.
+ if (macDraw->winPtr && (macDraw->flags & TK_CLIP_INVALID)) {
TkMacOSXUpdateClipRgn(macDraw->winPtr);
}
if (macDraw->visRgn) {
diff --git a/macosx/tkMacOSXEmbed.c b/macosx/tkMacOSXEmbed.c
index ef4f44d..f95d5d1 100644
--- a/macosx/tkMacOSXEmbed.c
+++ b/macosx/tkMacOSXEmbed.c
@@ -850,12 +850,12 @@ EmbedStructureProc(
if (eventPtr->type == ConfigureNotify) {
/*
- * Send a ConfigureNotify to the embedded application.
- */
+ * Send a ConfigureNotify to the embedded application.
+ */
- if (containerPtr->embeddedPtr != NULL) {
- TkDoConfigureNotify(containerPtr->embeddedPtr);
- }
+ if (containerPtr->embeddedPtr != NULL) {
+ TkDoConfigureNotify(containerPtr->embeddedPtr);
+ }
if (containerPtr->embedded != None) {
/*
* Ignore errors, since the embedded application could have
diff --git a/macosx/tkMacOSXEvent.c b/macosx/tkMacOSXEvent.c
index 4f36915..63493bc 100644
--- a/macosx/tkMacOSXEvent.c
+++ b/macosx/tkMacOSXEvent.c
@@ -35,7 +35,7 @@ enum {
switch ((NSInteger)type) {
case NSAppKitDefined:
- subtype = [theEvent subtype];
+ subtype = [theEvent subtype];
switch (subtype) {
/* Ignored at the moment. */
@@ -49,11 +49,11 @@ enum {
break;
case NSWindowMovedEventType:
break;
- case NSWindowWillMoveEventType:
- break;
+ case NSWindowWillMoveEventType:
+ break;
- default:
- break;
+ default:
+ break;
}
break; /* AppkitEvent. Return theEvent */
case NSKeyUp:
@@ -80,7 +80,7 @@ enum {
break; /* Mouse event. Return the processed event. */
#if 0
case NSSystemDefined:
- subtype = [theEvent subtype];
+ subtype = [theEvent subtype];
break;
case NSApplicationDefined: {
id win;
@@ -88,14 +88,14 @@ enum {
break;
}
case NSCursorUpdate:
- break;
+ break;
case NSEventTypeGesture:
case NSEventTypeMagnify:
case NSEventTypeRotate:
case NSEventTypeSwipe:
case NSEventTypeBeginGesture:
case NSEventTypeEndGesture:
- break;
+ break;
#endif
default:
diff --git a/macosx/tkMacOSXFileTypes.c b/macosx/tkMacOSXFileTypes.c
index 5df7ddd..acf2da9 100644
--- a/macosx/tkMacOSXFileTypes.c
+++ b/macosx/tkMacOSXFileTypes.c
@@ -26,9 +26,9 @@ without generating deprecation warnings.
#include "tkMacOSXPrivate.h"
#define CHARS_TO_OSTYPE(string) (OSType) string[0] << 24 | \
- (OSType) string[1] << 16 | \
- (OSType) string[2] << 8 | \
- (OSType) string[3]
+ (OSType) string[1] << 16 | \
+ (OSType) string[2] << 8 | \
+ (OSType) string[3]
MODULE_SCOPE NSString *TkMacOSXOSTypeToUTI(OSType ostype) {
char string[5];
diff --git a/macosx/tkMacOSXHLEvents.c b/macosx/tkMacOSXHLEvents.c
index 8e1fff5..0d07fdf 100644
--- a/macosx/tkMacOSXHLEvents.c
+++ b/macosx/tkMacOSXHLEvents.c
@@ -307,34 +307,34 @@ static const char getSdefProc[] = "::tk::mac::GetDynamicSdef";
/*
* This descriptor can be coerced to a file url. Construct a Tcl
* expression which passes the file path as a string argument to
- * ::tk::mac::DoScriptFile.
+ * ::tk::mac::DoScriptFile.
*/
if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeFileURL, &type,
- (Ptr) URLBuffer, URL_MAX_LENGTH, &actual)) {
- if (actual > 0) {
- URLBuffer[actual] = '\0';
- NSString *urlString = [NSString stringWithUTF8String:(char*)URLBuffer];
- NSURL *fileURL = [NSURL URLWithString:urlString];
- AppleEventInfo *AEInfo = (AppleEventInfo *)ckalloc(sizeof(AppleEventInfo));
- Tcl_DString *scriptFileCommand = &AEInfo->command;
- Tcl_DStringInit(scriptFileCommand);
- Tcl_DStringAppend(scriptFileCommand, scriptFileProc, TCL_INDEX_NONE);
- Tcl_DStringAppendElement(scriptFileCommand, [[fileURL path] UTF8String]);
- AEInfo->interp = _eventInterp;
- AEInfo->procedure = scriptFileProc;
- AEInfo->replyEvent = nil;
+ (Ptr) URLBuffer, URL_MAX_LENGTH, &actual)) {
+ if (actual > 0) {
+ URLBuffer[actual] = '\0';
+ NSString *urlString = [NSString stringWithUTF8String:(char*)URLBuffer];
+ NSURL *fileURL = [NSURL URLWithString:urlString];
+ AppleEventInfo *AEInfo = (AppleEventInfo *)ckalloc(sizeof(AppleEventInfo));
+ Tcl_DString *scriptFileCommand = &AEInfo->command;
+ Tcl_DStringInit(scriptFileCommand);
+ Tcl_DStringAppend(scriptFileCommand, scriptFileProc, TCL_INDEX_NONE);
+ Tcl_DStringAppendElement(scriptFileCommand, [[fileURL path] UTF8String]);
+ AEInfo->interp = _eventInterp;
+ AEInfo->procedure = scriptFileProc;
+ AEInfo->replyEvent = nil;
AEInfo->retryCount = 0;
- ProcessAppleEvent((void *)AEInfo);
- }
- }
+ ProcessAppleEvent((void *)AEInfo);
+ }
+ }
} else if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
NULL, 0, &actual)) {
- /*
- * The descriptor cannot be coerced to a file URL but can be coerced to
- * text. Construct a Tcl expression which passes the text as a string
- * argument to ::tk::mac::DoScriptText.
- */
+ /*
+ * The descriptor cannot be coerced to a file URL but can be coerced to
+ * text. Construct a Tcl expression which passes the text as a string
+ * argument to ::tk::mac::DoScriptText.
+ */
if (actual > 0) {
char *data = (char *)ckalloc(actual + 1);
@@ -350,23 +350,23 @@ static const char getSdefProc[] = "::tk::mac::GetDynamicSdef";
AEInfo->interp = _eventInterp;
AEInfo->procedure = scriptTextProc;
AEInfo->retryCount = 0;
- if (Tcl_FindCommand(AEInfo->interp, AEInfo->procedure, NULL, 0)) {
- AEInfo->replyEvent = replyEvent;
- ProcessAppleEvent(AEInfo);
- } else {
- AEInfo->replyEvent = nil;
- ProcessAppleEvent(AEInfo);
- }
+ if (Tcl_FindCommand(AEInfo->interp, AEInfo->procedure, NULL, 0)) {
+ AEInfo->replyEvent = replyEvent;
+ ProcessAppleEvent(AEInfo);
+ } else {
+ AEInfo->replyEvent = nil;
+ ProcessAppleEvent(AEInfo);
+ }
}
}
}
}
- (void)handleURLEvent:(NSAppleEventDescriptor*)event
- withReplyEvent:(NSAppleEventDescriptor*)replyEvent
+ withReplyEvent:(NSAppleEventDescriptor*)replyEvent
{
NSString* url = [[event paramDescriptorForKeyword:keyDirectObject]
- stringValue];
+ stringValue];
const char *cURL=[url UTF8String];
AppleEventInfo *AEInfo = (AppleEventInfo *)ckalloc(sizeof(AppleEventInfo));
Tcl_DString *launchCommand = &AEInfo->command;
@@ -456,18 +456,18 @@ static void ProcessAppleEvent(
Tcl_DStringLength(&AEInfo->command), TCL_EVAL_GLOBAL);
if (AEInfo->replyEvent && code >= 0) {
- Tcl_Size reslen;
- const char *result = Tcl_GetStringFromObj(Tcl_GetObjResult(AEInfo->interp),
- &reslen);
- if (code == TCL_OK) {
- AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
- keyDirectObject, typeChar, result, reslen);
- } else {
- AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
- keyErrorString, typeChar, result, reslen);
- AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
- keyErrorNumber, typeSInt32, (Ptr) &code, sizeof(int));
- }
+ Tcl_Size reslen;
+ const char *result = Tcl_GetStringFromObj(Tcl_GetObjResult(AEInfo->interp),
+ &reslen);
+ if (code == TCL_OK) {
+ AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
+ keyDirectObject, typeChar, result, reslen);
+ } else {
+ AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
+ keyErrorString, typeChar, result, reslen);
+ AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
+ keyErrorNumber, typeSInt32, (Ptr) &code, sizeof(int));
+ }
} else if (code != TCL_OK) {
Tcl_BackgroundException(AEInfo->interp, code);
}
@@ -537,8 +537,8 @@ TkMacOSXInitAppleEvents(
/*
* We do not load our sdef dynamically but this event handler
- * is required to silence error messages from inline execution
- * of AppleScript at the Objective-C level.
+ * is required to silence error messages from inline execution
+ * of AppleScript at the Objective-C level.
*/
[aeManager setEventHandler:NSApp
andSelector:@selector(handleGetSDEFEvent:withReplyEvent:)
diff --git a/macosx/tkMacOSXImage.c b/macosx/tkMacOSXImage.c
index 30cfc60..488f029 100644
--- a/macosx/tkMacOSXImage.c
+++ b/macosx/tkMacOSXImage.c
@@ -19,6 +19,10 @@
#include "tkColor.h"
#include "xbytes.h"
+static CGImageRef CreateCGImageFromPixmap(Drawable pixmap);
+static CGImageRef CreateCGImageFromDrawableRect( Drawable drawable, int force_1x_scale,
+ int x, int y, unsigned int width, unsigned int height);
+
/* Pixel formats
*
* Tk uses the XImage structure defined in Xlib.h for storing images. The
@@ -510,8 +514,16 @@ TkMacOSXPutImage(
return BadDrawable;
}
if (dc.context) {
- CGRect bounds, srcRect, dstRect;
+ CGRect dstRect, srcRect = CGRectMake(src_x, src_y, width, height);
+ /*
+ * Whole image is copied before cropping. For performance,
+ * consider revising TkMacOSXCreateCGImageWithXImage() to accept
+ * source x/y/w/h and copy only the needed portion instead.
+ */
CGImageRef img = TkMacOSXCreateCGImageWithXImage(image, pixelFormat);
+ CGImageRef cropped = CGImageCreateWithImageInRect(img, srcRect);
+ CGImageRelease(img);
+ img = cropped;
/*
* The CGContext for a pixmap is RGB only, with A = 0.
@@ -521,12 +533,9 @@ TkMacOSXPutImage(
CGContextSetBlendMode(dc.context, kCGBlendModeSourceAtop);
}
if (img) {
- bounds = CGRectMake(0, 0, image->width, image->height);
- srcRect = CGRectMake(src_x, src_y, width, height);
dstRect = CGRectMake(dest_x, dest_y, width, height);
- TkMacOSXDrawCGImage(drawable, gc, dc.context,
- img, gc->foreground, gc->background,
- bounds, srcRect, dstRect);
+ TkMacOSXDrawCGImage(drawable, gc, dc.context, img,
+ gc->foreground, gc->background, dstRect);
CFRelease(img);
} else {
TkMacOSXDbgMsg("Invalid source drawable");
@@ -620,6 +629,11 @@ int TkpPutRGBAImage(
* with origin at the top left, as used by XImage and CGImage, not bottom
* left as used by NSView.
*
+ * If force_1x_scale is true, then the returned CGImage will be downscaled
+ * if necessary to have the requested width and height. Othewise, for
+ * windows on Retina displays, the width and height of the returned CGImage
+ * will be twice the requested width and height.
+ *
* Side effects:
* None
*
@@ -629,6 +643,7 @@ int TkpPutRGBAImage(
static CGImageRef
CreateCGImageFromDrawableRect(
Drawable drawable,
+ int force_1x_scale,
int x,
int y,
unsigned int width,
@@ -637,6 +652,7 @@ CreateCGImageFromDrawableRect(
MacDrawable *mac_drawable = (MacDrawable *)drawable;
CGContextRef cg_context = NULL;
CGImageRef cg_image = NULL, result = NULL;
+ CGFloat scaleFactor = 1.0;
if (mac_drawable->flags & TK_IS_PIXMAP) {
cg_context = TkMacOSXGetCGContextForDrawable(drawable);
CGContextRetain(cg_context);
@@ -646,18 +662,9 @@ CreateCGImageFromDrawableRect(
TkMacOSXDbgMsg("Invalid source drawable");
return NULL;
}
- NSSize size = view.frame.size;
- NSUInteger view_width = size.width, view_height = size.height;
- NSUInteger bytesPerPixel = 4,
- bytesPerRow = bytesPerPixel * view_width,
- bitsPerComponent = 8;
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- cg_context = CGBitmapContextCreate(NULL, view_width, view_height,
- bitsPerComponent, bytesPerRow, colorSpace,
- kCGImageAlphaPremultipliedLast |
- kCGBitmapByteOrder32Big);
- CFRelease(colorSpace);
- [view.layer renderInContext:cg_context];
+ scaleFactor = view.layer.contentsScale;
+ cg_context = ((TKContentView *)view).tkLayerBitmapContext;
+ CGContextRetain(cg_context);
}
if (cg_context) {
cg_image = CGBitmapContextCreateImage(cg_context);
@@ -666,8 +673,30 @@ CreateCGImageFromDrawableRect(
if (cg_image) {
CGRect rect = CGRectMake(x + mac_drawable->xOff, y + mac_drawable->yOff,
width, height);
+ rect = CGRectApplyAffineTransform(rect, CGAffineTransformMakeScale(scaleFactor, scaleFactor));
result = CGImageCreateWithImageInRect(cg_image, rect);
CGImageRelease(cg_image);
+ if (force_1x_scale && (scaleFactor != 1.0)) {
+ // See https://web.archive.org/web/20200219030756/http://blog.foundry376.com/2008/07/scaling-a-cgimage/#comment-200
+ // create context, keeping original image properties
+ CGColorSpaceRef colorspace = CGImageGetColorSpace(cg_image);
+ cg_context = CGBitmapContextCreate(NULL, width, height,
+ CGImageGetBitsPerComponent(cg_image),
+ //CGImageGetBytesPerRow(cg_image), // wastes space?
+ CGImageGetBitsPerPixel(cg_image) * width / 8,
+ colorspace,
+ CGImageGetAlphaInfo(cg_image));
+ CGColorSpaceRelease(colorspace);
+ if (cg_context) {
+ // draw image to context (resizing it)
+ CGContextDrawImage(cg_context, CGRectMake(0, 0, width, height),
+ cg_image);
+ // extract resulting image from context
+ result = CGBitmapContextCreateImage(cg_context);
+ CGContextRelease(cg_context);
+ }
+ CGImageRelease(cg_image);
+ }
}
return result;
}
@@ -799,7 +828,8 @@ XGetImage(
return NULL;
}
- cgImage = CreateCGImageFromDrawableRect(drawable, x, y, width, height);
+ // Request 1x-scale image for compatibility
+ cgImage = CreateCGImageFromDrawableRect(drawable, 1, x, y, width, height);
if (cgImage) {
bitmapRep = [NSBitmapImageRep alloc];
[bitmapRep initWithCGImage:cgImage];
@@ -890,9 +920,8 @@ XCopyArea(
int dest_y)
{
TkMacOSXDrawingContext dc;
- MacDrawable *srcDraw = (MacDrawable *)src;
CGImageRef img = NULL;
- CGRect bounds, srcRect, dstRect;
+ CGRect dstRect;
LastKnownRequestProcessed(display)++;
if (!width || !height) {
@@ -909,20 +938,13 @@ XCopyArea(
return BadDrawable;
}
- if (srcDraw->flags & TK_IS_PIXMAP) {
- img = CreateCGImageFromPixmap(src);
- } else if (TkMacOSXGetNSWindowForDrawable(src)) {
- img = CreateCGImageFromDrawableRect(src, src_x, src_y, width, height);
- } else {
- TkMacOSXDbgMsg("Invalid source drawable - neither window nor pixmap.");
- }
+ // Use unscaled source (TkMacOSXDrawCGImage() will implicitly downscale)
+ img = CreateCGImageFromDrawableRect(src, 0, src_x, src_y, width, height);
if (img) {
- bounds = CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height);
- srcRect = CGRectMake(src_x, src_y, width, height);
dstRect = CGRectMake(dest_x, dest_y, width, height);
TkMacOSXDrawCGImage(dst, gc, dc.context, img,
- gc->foreground, gc->background, bounds, srcRect, dstRect);
+ gc->foreground, gc->background, dstRect);
CFRelease(img);
} else {
TkMacOSXDbgMsg("Failed to construct CGImage.");
@@ -967,7 +989,7 @@ XCopyPlane(
TkMacOSXDrawingContext dc;
MacDrawable *srcDraw = (MacDrawable *)src;
MacDrawable *dstDraw = (MacDrawable *)dst;
- CGRect bounds, srcRect, dstRect;
+ CGRect srcRect, dstRect;
LastKnownRequestProcessed(display)++;
if (!width || !height) {
/* TkMacOSXDbgMsg("Drawing of empty area requested"); */
@@ -990,7 +1012,7 @@ XCopyPlane(
TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask;
unsigned long imageBackground = gc->background;
- if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP) {
+ if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP) {
srcRect = CGRectMake(src_x, src_y, width, height);
CGImageRef mask = CreateCGImageFromPixmap(
clipPtr->value.pixmap);
@@ -1033,13 +1055,9 @@ XCopyPlane(
CGImageRelease(submask);
CGImageRelease(subimage);
} else {
- bounds = CGRectMake(0, 0,
- srcDraw->size.width, srcDraw->size.height);
- srcRect = CGRectMake(src_x, src_y, width, height);
dstRect = CGRectMake(dest_x, dest_y, width, height);
TkMacOSXDrawCGImage(dst, gc, dc.context, img,
- gc->foreground, imageBackground, bounds,
- srcRect, dstRect);
+ gc->foreground, imageBackground, dstRect);
CGImageRelease(img);
}
} else {
@@ -1369,7 +1387,7 @@ TkMacOSXNSImageConfigureModel(
case NAME_SOURCE:
Tcl_SetObjResult(interp, Tcl_NewStringObj("Unknown named NSImage.\n"
"Try omitting ImageName, "
- "e.g. use NSCaution for NSImageNameCaution.", TCL_INDEX_NONE));
+ "e.g. use NSCaution for NSImageNameCaution.", TCL_INDEX_NONE));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SYSTEM", "BAD_VALUE", NULL);
goto errorExit;
case FILE_SOURCE:
@@ -1473,9 +1491,9 @@ TkMacOSXNSImageObjCmd(
objPtr = Tk_GetOptionValue(interp, (char *)modelPtr, optionTable,
objv[2], NULL);
if (objPtr == NULL) {
- goto error;
- }
- Tcl_SetObjResult(interp, objPtr);
+ goto error;
+ }
+ Tcl_SetObjResult(interp, objPtr);
break;
case CONFIGURE:
if (objc == 2) {
diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c
index 03a05fc..bbd41ee 100644
--- a/macosx/tkMacOSXInit.c
+++ b/macosx/tkMacOSXInit.c
@@ -41,8 +41,6 @@ static Tcl_ObjCmdProc TkMacOSVersionObjCmd;
@implementation TKApplication
@synthesize poolLock = _poolLock;
@synthesize macOSVersion = _macOSVersion;
-@synthesize isDrawing = _isDrawing;
-@synthesize isSigned = _isSigned;
@synthesize tkLiveResizeEnded = _tkLiveResizeEnded;
@synthesize tkPointerWindow = _tkPointerWindow;
- (void) setTkPointerWindow: (TkWindow *)winPtr
@@ -290,12 +288,6 @@ static Tcl_ObjCmdProc TkMacOSVersionObjCmd;
[NSApp setMacOSVersion: 10000*majorVersion + 100*minorVersion];
/*
- * We are not drawing right now.
- */
-
- [NSApp setIsDrawing:NO];
-
- /*
* Be our own delegate.
*/
@@ -394,7 +386,7 @@ static void closePanels(
[[NSFontPanel sharedFontPanel] orderOut:nil];
}
if ([NSColorPanel sharedColorPanelExists]) {
- [[NSColorPanel sharedColorPanel] orderOut:nil];
+ [[NSColorPanel sharedColorPanel] orderOut:nil];
}
}
@@ -431,6 +423,18 @@ TCL_NORETURN void TkpExitProc(
}
/*
+ * At this point it is too late to be looking up the Tk window associated
+ * to any NSWindows, but it can happen. This makes sure the answer is None
+ * if such a query is attempted.
+ */
+
+ for (TKWindow *w in [NSApp orderedWindows]) {
+ if ([w respondsToSelector: @selector (tkWindow)]) {
+ [w setTkWindow: None];
+ }
+ }
+
+ /*
* Tcl_Exit does not call Tcl_Finalize if there is an exit proc installed.
*/
@@ -471,7 +475,7 @@ TkpInit(
if (!initialized) {
struct stat st;
Bool shouldOpenConsole = NO;
- Bool stdinIsNullish = (!isatty(0) &&
+ Bool stdinIsNullish = (!isatty(0) &&
(fstat(0, &st) || (S_ISCHR(st.st_mode) && st.st_blocks == 0)));
/*
@@ -495,7 +499,7 @@ TkpInit(
if (Tcl_MacOSXOpenVersionedBundleResources(interp,
"com.tcltk.tklibrary", TK_FRAMEWORK_VERSION, 0, PATH_MAX,
tkLibPath) != TCL_OK) {
- # if 0 /* This is not really an error. Wish still runs fine. */
+ # if 0 /* This is not really an error. Wish still runs fine. */
TkMacOSXDbgMsg("Tcl_MacOSXOpenVersionedBundleResources failed");
# endif
}
@@ -517,40 +521,40 @@ TkpInit(
[TKApplication sharedApplication];
[pool drain];
- /*
- * WARNING: The finishLaunching method runs asynchronously. This
- * creates a race between the initialization of the NSApplication and
- * the initialization of Tk. If Tk wins the race bad things happen
- * with the root window (see below). If the NSApplication wins then an
- * AppleEvent created during launch, e.g. by dropping a file icon on
- * the application icon, will be delivered before the procedure meant
- * to to handle the AppleEvent has been defined. This is handled in
- * tkMacOSXHLEvents.c by scheduling a timer event to handle the
- * AppleEvent later, after the required procedure has been defined.
- */
+ /*
+ * WARNING: The finishLaunching method runs asynchronously. This
+ * creates a race between the initialization of the NSApplication and
+ * the initialization of Tk. If Tk wins the race bad things happen
+ * with the root window (see below). If the NSApplication wins then an
+ * AppleEvent created during launch, e.g. by dropping a file icon on
+ * the application icon, will be delivered before the procedure meant
+ * to to handle the AppleEvent has been defined. This is handled in
+ * tkMacOSXHLEvents.c by scheduling a timer event to handle the
+ * AppleEvent later, after the required procedure has been defined.
+ */
[NSApp _setup:interp];
[NSApp finishLaunching];
- /*
- * Create a Tk event source based on the Appkit event queue.
- */
+ /*
+ * Create a Tk event source based on the Appkit event queue.
+ */
Tk_MacOSXSetupTkNotifier();
/*
* If Tk initialization wins the race, the root window is mapped before
- * the NSApplication is initialized. This can cause bad things to
- * happen. The root window can open off screen with no way to make it
- * appear on screen until the app icon is clicked. This will happen if
- * a Tk application opens a modal window in its startup script (see
- * ticket 56a1823c73). In other cases, an empty root window can open
- * on screen and remain visible for a noticeable amount of time while
- * the Tk initialization finishes (see ticket d1989fb7cf). The call
- * below forces Tk to block until the Appkit event queue has been
- * created. This seems to be sufficient to ensure that the
- * NSApplication initialization wins the race, avoiding these bad
- * window behaviors.
+ * the NSApplication is initialized. This can cause bad things to
+ * happen. The root window can open off screen with no way to make it
+ * appear on screen until the app icon is clicked. This will happen if
+ * a Tk application opens a modal window in its startup script (see
+ * ticket 56a1823c73). In other cases, an empty root window can open
+ * on screen and remain visible for a noticeable amount of time while
+ * the Tk initialization finishes (see ticket d1989fb7cf). The call
+ * below forces Tk to block until the Appkit event queue has been
+ * created. This seems to be sufficient to ensure that the
+ * NSApplication initialization wins the race, avoiding these bad
+ * window behaviors.
*/
Tcl_DoOneEvent(TCL_WINDOW_EVENTS | TCL_DONT_WAIT);
@@ -675,7 +679,7 @@ TkpInit(
Tcl_CreateObjCommand(interp, "::tk::mac::GetAppPath",
TkMacOSXGetAppPathObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "::tk::mac::macOSVersion",
- TkMacOSVersionObjCmd, NULL, NULL);
+ TkMacOSVersionObjCmd, NULL, NULL);
MacSystrayInit(interp);
MacPrint_Init(interp);
diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c
index a16eb42..42698ca 100644
--- a/macosx/tkMacOSXKeyEvent.c
+++ b/macosx/tkMacOSXKeyEvent.c
@@ -64,8 +64,8 @@ static NSUInteger textInputModifiers;
static NSMutableArray *nsEvArray = nil;
if (nsEvArray == nil) {
- nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
- processingCompose = NO;
+ nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
+ processingCompose = NO;
}
if (!winPtr) {
return theEvent;
@@ -80,7 +80,7 @@ static NSUInteger textInputModifiers;
if ([theEvent type] == NSKeyDown &&
[theEvent isARepeat] &&
[NSEvent keyRepeatDelay] < 0) {
- return theEvent;
+ return theEvent;
}
/*
@@ -311,7 +311,7 @@ static NSUInteger textInputModifiers;
Bool sendingIMEText = NO;
str = ([aString isKindOfClass: [NSAttributedString class]]) ?
- [aString string] : aString;
+ [aString string] : aString;
len = [str length];
if (NS_KEYLOG) {
@@ -426,7 +426,7 @@ static NSUInteger textInputModifiers;
(void)selRange;
str = ([aString isKindOfClass: [NSAttributedString class]]) ?
- [aString string] : aString;
+ [aString string] : aString;
if (focusWin) {
/*
@@ -636,12 +636,12 @@ setupXEvent(XEvent *xEvent, Tk_Window tkwin, NSUInteger modifiers)
display = Tk_Display(tkwin);
if (modifiers) {
state = (modifiers & NSAlphaShiftKeyMask ? LockMask : 0) |
- (modifiers & NSShiftKeyMask ? ShiftMask : 0) |
- (modifiers & NSControlKeyMask ? ControlMask : 0) |
- (modifiers & NSCommandKeyMask ? Mod1Mask : 0) |
- (modifiers & NSAlternateKeyMask ? Mod2Mask : 0) |
- (modifiers & NSNumericPadKeyMask ? Mod3Mask : 0) |
- (modifiers & NSFunctionKeyMask ? Mod4Mask : 0) ;
+ (modifiers & NSShiftKeyMask ? ShiftMask : 0) |
+ (modifiers & NSControlKeyMask ? ControlMask : 0) |
+ (modifiers & NSCommandKeyMask ? Mod1Mask : 0) |
+ (modifiers & NSAlternateKeyMask ? Mod2Mask : 0) |
+ (modifiers & NSNumericPadKeyMask ? Mod3Mask : 0) |
+ (modifiers & NSFunctionKeyMask ? Mod4Mask : 0) ;
}
memset(xEvent, 0, sizeof(XEvent));
xEvent->xany.serial = LastKnownRequestProcessed(display);
diff --git a/macosx/tkMacOSXKeyboard.c b/macosx/tkMacOSXKeyboard.c
index 3874dbd..f898496 100644
--- a/macosx/tkMacOSXKeyboard.c
+++ b/macosx/tkMacOSXKeyboard.c
@@ -268,7 +268,7 @@ UpdateKeymaps()
*/
for (index = 3; index >= 0; index--) {
- for (virt = 0; virt < 128; virt++) {
+ for (virt = 0; virt < 128; virt++) {
MacKeycode macKC;
macKC.v = (keycode_v) {.virt = virt, .o_s = index, .keychar = 0};
int modifiers = INDEX2CARBON(index);
@@ -288,7 +288,7 @@ UpdateKeymaps()
hPtr = Tcl_CreateHashEntry(&unichar2xvirtual,
INT2PTR(macKC.x.keychar), &dummy);
Tcl_SetHashValue(hPtr, INT2PTR(macKC.x.xvirtual));
- }
+ }
xvirtual2unichar[macKC.x.xvirtual] = macKC.x.keychar;
}
}
diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c
index 1908bb9..bf41d66 100644
--- a/macosx/tkMacOSXMenu.c
+++ b/macosx/tkMacOSXMenu.c
@@ -960,8 +960,6 @@ TkpPostMenu(
}
realWin = Tk_Parent(realWin);
}
- NSWindow *win = [realWinView window];
- NSView *view = [win contentView];
NSMenu *menu = (NSMenu *) menuPtr->platformData;
NSInteger itemIndex = index;
NSInteger numItems = [menu numberOfItems];
@@ -971,8 +969,8 @@ TkpPostMenu(
inPostMenu = true;
result = TkPreprocessMenu(menuPtr);
if (result != TCL_OK) {
- inPostMenu = false;
- return result;
+ inPostMenu = false;
+ return result;
}
if (itemIndex >= numItems) {
itemIndex = numItems - 1;
@@ -991,8 +989,9 @@ TkpPostMenu(
}
[menu popUpMenuPositioningItem:item
- atLocation:[win tkConvertPointFromScreen:location]
- inView:view];
+ atLocation:location
+ inView:nil
+ appearance:realWinView.effectiveAppearance];
inPostMenu = false;
return TCL_OK;
}
diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c
index ac7befd..6d71ffc 100644
--- a/macosx/tkMacOSXMenubutton.c
+++ b/macosx/tkMacOSXMenubutton.c
@@ -173,7 +173,7 @@ TkpDisplayMenuButton(
butPtr->flags &= ~REDRAW_PENDING;
if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
- return;
+ return;
}
pixmap = (Pixmap) Tk_WindowId(tkwin);
@@ -191,7 +191,7 @@ TkpDisplayMenuButton(
*/
if (butPtr->highlightWidth < 3) {
- if (butPtr->flags & GOT_FOCUS) {
+ if (butPtr->flags & GOT_FOCUS) {
GC gc = Tk_GCForColor(butPtr->highlightColorPtr, pixmap);
TkMacOSXDrawSolidBorder(tkwin, gc, 0, butPtr->highlightWidth);
}
@@ -259,23 +259,23 @@ TkpComputeMenuButtonGeometry(
avgWidth = 0;
if (butPtr->image != NULL) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- haveImage = 1;
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
} else if (butPtr->bitmap != None) {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- haveImage = 1;
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
}
if (butPtr->text && strlen(butPtr->text) > 0) {
haveText = 1;
- Tk_FreeTextLayout(butPtr->textLayout);
- butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
- butPtr->text, TCL_INDEX_NONE, 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);
+ Tk_FreeTextLayout(butPtr->textLayout);
+ butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
+ butPtr->text, TCL_INDEX_NONE, 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);
}
/*
@@ -286,7 +286,7 @@ TkpComputeMenuButtonGeometry(
*/
if (haveImage && haveText) {
- switch ((enum compound) butPtr->compound) {
+ switch ((enum compound) butPtr->compound) {
case COMPOUND_TOP:
case COMPOUND_BOTTOM:
/*
@@ -315,33 +315,33 @@ TkpComputeMenuButtonGeometry(
break;
case COMPOUND_NONE:
break;
- }
+ }
- if (butPtr->width > 0) {
- width = butPtr->width;
- }
- if (butPtr->height > 0) {
- height = butPtr->height;
- }
+ if (butPtr->width > 0) {
+ width = butPtr->width;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height;
+ }
} else {
- if (haveImage) { /* Image only */
- if (butPtr->width > 0) {
- width = butPtr->width;
- }
- if (butPtr->height > 0) {
- height = butPtr->height;
- }
- } else { /* Text only */
- width = txtWidth;
- height = txtHeight;
- if (butPtr->width > 0) {
- width = butPtr->width * avgWidth + 2*butPtr->padX;
- }
- if (butPtr->height > 0) {
- height = butPtr->height * fm.linespace + 2*butPtr->padY;
- }
- }
+ if (haveImage) { /* Image only */
+ if (butPtr->width > 0) {
+ width = butPtr->width;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height;
+ }
+ } else { /* Text only */
+ width = txtWidth;
+ height = txtHeight;
+ if (butPtr->width > 0) {
+ width = butPtr->width * avgWidth + 2*butPtr->padX;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height * fm.linespace + 2*butPtr->padY;
+ }
+ }
}
butPtr->inset = highlightWidth + butPtr->borderWidth;
@@ -381,30 +381,30 @@ DrawMenuButtonImageAndText(
int fullWidth = 0, fullHeight = 0;
if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
- return;
+ return;
}
DrawParams *dpPtr = &mbPtr->drawParams;
pixmap = (Pixmap) Tk_WindowId(tkwin);
if (butPtr->image != NULL) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- haveImage = 1;
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
} else if (butPtr->bitmap != None) {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- haveImage = 1;
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
}
haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
- int x = 0, y = 0;
+ int x = 0, y = 0;
- textXOffset = 0;
- textYOffset = 0;
- fullWidth = 0;
- fullHeight = 0;
+ textXOffset = 0;
+ textYOffset = 0;
+ fullWidth = 0;
+ fullHeight = 0;
- switch ((enum compound) butPtr->compound) {
+ switch ((enum compound) butPtr->compound) {
case COMPOUND_TOP:
case COMPOUND_BOTTOM:
/*
@@ -435,7 +435,7 @@ DrawMenuButtonImageAndText(
}
fullWidth = butPtr->textWidth + butPtr->padX + width;
fullHeight = (height > butPtr->textHeight ? height :
- butPtr->textHeight);
+ butPtr->textHeight);
textYOffset = (fullHeight - butPtr->textHeight)/2;
imageYOffset = (fullHeight - height)/2;
break;
@@ -446,7 +446,7 @@ DrawMenuButtonImageAndText(
fullWidth = (width > butPtr->textWidth ? width : butPtr->textWidth);
fullHeight = (height > butPtr->textHeight ? height :
- butPtr->textHeight);
+ butPtr->textHeight);
textXOffset = (fullWidth - butPtr->textWidth) / 2;
imageXOffset = (fullWidth - width) / 2;
textYOffset = (fullHeight - butPtr->textHeight) / 2;
@@ -456,54 +456,54 @@ DrawMenuButtonImageAndText(
break;
}
- TkComputeAnchor(butPtr->anchor, tkwin,
- butPtr->padX + butPtr->inset, butPtr->padY + butPtr->inset,
- fullWidth, fullHeight, &x, &y);
- imageXOffset = LEFT_INSET;
- imageYOffset += y;
- textYOffset -= 1;
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->inset, butPtr->padY + butPtr->inset,
+ fullWidth, fullHeight, &x, &y);
+ imageXOffset = LEFT_INSET;
+ imageYOffset += y;
+ textYOffset -= 1;
- if (butPtr->image != NULL) {
+ 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);
+ 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 {
int x, y;
- if (haveImage) {
- TkComputeAnchor(butPtr->anchor, tkwin,
- butPtr->padX + butPtr->borderWidth,
- butPtr->padY + butPtr->borderWidth,
- width, height, &x, &y);
+ if (haveImage) {
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ width, height, &x, &y);
imageXOffset = LEFT_INSET;
imageYOffset += y;
if (butPtr->image != NULL) {
Tk_RedrawImage(butPtr->image, 0, 0, width, height,
pixmap, imageXOffset, imageYOffset);
- } else {
- XSetClipOrigin(butPtr->display, dpPtr->gc, x, y);
- XCopyPlane(butPtr->display, butPtr->bitmap,
+ } 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 {
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+ } else {
textXOffset = LEFT_INSET;
TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
butPtr->textWidth, butPtr->textHeight, &x, &y);
@@ -537,7 +537,7 @@ TkMacOSXDrawMenuButton(
MacMenuButton *mbPtr, /* Mac menubutton. */
TCL_UNUSED(GC), /* The GC we are drawing into - not used */
Pixmap pixmap) /* The pixmap we are drawing into - needed for the
- * bevel button */
+ * bevel button */
{
TkMenuButton *butPtr = (TkMenuButton *) mbPtr;
TkWindow *winPtr = (TkWindow *) butPtr->tkwin;
@@ -552,23 +552,23 @@ TkMacOSXDrawMenuButton(
Tk_Width(butPtr->tkwin), Tk_Height(butPtr->tkwin));
if (useNewerHITools == 1) {
- HIRect contHIRec;
- static HIThemeButtonDrawInfo hiinfo;
+ HIRect contHIRec;
+ static HIThemeButtonDrawInfo hiinfo;
- MenuButtonBackgroundDrawCB(mbPtr, 32, true);
+ MenuButtonBackgroundDrawCB(mbPtr, 32, true);
if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, &dc)) {
return;
}
- 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;
- }
+ 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;
+ }
/*
* To avoid menubuttons with white text on a white background, we
@@ -581,10 +581,10 @@ TkMacOSXDrawMenuButton(
hiinfo.state = kThemeStateInactive;
}
- HIThemeDrawButton(&cntrRect, &hiinfo, dc.context,
+ HIThemeDrawButton(&cntrRect, &hiinfo, dc.context,
kHIThemeOrientationNormal, &contHIRec);
TkMacOSXRestoreDrawingContext(&dc);
- MenuButtonContentDrawCB(mbPtr->btnkind, &mbPtr->drawinfo,
+ MenuButtonContentDrawCB(mbPtr->btnkind, &mbPtr->drawinfo,
mbPtr, 32, true);
} else {
if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, &dc)) {
@@ -623,11 +623,11 @@ MenuButtonBackgroundDrawCB (
Pixmap pixmap;
if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
- return;
+ return;
}
pixmap = (Pixmap) Tk_WindowId(tkwin);
Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
- Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
}
/*
@@ -658,7 +658,7 @@ MenuButtonContentDrawCB (
Tk_Window tkwin = butPtr->tkwin;
if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
- return;
+ return;
}
DrawMenuButtonImageAndText(butPtr);
}
@@ -749,22 +749,22 @@ TkMacOSXComputeMenuButtonParams(
drawinfo->state = kThemeStateInactive;
if ((mbPtr->flags & ACTIVE) == 0) {
- if (butPtr->state == STATE_DISABLED) {
- drawinfo->state = kThemeStateUnavailableInactive;
- } else {
- drawinfo->state = kThemeStateInactive;
- }
+ if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailableInactive;
+ } else {
+ drawinfo->state = kThemeStateInactive;
+ }
} else if (butPtr->state == STATE_DISABLED) {
- drawinfo->state = kThemeStateUnavailable;
+ drawinfo->state = kThemeStateUnavailable;
} else {
- drawinfo->state = kThemeStateActive;
+ drawinfo->state = kThemeStateActive;
}
drawinfo->adornment = kThemeAdornmentNone;
if (butPtr->highlightWidth >= 3) {
- if ((butPtr->flags & GOT_FOCUS)) {
- drawinfo->adornment |= kThemeAdornmentFocus;
- }
+ if ((butPtr->flags & GOT_FOCUS)) {
+ drawinfo->adornment |= kThemeAdornmentFocus;
+ }
}
drawinfo->adornment |= kThemeAdornmentArrowDoubleArrow;
}
@@ -795,12 +795,12 @@ TkMacOSXComputeMenuButtonDrawParams(
((butPtr->image != NULL) || (butPtr->bitmap != None));
dpPtr->border = butPtr->normalBorder;
if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
- dpPtr->gc = butPtr->disabledGC;
+ dpPtr->gc = butPtr->disabledGC;
} else if (butPtr->state == STATE_ACTIVE) {
- dpPtr->gc = butPtr->activeTextGC;
- dpPtr->border = butPtr->activeBorder;
+ dpPtr->gc = butPtr->activeTextGC;
+ dpPtr->border = butPtr->activeBorder;
} else {
- dpPtr->gc = butPtr->normalTextGC;
+ dpPtr->gc = butPtr->normalTextGC;
}
}
diff --git a/macosx/tkMacOSXMenus.c b/macosx/tkMacOSXMenus.c
index b1b8bad..b717352 100644
--- a/macosx/tkMacOSXMenus.c
+++ b/macosx/tkMacOSXMenus.c
@@ -116,18 +116,18 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
_defaultWindowsMenuItems = [_defaultWindowsMenuItems
arrayByAddingObjectsFromArray:
[NSArray arrayWithObjects:
- [NSMenuItem separatorItem],
+ [NSMenuItem separatorItem],
[NSMenuItem itemWithTitle:@"Show Previous Tab"
- action:@selector(selectPreviousTab:)
- target:nil
+ action:@selector(selectPreviousTab:)
+ target:nil
keyEquivalent:@"\t"
- keyEquivalentModifierMask:
+ keyEquivalentModifierMask:
NSControlKeyMask|NSShiftKeyMask],
- [NSMenuItem itemWithTitle:@"Show Next Tab"
- action:@selector(selectNextTab:)
- target:nil
+ [NSMenuItem itemWithTitle:@"Show Next Tab"
+ action:@selector(selectNextTab:)
+ target:nil
keyEquivalent:@"\t"
- keyEquivalentModifierMask:NSControlKeyMask],
+ keyEquivalentModifierMask:NSControlKeyMask],
[NSMenuItem itemWithTitle:@"Move Tab To New Window"
action:@selector(moveTabToNewWindow:)
target:nil],
@@ -135,7 +135,7 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
action:@selector(mergeAllWindows:)
target:nil],
[NSMenuItem separatorItem],
- nil]];
+ nil]];
}
_defaultWindowsMenuItems = [_defaultWindowsMenuItems arrayByAddingObject:
[NSMenuItem itemWithTitle:@"Bring All to Front"
@@ -193,7 +193,7 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp);
}
return haveDemo;
} else {
- return [super validateUserInterfaceItem:anItem];
+ return [super validateUserInterfaceItem:anItem];
}
}
diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c
index 83d2cd2..062a125 100644
--- a/macosx/tkMacOSXMouseEvent.c
+++ b/macosx/tkMacOSXMouseEvent.c
@@ -504,8 +504,9 @@ enum {
state |= Tk_GetButtonMask(Button1);
}
if (eventType == NSMouseEntered) {
- Tk_UpdatePointer((Tk_Window) [NSApp tkPointerWindow],
- global.x, global.y, state);
+ Tk_Window new_win = Tk_CoordsToWindow(global.x, global.y,
+ (Tk_Window) [NSApp tkPointerWindow]);
+ Tk_UpdatePointer(new_win, global.x, global.y, state);
} else if (eventType == NSMouseExited) {
if ([NSApp tkDragTarget]) {
Tk_UpdatePointer((Tk_Window) [NSApp tkDragTarget],
@@ -883,9 +884,9 @@ TkpWarpPointer(
CGWarpMouseCursorPosition(pt);
if (dispPtr->warpWindow) {
- TkGenerateButtonEventForXPointer(Tk_WindowId(dispPtr->warpWindow));
+ TkGenerateButtonEventForXPointer(Tk_WindowId(dispPtr->warpWindow));
} else {
- TkGenerateButtonEventForXPointer(None);
+ TkGenerateButtonEventForXPointer(None);
}
}
diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c
index a20eec2..f353380 100644
--- a/macosx/tkMacOSXNotify.c
+++ b/macosx/tkMacOSXNotify.c
@@ -310,12 +310,12 @@ TkMacOSXNotifyExitHandler(
* This static function is meant to be run as an idle task. It attempts
* to redraw all views which have the tkNeedsDisplay property set to YES.
* This relies on a feature of [NSApp nextEventMatchingMask: ...] which
- * is undocumented, namely that it sometimes blocks and calls drawRect
+ * is undocumented, namely that it sometimes blocks and calls updateLayer
* for all views that need display before it returns. We call it with
* deQueue=NO so that it will not change anything on the AppKit event
* queue, because we only want the side effect that it runs drawRect. The
* only times when any NSViews have the needsDisplay property set to YES
- * are during execution of this function or in the addTkDirtyRect method
+ * are during execution of this function or in the setFrameSize method
* of TKContentView.
*
* The reason for running this function as an idle task is to try to
@@ -342,7 +342,7 @@ void
TkMacOSXDrawAllViews(
void *clientData)
{
- int count = 0, *dirtyCount = (int *)clientData;
+ int count = 0, *dirtyCount = (int *)clientData;
for (NSWindow *window in [NSApp windows]) {
if ([[window contentView] isMemberOfClass:[TKContentView class]]) {
@@ -352,7 +352,6 @@ TkMacOSXDrawAllViews(
if (dirtyCount) {
continue;
}
- [[view layer] setNeedsDisplayInRect:[view tkDirtyRect]];
[view setNeedsDisplay:YES];
}
} else {
@@ -362,26 +361,15 @@ TkMacOSXDrawAllViews(
if (dirtyCount) {
*dirtyCount = count;
}
+
+ /*
+ * Trigger calls to updateLayer methods for the views flagged above.
+ */
+
[NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(TkMacOSXGetModalSession())
dequeue:NO];
- for (NSWindow *window in [NSApp windows]) {
- if ([[window contentView] isMemberOfClass:[TKContentView class]]) {
- TKContentView *view = [window contentView];
-
- /*
- * If we did not run drawRect, we set needsDisplay back to NO.
- * Note that if drawRect did run it may have added to Tk's dirty
- * rect, due to attempts to draw outside of drawRect's dirty rect.
- */
-
- if ([view needsDisplay]) {
- [view setNeedsDisplay: NO];
- }
- }
- }
- [NSApp setNeedsToDraw:NO];
}
/*
@@ -448,11 +436,11 @@ TkMacOSXEventsSetupProc(
*/
NSEvent *currentEvent =
- [NSApp nextEventMatchingMask:NSAnyEventMask
+ [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(TkMacOSXGetModalSession())
dequeue:NO];
- if ((currentEvent) || [NSApp needsToDraw] ) {
+ if ((currentEvent)) {
Tcl_SetMaxBlockTime(&zeroBlockTime);
Tcl_DeleteTimerHandler(ticker);
ticker = NULL;
diff --git a/macosx/tkMacOSXPrint.c b/macosx/tkMacOSXPrint.c
index ee30e1f..ac29714 100644
--- a/macosx/tkMacOSXPrint.c
+++ b/macosx/tkMacOSXPrint.c
@@ -92,8 +92,8 @@ StartPrint(
/* Check for proper number of arguments. */
if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "file");
- return TCL_ERROR;
+ Tcl_WrongNumArgs(interp, 1, objv, "file");
+ return TCL_ERROR;
}
fileName = [NSString stringWithUTF8String: Tcl_GetString(objv[1])];
@@ -105,20 +105,20 @@ StartPrint(
status = PMCreateSession( & printSession);
if (status != noErr) {
- NSLog(@ "Error creating print session.");
- return TCL_ERROR;
+ NSLog(@ "Error creating print session.");
+ return TCL_ERROR;
}
status = PMCreatePrintSettings( & printSettings);
if (status != noErr) {
- NSLog(@ "Error creating print settings.");
- return TCL_ERROR;
+ NSLog(@ "Error creating print settings.");
+ return TCL_ERROR;
}
status = PMSessionDefaultPrintSettings(printSession, printSettings);
if (status != noErr) {
- NSLog(@ "Error creating default print settings.");
- return TCL_ERROR;
+ NSLog(@ "Error creating default print settings.");
+ return TCL_ERROR;
}
printSession = (PMPrintSession)[printInfo PMPrintSession];
@@ -163,25 +163,25 @@ FinishPrint(
* otherwise printing will occur regardless of value.
*/
if (buttonValue == NSModalResponseCancel) {
- return noErr;
+ return noErr;
}
status = PMCreateSession( & printSession);
if (status != noErr) {
- NSLog(@ "Error creating print session.");
- return status;
+ NSLog(@ "Error creating print session.");
+ return status;
}
status = PMCreatePrintSettings( & printSettings);
if (status != noErr) {
- NSLog(@ "Error creating print settings.");
- return status;
+ NSLog(@ "Error creating print settings.");
+ return status;
}
status = PMSessionDefaultPrintSettings(printSession, printSettings);
if (status != noErr) {
- NSLog(@ "Error creating default print settings.");
- return status;
+ NSLog(@ "Error creating default print settings.");
+ return status;
}
printSession = (PMPrintSession)[printInfo PMPrintSession];
@@ -191,81 +191,81 @@ FinishPrint(
/*Handle print operation.*/
if (buttonValue == NSModalResponseOK) {
- if (urlFile == NULL) {
- NSLog(@ "Could not get file to print.");
- return noErr;
- }
-
- fileName = file;
-
- CFURLRef printURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, urlFile, kCFURLPOSIXPathStyle, false);
-
- PMPrinter currentPrinter;
- PMDestinationType printDestination;
-
- /*Get the intended destination.*/
- status = PMSessionGetDestinationType(printSession, printSettings, & printDestination);
-
- /*Destination is printer. Send file to printer.*/
- if (status == noErr && printDestination == kPMDestinationPrinter) {
-
- status = PMSessionGetCurrentPrinter(printSession, & currentPrinter);
- if (status == noErr) {
- CFArrayRef mimeTypes;
- status = PMPrinterGetMimeTypes(currentPrinter, printSettings, & mimeTypes);
- if (status == noErr && mimeTypes != NULL) {
- mimeType = CFSTR("application/pdf");
- if (CFArrayContainsValue(mimeTypes, CFRangeMake(0, CFArrayGetCount(mimeTypes)), mimeType)) {
- status = PMPrinterPrintWithFile(currentPrinter, printSettings, pageFormat, mimeType, printURL);
- CFRelease(urlFile);
- return status;
- }
- }
- }
- }
-
- /* Destination is file. Determine how to handle. */
- if (status == noErr && printDestination == kPMDestinationFile) {
- CFURLRef outputLocation = NULL;
-
- status = PMSessionCopyDestinationLocation(printSession, printSettings, & outputLocation);
- if (status == noErr) {
- /*Get the source file and target destination, convert to strings.*/
- CFStringRef sourceFile = CFURLCopyFileSystemPath(printURL, kCFURLPOSIXPathStyle);
- CFStringRef savePath = CFURLCopyFileSystemPath(outputLocation, kCFURLPOSIXPathStyle);
- NSString * sourcePath = (NSString * ) sourceFile;
- NSString * finalPath = (NSString * ) savePath;
- NSString * pathExtension = [finalPath pathExtension];
- NSFileManager * fileManager = [NSFileManager defaultManager];
+ if (urlFile == NULL) {
+ NSLog(@ "Could not get file to print.");
+ return noErr;
+ }
+
+ fileName = file;
+
+ CFURLRef printURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, urlFile, kCFURLPOSIXPathStyle, false);
+
+ PMPrinter currentPrinter;
+ PMDestinationType printDestination;
+
+ /*Get the intended destination.*/
+ status = PMSessionGetDestinationType(printSession, printSettings, & printDestination);
+
+ /*Destination is printer. Send file to printer.*/
+ if (status == noErr && printDestination == kPMDestinationPrinter) {
+
+ status = PMSessionGetCurrentPrinter(printSession, & currentPrinter);
+ if (status == noErr) {
+ CFArrayRef mimeTypes;
+ status = PMPrinterGetMimeTypes(currentPrinter, printSettings, & mimeTypes);
+ if (status == noErr && mimeTypes != NULL) {
+ mimeType = CFSTR("application/pdf");
+ if (CFArrayContainsValue(mimeTypes, CFRangeMake(0, CFArrayGetCount(mimeTypes)), mimeType)) {
+ status = PMPrinterPrintWithFile(currentPrinter, printSettings, pageFormat, mimeType, printURL);
+ CFRelease(urlFile);
+ return status;
+ }
+ }
+ }
+ }
+
+ /* Destination is file. Determine how to handle. */
+ if (status == noErr && printDestination == kPMDestinationFile) {
+ CFURLRef outputLocation = NULL;
+
+ status = PMSessionCopyDestinationLocation(printSession, printSettings, & outputLocation);
+ if (status == noErr) {
+ /*Get the source file and target destination, convert to strings.*/
+ CFStringRef sourceFile = CFURLCopyFileSystemPath(printURL, kCFURLPOSIXPathStyle);
+ CFStringRef savePath = CFURLCopyFileSystemPath(outputLocation, kCFURLPOSIXPathStyle);
+ NSString * sourcePath = (NSString * ) sourceFile;
+ NSString * finalPath = (NSString * ) savePath;
+ NSString * pathExtension = [finalPath pathExtension];
+ NSFileManager * fileManager = [NSFileManager defaultManager];
NSError * error = nil;
- /*
+ /*
* Is the target file a PDF? If so, copy print file
* to output location.
*/
- if ([pathExtension isEqualToString: @ "pdf"]) {
+ if ([pathExtension isEqualToString: @ "pdf"]) {
/*Make sure no file conflict exists.*/
if ([fileManager fileExistsAtPath: finalPath]) {
[fileManager removeItemAtPath: finalPath error: &error];
}
- if ([fileManager fileExistsAtPath: sourcePath]) {
- error = nil;
- [fileManager copyItemAtPath: sourcePath toPath: finalPath error: & error];
- }
+ if ([fileManager fileExistsAtPath: sourcePath]) {
+ error = nil;
+ [fileManager copyItemAtPath: sourcePath toPath: finalPath error: & error];
+ }
return status;
- }
-
- /*
- * Is the target file PostScript? If so, run print file
- * through CUPS filter to convert back to PostScript.
- */
-
- if ([pathExtension isEqualToString: @ "ps"]) {
- char source[5012];
- char target[5012];
- [sourcePath getCString: source maxLength: (sizeof source) encoding: NSUTF8StringEncoding];
- [finalPath getCString: target maxLength: (sizeof target) encoding: NSUTF8StringEncoding];
+ }
+
+ /*
+ * Is the target file PostScript? If so, run print file
+ * through CUPS filter to convert back to PostScript.
+ */
+
+ if ([pathExtension isEqualToString: @ "ps"]) {
+ char source[5012];
+ char target[5012];
+ [sourcePath getCString: source maxLength: (sizeof source) encoding: NSUTF8StringEncoding];
+ [finalPath getCString: target maxLength: (sizeof target) encoding: NSUTF8StringEncoding];
/*Make sure no file conflict exists.*/
if ([fileManager fileExistsAtPath: finalPath]) {
[fileManager removeItemAtPath: finalPath error: &error];
@@ -290,39 +290,39 @@ FinishPrint(
}
}
- /* Destination is preview. Open file in default application for PDF. */
- if ((status == noErr) && (printDestination == kPMDestinationPreview)) {
- CFStringRef urlpath = CFURLCopyFileSystemPath(printURL, kCFURLPOSIXPathStyle);
- NSString * path = (NSString * ) urlpath;
- NSURL * url = [NSURL fileURLWithPath: path];
- NSWorkspace * ws = [NSWorkspace sharedWorkspace];
- [ws openURL: url];
- status = noErr;
- return status;
- }
-
- /*
- * If destination is not printer, file or preview,
- * we do not support it. Display alert.
- */
+ /* Destination is preview. Open file in default application for PDF. */
+ if ((status == noErr) && (printDestination == kPMDestinationPreview)) {
+ CFStringRef urlpath = CFURLCopyFileSystemPath(printURL, kCFURLPOSIXPathStyle);
+ NSString * path = (NSString * ) urlpath;
+ NSURL * url = [NSURL fileURLWithPath: path];
+ NSWorkspace * ws = [NSWorkspace sharedWorkspace];
+ [ws openURL: url];
+ status = noErr;
+ return status;
+ }
+
+ /*
+ * If destination is not printer, file or preview,
+ * we do not support it. Display alert.
+ */
if (((status == noErr) && (printDestination != kPMDestinationPreview)) || ((status == noErr) && (printDestination != kPMDestinationFile)) || ((status == noErr) && (printDestination != kPMDestinationPrinter))) {
- NSAlert * alert = [[[NSAlert alloc] init] autorelease];
- [alert addButtonWithTitle: @ "OK"];
+ NSAlert * alert = [[[NSAlert alloc] init] autorelease];
+ [alert addButtonWithTitle: @ "OK"];
- [alert setMessageText: @ "Unsupported Printing Operation"];
- [alert setInformativeText: @ "This printing operation is not supported."];
- [alert setAlertStyle: NSAlertStyleInformational];
- [alert runModal];
- return status;
- }
+ [alert setMessageText: @ "Unsupported Printing Operation"];
+ [alert setInformativeText: @ "This printing operation is not supported."];
+ [alert setAlertStyle: NSAlertStyleInformational];
+ [alert runModal];
+ return status;
+ }
}
/* Return because cancel button was clicked. */
if (buttonValue == NSModalResponseCancel) {
- PMRelease(printSession);
- return status;
+ PMRelease(printSession);
+ return status;
}
return status;
diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h
index 151f2f8..5143515 100644
--- a/macosx/tkMacOSXPrivate.h
+++ b/macosx/tkMacOSXPrivate.h
@@ -166,7 +166,7 @@ typedef union MacKeycode_t {
#define ON_KEYPAD(virt) ((virt >= 0x41) && (virt <= 0x5C))
#define IS_PRINTABLE(keychar) ((keychar >= 0x20) && (keychar != 0x7f) && \
- ((keychar < 0xF700) || keychar >= 0xF8FF))
+ ((keychar < 0xF700) || keychar >= 0xF8FF))
/*
* An "index" is 2-bit bitfield showing the state of the Option and Shift
@@ -240,14 +240,14 @@ MODULE_SCOPE int TkMacOSXIsWindowZoomed(TkWindow *winPtr);
MODULE_SCOPE int TkGenerateButtonEventForXPointer(Window window);
MODULE_SCOPE void TkMacOSXDrawCGImage(Drawable d, GC gc, CGContextRef context,
CGImageRef image, unsigned long imageForeground,
- unsigned long imageBackground, CGRect imageBounds,
- CGRect srcBounds, CGRect dstBounds);
+ unsigned long imageBackground, CGRect dstBounds);
MODULE_SCOPE int TkMacOSXSetupDrawingContext(Drawable d, GC gc,
TkMacOSXDrawingContext *dcPtr);
MODULE_SCOPE void TkMacOSXRestoreDrawingContext(
TkMacOSXDrawingContext *dcPtr);
MODULE_SCOPE void TkMacOSXSetColorInContext(GC gc, unsigned long pixel,
CGContextRef context);
+MODULE_SCOPE void TkMacOSXRedrawViewIdleTask(void *clientData);
#define TkMacOSXGetTkWindow(window) ((TkWindow *)Tk_MacOSXGetTkWindow(window))
#define TkMacOSXGetNSWindowForDrawable(drawable) ((NSWindow *)Tk_MacOSXGetNSWindowForDrawable(drawable))
#define TkMacOSXGetNSViewForDrawable(macWin) ((NSView *)Tk_MacOSXGetNSViewForDrawable((Drawable)(macWin)))
@@ -320,9 +320,6 @@ VISIBILITY_HIDDEN
}
@property int poolLock;
@property int macOSVersion;
-@property Bool isDrawing;
-@property Bool needsToDraw;
-@property Bool isSigned;
@property Bool tkLiveResizeEnded;
/*
@@ -392,7 +389,7 @@ VISIBILITY_HIDDEN
- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent;
- (void)handleURLEvent: (NSAppleEventDescriptor*)event
- withReplyEvent: (NSAppleEventDescriptor*)replyEvent;
+ withReplyEvent: (NSAppleEventDescriptor*)replyEvent;
@end
VISIBILITY_HIDDEN
@@ -411,6 +408,7 @@ VISIBILITY_HIDDEN
}
@property Bool tkNeedsDisplay;
@property NSRect tkDirtyRect;
+@property CGContextRef tkLayerBitmapContext;
@end
@interface TKContentView(TKKeyEvent)
@@ -423,6 +421,7 @@ VISIBILITY_HIDDEN
- (void) clearTkDirtyRect;
- (void) generateExposeEvents: (NSRect) rect;
- (void) tkToolbarButton: (id) sender;
+- (void) resetTkLayerBitmapContext;
@end
@interface NSWindow(TKWm)
@@ -467,6 +466,14 @@ VISIBILITY_HIDDEN
- (NSMenuItem *)itemInSupermenu;
@end
+// Need undocumented appearance: argument
+@interface NSMenu(TKMenu)
+- (BOOL)popUpMenuPositioningItem:(NSMenuItem *)item
+ atLocation:(NSPoint)location
+ inView:(NSView *)view
+ appearance:(NSAppearance *)appearance;
+@end
+
@interface NSMenuItem(TKUtils)
+ (id)itemWithSubmenu:(NSMenu *)submenu;
+ (id)itemWithTitle:(NSString *)title submenu:(NSMenu *)submenu;
diff --git a/macosx/tkMacOSXScale.c b/macosx/tkMacOSXScale.c
index 96a61b8..38ff385 100644
--- a/macosx/tkMacOSXScale.c
+++ b/macosx/tkMacOSXScale.c
@@ -169,10 +169,10 @@ TkpDisplayScale(
Tcl_Preserve(scalePtr);
if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) {
Tcl_Preserve(interp);
- if (snprintf(string, TCL_DOUBLE_SPACE, scalePtr->format,
- scalePtr->value) < 0) {
- string[TCL_DOUBLE_SPACE - 1] = '\0';
- }
+ if (snprintf(string, TCL_DOUBLE_SPACE, scalePtr->format,
+ scalePtr->value) < 0) {
+ string[TCL_DOUBLE_SPACE - 1] = '\0';
+ }
Tcl_DStringInit(&buf);
Tcl_DStringAppend(&buf, scalePtr->command, TCL_INDEX_NONE);
Tcl_DStringAppend(&buf, " ", TCL_INDEX_NONE);
diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c
index a420898..1d4ffec 100644
--- a/macosx/tkMacOSXSubwindows.c
+++ b/macosx/tkMacOSXSubwindows.c
@@ -56,32 +56,37 @@ XDestroyWindow(
Window window) /* Window. */
{
MacDrawable *macWin = (MacDrawable *)window;
+ TKContentView *view = (TKContentView *)TkMacOSXGetNSViewForDrawable(macWin);
+ //fprintf(stderr, "XDestroyWindow: %s with parent %s\n",
+ // Tk_PathName(macWin->winPtr),
+ // Tk_PathName(macWin->winPtr->parentPtr));
/*
* Remove any dangling pointers that may exist if the window we are
* deleting is being tracked by the grab code.
*/
- TkPointerDeadWindow(macWin->winPtr);
TkMacOSXSelDeadWindow(macWin->winPtr);
+ TkPointerDeadWindow(macWin->winPtr);
macWin->toplevel->referenceCount--;
if (!Tk_IsTopLevel(macWin->winPtr)) {
- TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
if (macWin->winPtr->parentPtr != NULL) {
TkMacOSXInvalClipRgns((Tk_Window)macWin->winPtr->parentPtr);
+ Tcl_CancelIdleCall(TkMacOSXRedrawViewIdleTask, (void *) view);
+ Tcl_DoWhenIdle(TkMacOSXRedrawViewIdleTask, (void *) view);
}
if (macWin->visRgn) {
CFRelease(macWin->visRgn);
- macWin->visRgn = NULL;
+ macWin->visRgn = NULL;
}
if (macWin->aboveVisRgn) {
CFRelease(macWin->aboveVisRgn);
- macWin->aboveVisRgn = NULL;
+ macWin->aboveVisRgn = NULL;
}
if (macWin->drawRgn) {
CFRelease(macWin->drawRgn);
- macWin->drawRgn = NULL;
+ macWin->drawRgn = NULL;
}
if (macWin->toplevel->referenceCount == 0) {
@@ -93,15 +98,15 @@ XDestroyWindow(
}
if (macWin->visRgn) {
CFRelease(macWin->visRgn);
- macWin->visRgn = NULL;
+ macWin->visRgn = NULL;
}
if (macWin->aboveVisRgn) {
CFRelease(macWin->aboveVisRgn);
- macWin->aboveVisRgn = NULL;
+ macWin->aboveVisRgn = NULL;
}
if (macWin->drawRgn) {
CFRelease(macWin->drawRgn);
- macWin->drawRgn = NULL;
+ macWin->drawRgn = NULL;
}
macWin->view = nil;
macWin->winPtr->privatePtr = NULL;
@@ -147,11 +152,10 @@ XMapWindow(
return BadWindow;
}
MacDrawable *macWin = (MacDrawable *)window;
- TkWindow *winPtr = macWin->winPtr;
- NSWindow *win = TkMacOSXGetNSWindowForDrawable(window);
static Bool initialized = NO;
NSPoint mouse = [NSEvent mouseLocation];
int x = mouse.x, y = TkMacOSXZeroScreenHeight() - mouse.y;
+ //fprintf(stderr, "XMapWindow: %s\n", Tk_PathName(macWin->winPtr));
/*
* Under certain situations it's possible for this function to be called
@@ -165,29 +169,44 @@ XMapWindow(
TkMacOSXMakeRealWindowExist(macWin->toplevel->winPtr);
}
+ TkWindow *winPtr = macWin->winPtr;
+ NSWindow *win = TkMacOSXGetNSWindowForDrawable(window);
+ TKContentView *view = [win contentView];
LastKnownRequestProcessed(display)++;
if (Tk_IsTopLevel(winPtr)) {
if (!Tk_IsEmbedded(winPtr)) {
- TKContentView *view = [win contentView];
/*
- * We want to activate Tk when a toplevel is mapped but we must not
- * supply YES here. This is because during Tk initialization the
- * root window is mapped before applicationDidFinishLaunching
- * returns. Forcing the app to activate too early can make the menu
- * bar unresponsive.
+ * We want to activate Tk when a toplevel is mapped but we can't
+ * always specify activateIgnoringOtherApps to be YES. This is
+ * because during Tk initialization the root window is mapped
+ * before applicationDidFinishLaunching returns. Forcing the app to
+ * activate too early can make the menu bar unresponsive.
*/
TkMacOSXApplyWindowAttributes(winPtr, win);
[win setExcludedFromWindowsMenu:NO];
[NSApp activateIgnoringOtherApps:initialized];
- [view addTkDirtyRect: [view bounds]];
if (initialized) {
if ([win canBecomeKeyWindow]) {
[win makeKeyAndOrderFront:NSApp];
} else {
[win orderFrontRegardless];
}
+
+ /*
+ * Delay for up to 20 milliseconds until the toplevel has
+ * actually become the highest toplevel. This is to ensure
+ * that the Visibility event occurs after the toplevel is
+ * visible.
+ */
+
+ for (int try = 0; try < 20; try++) {
+ if ([[NSApp orderedWindows] firstObject] == win) {
+ break;
+ }
+ [NSThread sleepForTimeInterval:.001];
+ }
}
/*
@@ -208,9 +227,7 @@ XMapWindow(
*/
TkMacOSXInvalClipRgns(contWinPtr);
- TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
}
- TkMacOSXInvalClipRgns((Tk_Window)winPtr);
} else {
/*
@@ -222,14 +239,13 @@ XMapWindow(
}
/*
- * Mark the toplevel as needing to be redrawn, unless the window is being
- * mapped while drawing is taking place.
+ * If a geometry manager is mapping hundreds of windows we
+ * don't want to redraw the view hundreds of times, so do
+ * it in an idle task.
*/
- TKContentView *view = [win contentView];
- if (view != [NSView focusView]) {
- [view addTkDirtyRect:[view bounds]];
- }
+ Tcl_CancelIdleCall(TkMacOSXRedrawViewIdleTask, (void *) view);
+ Tcl_DoWhenIdle(TkMacOSXRedrawViewIdleTask, (void *) view);
/*
* Generate VisibilityNotify events for window and all mapped children.
@@ -253,7 +269,8 @@ XMapWindow(
*
* NotifyVisibility --
*
- * Recursively called helper proc for XMapWindow().
+ * Helper for XMapWindow(). Generates VisibilityNotify events
+ * for the window and all of its descendants.
*
* Results:
* None.
@@ -308,7 +325,6 @@ XUnmapWindow(
{
MacDrawable *macWin = (MacDrawable *)window;
TkWindow *winPtr = macWin->winPtr;
- TkWindow *parentPtr = winPtr->parentPtr;
NSWindow *win = TkMacOSXGetNSWindowForDrawable(window);
if (!window) {
@@ -353,22 +369,12 @@ XUnmapWindow(
} else {
/*
- * Rebuild the visRgn clip region for the parent so it will be allowed
+ * Rebuild the clip regions for the parent so it will be allowed
* to draw in the space from which this subwindow was removed and then
* redraw the window.
*/
- if (parentPtr && parentPtr->privatePtr->visRgn) {
- TkMacOSXInvalidateViewRegion(
- TkMacOSXGetNSViewForDrawable(parentPtr->window),
- parentPtr->privatePtr->visRgn);
- }
- TkMacOSXInvalClipRgns((Tk_Window)parentPtr);
- TkMacOSXUpdateClipRgn(parentPtr);
- }
- TKContentView *view = [win contentView];
- if (view != [NSView focusView]) {
- [view addTkDirtyRect:[view bounds]];
+ TkMacOSXInvalClipRgns((Tk_Window)winPtr->parentPtr);
}
return Success;
}
@@ -408,7 +414,6 @@ XResizeWindow(
[(TKWindow *)w tkLayoutChanged];
} else {
NSRect r = [w contentRectForFrameRect:[w frame]];
-
r.origin.y += r.size.height - height;
r.size.width = width;
r.size.height = height;
@@ -739,15 +744,10 @@ XConfigureWindow(
NSView *view = TkMacOSXGetNSViewForDrawable(macWin);
if (view) {
- TkMacOSXInvalClipRgns((Tk_Window)winPtr->parentPtr);
- TkpRedrawWidget((Tk_Window)winPtr);
+ TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
}
}
-#if 0
- TkGenWMMoveRequestEvent(macWin->winPtr,
- macWin->winPtr->changes.x, macWin->winPtr->changes.y);
-#endif
return Success;
}
@@ -964,6 +964,7 @@ TkMacOSXUpdateClipRgn(
}
}
+// Unused and misspelled stub function
/*
*----------------------------------------------------------------------
*
@@ -992,6 +993,11 @@ TkMacOSXVisableClipRgn(
return (Region) HIShapeCreateMutableCopy(winPtr->privatePtr->visRgn);
}
+#if 0
+//This code is not currently used. But it shows how to iterate over the
+//rectangles in a region described by an HIShape. Probably we want to
+//replace the current dirtyRect by such a region.
+
/*
*----------------------------------------------------------------------
*
@@ -1029,9 +1035,13 @@ InvalViewRect(
break;
case kHIShapeEnumerateRect:
dirtyRect = NSRectFromCGRect(CGRectApplyAffineTransform(*rect, t));
- [view addTkDirtyRect:dirtyRect];
+ // Cannot rely on addTkDirtyRect: to force redrawing.
+ //MC This is the only place where the rect is not the view bounds.
+ //And it kills liveResize.
+ //[view generateExposeEvents:dirtyRect];
break;
}
+ [view generateExposeEvents:[view bounds]];
return noErr;
}
@@ -1046,22 +1056,34 @@ TkMacOSXInvalidateViewRegion(
InvalViewRect, view);
}
}
+#endif
/*
*----------------------------------------------------------------------
*
* TkMacOSXInvalidateWindow --
*
- * This function invalidates a window and (optionally) its children.
+ * This stub function redraws the part of the toplevel window
+ * covered by a given Tk window. (Except currently it redraws
+ * the entire toplevel.)
*
* Results:
* None.
*
* Side effects:
- * Damage is created.
+ * The window is redrawn.
*
*----------------------------------------------------------------------
*/
+void
+TkMacOSXRedrawViewIdleTask(
+ void *clientData)
+{
+ TKContentView *view = (TKContentView *) clientData;
+ // fprintf(stderr, "idle redraw for %p\n", view);
+ [view generateExposeEvents:[view bounds]];
+ [view setTkNeedsDisplay:YES];
+}
void
TkMacOSXInvalidateWindow(
@@ -1072,11 +1094,16 @@ TkMacOSXInvalidateWindow(
#ifdef TK_MAC_DEBUG_CLIP_REGIONS
TkMacOSXDbgMsg("%s", macWin->winPtr->pathName);
#endif
- if (macWin->flags & TK_CLIP_INVALID) {
- TkMacOSXUpdateClipRgn(macWin->winPtr);
+ TKContentView *view = (TKContentView *)TkMacOSXGetNSViewForDrawable(macWin);
+ TkWindow *winPtr = macWin->winPtr;
+ Tk_Window tkwin = (Tk_Window) winPtr;
+ Tk_Window parent = (Tk_Window) winPtr->parentPtr;
+ TkMacOSXInvalClipRgns(tkwin);
+ if ((flag == TK_PARENT_WINDOW) && parent){
+ TkMacOSXInvalClipRgns(parent);
}
- TkMacOSXInvalidateViewRegion(TkMacOSXGetNSViewForDrawable(macWin),
- (flag == TK_WINDOW_ONLY) ? macWin->visRgn : macWin->aboveVisRgn);
+ [view generateExposeEvents:[view bounds]];
+ [view setTkNeedsDisplay:YES];
}
/*
@@ -1105,17 +1132,19 @@ Tk_MacOSXGetNSWindowForDrawable(
if (!macWin || macWin->flags & TK_IS_PIXMAP) {
result = nil;
+
} else if (macWin->toplevel && macWin->toplevel->winPtr &&
macWin->toplevel->winPtr->wmInfoPtr &&
macWin->toplevel->winPtr->wmInfoPtr->window) {
result = macWin->toplevel->winPtr->wmInfoPtr->window;
+
} else if (macWin->winPtr && macWin->winPtr->wmInfoPtr &&
macWin->winPtr->wmInfoPtr->window) {
result = macWin->winPtr->wmInfoPtr->window;
+
} else if (macWin->toplevel && (macWin->toplevel->flags & TK_EMBEDDED)) {
TkWindow *contWinPtr = (TkWindow *)Tk_GetOtherWindow((Tk_Window)macWin->toplevel->winPtr);
-
- if (contWinPtr) {
+ if (contWinPtr && contWinPtr->privatePtr) {
result = TkMacOSXGetNSWindowForDrawable((Drawable)contWinPtr->privatePtr);
}
}
diff --git a/macosx/tkMacOSXSysTray.c b/macosx/tkMacOSXSysTray.c
index 76186cc..99ffc9b 100644
--- a/macosx/tkMacOSXSysTray.c
+++ b/macosx/tkMacOSXSysTray.c
@@ -205,7 +205,7 @@ MacSystrayObjCmd(
static const char *modifyOptions[] =
{"image", "text", "b1_callback", "b3_callback", NULL};
typedef enum {TRAY_IMAGE, TRAY_TEXT, TRAY_B1_CALLBACK, TRAY_B3_CALLBACK
- } modifyOptionsEnum;
+ } modifyOptionsEnum;
if ([NSApp macOSVersion] < 101000) {
Tcl_AppendResult(interp,
@@ -329,9 +329,9 @@ MacSystrayObjCmd(
break;
}
- /*
- * Modify the text for the tooltip.
- */
+ /*
+ * Modify the text for the tooltip.
+ */
case TRAY_TEXT: {
NSString *tooltip = [NSString stringWithUTF8String:Tcl_GetString(objv[3])];
@@ -345,9 +345,9 @@ MacSystrayObjCmd(
break;
}
- /*
- * Modify the proc for the callback.
- */
+ /*
+ * Modify the proc for the callback.
+ */
case TRAY_B1_CALLBACK: {
[statusItem setB1Callback : objv[3]];
@@ -365,14 +365,14 @@ MacSystrayObjCmd(
/*
* Set all properties to nil, and release statusItem.
*/
- [statusItem setImagewithImage: nil];
- [statusItem setTextwithString: nil];
- [statusItem setB1Callback : NULL];
- [statusItem setB3Callback : NULL];
- [statusItem release];
- *info = NULL;
- statusItem = NULL;
- break;
+ [statusItem setImagewithImage: nil];
+ [statusItem setTextwithString: nil];
+ [statusItem setB1Callback : NULL];
+ [statusItem setB3Callback : NULL];
+ [statusItem release];
+ *info = NULL;
+ statusItem = NULL;
+ break;
}
}
diff --git a/macosx/tkMacOSXTest.c b/macosx/tkMacOSXTest.c
index 0e0b06b..b36c283 100644
--- a/macosx/tkMacOSXTest.c
+++ b/macosx/tkMacOSXTest.c
@@ -140,6 +140,8 @@ MenuBarHeightObjCmd(
* Returns true if and only if the NSView of the drawable is the
* current focusView, which on 10.14 and newer systems can only be the
* case when within [NSView drawRect].
+ * NOTE: This is no longer needed when we use updateLayer instead
+ * of drawRect. Now it always returns True.
*
* Side effects:
* None
@@ -151,21 +153,8 @@ MODULE_SCOPE Bool
TkTestLogDisplay(
Drawable drawable)
{
- MacDrawable *macWin = (MacDrawable *)drawable;
- NSWindow *win = nil;
- if (macWin->toplevel && macWin->toplevel->winPtr &&
- macWin->toplevel->winPtr->wmInfoPtr &&
- macWin->toplevel->winPtr->wmInfoPtr->window) {
- win = macWin->toplevel->winPtr->wmInfoPtr->window;
- } else if (macWin->winPtr && macWin->winPtr->wmInfoPtr &&
- macWin->winPtr->wmInfoPtr->window) {
- win = macWin->winPtr->wmInfoPtr->window;
- }
- if (win) {
- return ([win contentView] == [NSView focusView]);
- } else {
- return True;
- }
+ (void) drawable;
+ return True;
}
/*
@@ -209,8 +198,8 @@ PressButtonObjCmd(
}
if (objc != 3) {
- Tcl_WrongNumArgs(interp, 1, objv, "x y");
- return TCL_ERROR;
+ Tcl_WrongNumArgs(interp, 1, objv, "x y");
+ return TCL_ERROR;
}
for (i = 1; i < objc; i++) {
if (Tcl_GetIntFromObj(interp,objv[i],&value) != TCL_OK) {
@@ -308,8 +297,8 @@ MoveMouseObjCmd(
}
if (objc != 3) {
- Tcl_WrongNumArgs(interp, 1, objv, "x y");
- return TCL_ERROR;
+ Tcl_WrongNumArgs(interp, 1, objv, "x y");
+ return TCL_ERROR;
}
for (i = 1; i < objc; i++) {
if (Tcl_GetIntFromObj(interp,objv[i],&value) != TCL_OK) {
@@ -370,12 +359,12 @@ InjectKeyEventObjCmd(
if (objc < 3) {
wrongArgs:
- Tcl_WrongNumArgs(interp, 1, objv, "option keysym ?arg?");
- return TCL_ERROR;
+ Tcl_WrongNumArgs(interp, 1, objv, "option keysym ?arg?");
+ return TCL_ERROR;
}
if (Tcl_GetIndexFromObjStruct(interp, objv[1], optionStrings,
- sizeof(char *), "option", 0, &index) != TCL_OK) {
- return TCL_ERROR;
+ sizeof(char *), "option", 0, &index) != TCL_OK) {
+ return TCL_ERROR;
}
type = types[index];
if (Tcl_GetIntFromObj(interp, objv[2], &keysym) != TCL_OK) {
@@ -387,37 +376,37 @@ InjectKeyEventObjCmd(
macKC.uint = XKeysymToKeycode(NULL, keysym);
for (i = 3; i < objc; i++) {
if (Tcl_GetIndexFromObjStruct(interp, objv[i], argStrings,
- sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
- return TCL_ERROR;
- }
- switch ((enum args) index) {
+ sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ switch ((enum args) index) {
case KEYEVENT_SHIFT:
mods |= NSShiftKeyMask;
- break;
+ break;
case KEYEVENT_CONTROL:
mods |= NSControlKeyMask;
- break;
+ break;
case KEYEVENT_OPTION:
mods |= NSAlternateKeyMask;
- break;
+ break;
case KEYEVENT_COMMAND:
mods |= NSCommandKeyMask;
- break;
+ break;
case KEYEVENT_FUNCTION:
mods |= NSFunctionKeyMask;
- break;
+ break;
case KEYEVENT_X:
if (++i >= objc) {
- goto wrongArgs;
- }
+ goto wrongArgs;
+ }
if (Tcl_GetIntFromObj(interp,objv[i], &x) != TCL_OK) {
return TCL_ERROR;
}
break;
case KEYEVENT_Y:
if (++i >= objc) {
- goto wrongArgs;
- }
+ goto wrongArgs;
+ }
if (Tcl_GetIntFromObj(interp,objv[i], &y) != TCL_OK) {
return TCL_ERROR;
}
@@ -445,7 +434,7 @@ InjectKeyEventObjCmd(
}
keyEvent = [NSEvent keyEventWithType:type
location:NSMakePoint(x, y)
- modifierFlags:mods
+ modifierFlags:mods
timestamp:GetCurrentEventTime()
windowNumber:0
context:nil
diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c
index e261bee..2915af1 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -150,7 +150,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
}
- (NSRect)windowWillUseStandardFrame:(NSWindow *)window
- defaultFrame:(NSRect)newFrame
+ defaultFrame:(NSRect)newFrame
{
(void)window;
@@ -244,7 +244,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
[view viewDidChangeEffectiveAppearance];
}
#endif
- [view addTkDirtyRect:[view bounds]];
+ [view setTkNeedsDisplay:YES];
Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL);
Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL);
}
@@ -256,7 +256,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
if (winPtr) {
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
+ while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
}
}
@@ -284,9 +284,11 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
NSWindow *w = [notification object];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
+#if 0
if (winPtr) {
- //Tk_UnmapWindow((Tk_Window)winPtr);
+ Tk_UnmapWindow((Tk_Window)winPtr);
}
+#endif
}
#endif /* TK_MAC_DEBUG_NOTIFICATIONS */
@@ -396,7 +398,7 @@ static void RefocusGrabWindow(void *data) {
}
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender
- hasVisibleWindows:(BOOL)flag
+ hasVisibleWindows:(BOOL)flag
{
(void)sender;
(void)flag;
@@ -473,31 +475,11 @@ static void RefocusGrabWindow(void *data) {
*
*----------------------------------------------------------------------
*/
-
+//XXXXX This stub is not used with CGImage drawing.
int
TkpWillDrawWidget(Tk_Window tkwin) {
- int result;
- if (tkwin) {
- TkWindow *winPtr = (TkWindow *)tkwin;
- TKContentView *view = (TKContentView *)TkMacOSXGetNSViewForDrawable(
- (Drawable)winPtr->privatePtr);
- result = ([NSApp isDrawing] && view == [NSView focusView]);
-#if 0
- printf("TkpWillDrawWidget: %s %d %d \n", Tk_PathName(tkwin),
- [NSApp isDrawing], (view == [NSView focusView]));
- if (!result) {
- NSRect dirtyRect;
- TkMacOSXWinNSBounds(winPtr, view, &dirtyRect);
- printf("TkpAppCanDraw: dirtyRect for %s is %s\n",
- Tk_PathName(tkwin),
- NSStringFromRect(dirtyRect).UTF8String);
- [view addTkDirtyRect:dirtyRect];
- }
-#endif
- } else {
- result = [NSApp isDrawing];
- }
- return result;
+ (void) tkwin;
+ return false;
}
/*
@@ -527,11 +509,14 @@ GenerateUpdates(
TkWindow *childPtr;
XEvent event;
CGRect bounds, damageBounds;
+ NSView *view = TkMacOSXGetNSViewForDrawable((Drawable)winPtr->privatePtr);
TkMacOSXWinCGBounds(winPtr, &bounds);
+#if 0
if (!CGRectIntersectsRect(bounds, *updateBounds)) {
return 0;
}
+#endif
/*
* Compute the bounding box of the area that the damage occurred in.
@@ -548,7 +533,11 @@ GenerateUpdates(
event.xexpose.width = damageBounds.size.width;
event.xexpose.height = damageBounds.size.height;
event.xexpose.count = 0;
- Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
+ if ([view inLiveResize]) {
+ Tk_HandleEvent(&event);
+ } else {
+ Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
+ }
#ifdef TK_MAC_DEBUG_DRAWING
TKLog(@"Exposed %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x,
@@ -970,22 +959,10 @@ ConfigureRestrictProc(
{
self = [super initWithFrame:frame];
if (self) {
- /*
- * The layer must exist before we set wantsLayer to YES.
- */
-
- self.layer = [CALayer layer];
self.wantsLayer = YES;
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
self.layer.contentsGravity = self.layer.contentsAreFlipped ?
kCAGravityTopLeft : kCAGravityBottomLeft;
-
- /*
- * Nothing gets drawn at all if the layer does not have a delegate.
- * Currently, we do not implement any methods of the delegate, however.
- */
-
- self.layer.delegate = (id) self;
trackingArea = [[NSTrackingArea alloc]
initWithRect:[self bounds]
options:(NSTrackingMouseEnteredAndExited |
@@ -995,18 +972,38 @@ ConfigureRestrictProc(
NSTrackingActiveAlways)
owner:self
userInfo:nil];
- [self addTrackingArea:trackingArea];
+ [self addTrackingArea:trackingArea];
}
return self;
}
-/*
- * We will just use drawRect.
- */
-
- (BOOL) wantsUpdateLayer
{
- return NO;
+ return YES;
+}
+- (void) updateLayer {
+ CGContextRef context = self.tkLayerBitmapContext;
+ if (context) {
+ /*
+ * Create a CGImage by copying (probably using copy-on-write) the
+ * bitmap data of the CGBitmapContext that we have been using for
+ * drawing. Then render that CGImage into the CALayer of this view by
+ * assigning a reference to the CGImage to the contents property of the
+ * layer. This will cause all drawing done since the last call to this
+ * function to become visible.
+ */
+
+ CGImageRef newImg = CGBitmapContextCreateImage(context);
+ self.layer.contents = (__bridge id) newImg;
+ CGImageRelease(newImg); // will quickly leak memory if this is missing
+
+ /*
+ * Run any pending widget display procs as part of the update.
+ */
+
+ while(Tcl_DoOneEvent(TCL_IDLE_EVENTS)){}
+ [self setTkNeedsDisplay:NO];
+ }
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
@@ -1021,6 +1018,9 @@ ConfigureRestrictProc(
*/
self.layer.contentsScale = self.window.screen.backingScaleFactor;
+ [self resetTkLayerBitmapContext];
+ // need to redraw
+ [self generateExposeEvents: self.bounds];
}
#endif
@@ -1028,84 +1028,39 @@ ConfigureRestrictProc(
{
_tkNeedsDisplay = YES;
_tkDirtyRect = NSUnionRect(_tkDirtyRect, rect);
- [NSApp setNeedsToDraw:YES];
- [self setNeedsDisplay:YES];
- [[self layer] setNeedsDisplay];
}
- (void) clearTkDirtyRect
{
_tkNeedsDisplay = NO;
_tkDirtyRect = NSZeroRect;
- [NSApp setNeedsToDraw:NO];
-}
-
-- (void) drawRect: (NSRect) rect
-{
- (void)rect;
-
-#ifdef TK_MAC_DEBUG_DRAWING
- TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
- if (winPtr) {
- fprintf(stderr, "drawRect: drawing %s in %s\n",
- Tk_PathName(winPtr), NSStringFromRect(rect).UTF8String);
- }
-#endif
-
- /*
- * We do not allow recursive calls to drawRect, but we only log them on OSX
- * > 10.13, where they should never happen.
- */
-
- if ([NSApp isDrawing]) {
- if ([NSApp macOSVersion] > 101300) {
- TKLog(@"WARNING: a recursive call to drawRect was aborted.");
- }
- return;
- }
-
- [NSApp setIsDrawing: YES];
- [self clearTkDirtyRect];
- [self generateExposeEvents:rect];
- [NSApp setIsDrawing:NO];
-
-#ifdef TK_MAC_DEBUG_DRAWING
- fprintf(stderr, "drawRect: done.\n");
-#endif
}
-(void) setFrameSize: (NSSize)newsize
{
+ NSSize oldsize = self.bounds.size;
[super setFrameSize: newsize];
+ if ((newsize.width == 1 && newsize.height == 1) ||
+ (oldsize.width == 0 && oldsize.height == 0)) {
+ return;
+ }
NSWindow *w = [self window];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
Tk_Window tkwin = (Tk_Window)winPtr;
- if (![self inLiveResize] &&
- [w respondsToSelector: @selector (tkLayoutChanged)]) {
- [(TKWindow *)w tkLayoutChanged];
- }
-
if (winPtr) {
- unsigned int width = (unsigned int)newsize.width;
- unsigned int height=(unsigned int)newsize.height;
+ unsigned int width = (unsigned int) newsize.width;
+ unsigned int height= (unsigned int) newsize.height;
void *oldArg;
Tk_RestrictProc *oldProc;
/*
- * This can be called from outside the Tk event loop. Since it calls
- * Tcl_DoOneEvent, we need to make sure we don't clobber the
- * AutoreleasePool set up by the caller.
+ * This function can be re-entered, so we need to make sure we don't
+ * clobber any AutoreleasePool set up by the caller.
*/
[NSApp _lockAutoreleasePool];
- /*
- * Disable Tk drawing until the window has been completely configured.
- */
-
- TkMacOSXSetDrawingEnabled(winPtr, 0);
-
/*
* Generate and handle a ConfigureNotify event for the new size.
*/
@@ -1113,24 +1068,31 @@ ConfigureRestrictProc(
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 (Tcl_DoOneEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT)) {}
Tk_RestrictEvents(oldProc, oldArg, &oldArg);
+
/*
- * Now that Tk has configured all subwindows, create the clip regions.
+ * Update Tk's window data for the new size.
*/
- TkMacOSXSetDrawingEnabled(winPtr, 1);
- TkMacOSXInvalClipRgns(tkwin);
- TkMacOSXUpdateClipRgn(winPtr);
+ if ([w respondsToSelector: @selector (tkLayoutChanged)]) {
+ [(TKWindow *)w tkLayoutChanged];
+ }
- /*
- * Generate and process expose events to redraw the window. To avoid
- * crashes, only do this if we are being called from drawRect. See
- * ticket [1fa8c3ed8d].
- */
+ /*
+ * Reset the cgimage layer and redraw the entire content view.
+ */
+
+ [self viewDidChangeBackingProperties];
+
+ /*
+ * In live resize we seem to need to draw a second time to
+ * avoid artifacts.
+ */
- if([NSApp isDrawing] || [self inLiveResize]) {
- [self generateExposeEvents: [self bounds]];
+ if ([self inLiveResize]) {
+ [self generateExposeEvents:self.bounds];
}
/*
@@ -1138,7 +1100,14 @@ ConfigureRestrictProc(
*/
[NSApp _unlockAutoreleasePool];
+
}
+
+ /*
+ * Request a call to updateLayer.
+ */
+
+ [self setNeedsDisplay:YES];
}
/*
@@ -1150,53 +1119,62 @@ ConfigureRestrictProc(
- (void) generateExposeEvents: (NSRect) rect
{
- unsigned long serial;
- int updatesNeeded;
CGRect updateBounds;
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
void *oldArg;
Tk_RestrictProc *oldProc;
- if (!winPtr) {
+ static int reentered = 0;
+
+ if (!winPtr ||
+ (winPtr->flags & (TK_ALREADY_DEAD)) ||
+ !Tk_IsMapped(winPtr)) {
return;
}
+ if (reentered) {
+ /*
+ * When in liveResize an event loop gets run below to
+ * immediately process displayProcs while the resize is being
+ * done. Those can cause calls to this function, leading to
+ * crashes or very poor performance. The reentered flag is
+ * used to detect this.
+ */
+ //fprintf(stderr, "Recursive call to generateExposeEvents\n");
+ return;
+ }
+ reentered = 1;
+
/*
* Generate Tk Expose events. All of these events will share the same
* serial number.
*/
-
- updateBounds = NSRectToCGRect(rect);
+ if ([self inLiveResize]) {
+ updateBounds = [self bounds];
+ } else {
+ updateBounds = NSRectToCGRect(rect);
+ }
updateBounds.origin.y = ([self bounds].size.height - updateBounds.origin.y
- updateBounds.size.height);
- updatesNeeded = GenerateUpdates(&updateBounds, winPtr);
- if (updatesNeeded) {
-
- serial = LastKnownRequestProcessed(Tk_Display(winPtr));
-
+ if ( GenerateUpdates(&updateBounds, winPtr)) {
/*
- * Use the ExposeRestrictProc to process only the expose events. This
- * will create idle drawing tasks, which we handle before we return.
+ * Use the ExposeRestrictProc to process the expose events we just
+ * generated. This will create idle drawing tasks, which we handle
+ * before we return in the case of a live resize.
*/
-
- oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg);
- while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT)) {};
- Tk_RestrictEvents(oldProc, oldArg, &oldArg);
+ unsigned int serial = LastKnownRequestProcessed(Tk_Display(winPtr));
+ oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg);
+ while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT)) {};
+ Tk_RestrictEvents(oldProc, NULL, &oldArg);
/*
- * Starting with OSX 10.14, which uses Core Animation to draw windows,
- * all drawing must be done within the drawRect method. (The CGContext
- * which draws to the backing CALayer is created by the NSView before
- * calling drawRect, and destroyed when drawRect returns. Drawing done
- * with the current CGContext outside of the drawRect method has no
- * effect.)
- *
- * Fortunately, Tk schedules all drawing to be done while Tcl is idle.
- * So to run any display procs which were scheduled by the expose
- * events we process all idle events before returning.
+ * During a LiveResize we process all idle tasks generated by the
+ * expose events to redraw the window while it is being resized.
*/
-
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
+ if ([self inLiveResize]) {
+ while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
+ }
}
+ reentered = 0;
}
/*
@@ -1242,7 +1220,7 @@ static const char *const accentNames[] = {
}
NSString *accent = [preferences stringForKey:@"AppleAccentColor"];
NSArray *words = [[preferences stringForKey:@"AppleHighlightColor"]
- componentsSeparatedByString: @" "];
+ componentsSeparatedByString: @" "];
NSString *highlight = [words count] > 3 ? [words objectAtIndex:3] : nil;
const char *accentName = accent ? accentNames[1 + accent.intValue] : defaultColor;
const char *highlightName = highlight ? highlight.UTF8String: defaultColor;
@@ -1251,6 +1229,7 @@ static const char *const accentNames[] = {
effectiveAppearanceName.UTF8String, accentName,
highlightName);
Tk_SendVirtualEvent(tkwin, "AppearanceChanged", Tcl_NewStringObj(data, TCL_INDEX_NONE));
+ [self generateExposeEvents:self.bounds];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
@@ -1352,6 +1331,32 @@ static const char *const accentNames[] = {
return [super validRequestorForSendType:sendType returnType:returnType];
}
+-(void) resetTkLayerBitmapContext {
+ static CGColorSpaceRef colorspace = NULL;
+ if (colorspace == NULL) {
+ colorspace = CGColorSpaceCreateDeviceRGB();
+ CGColorSpaceRetain(colorspace);
+ }
+ CGContextRef newCtx = CGBitmapContextCreate(
+ NULL, self.layer.contentsScale * self.frame.size.width,
+ self.layer.contentsScale * self.frame.size.height, 8, 0, colorspace,
+ kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipLast // will also need to specify this when capturing
+ );
+ CGContextScaleCTM(newCtx, self.layer.contentsScale, self.layer.contentsScale);
+#if 0
+ fprintf(stderr, "rTkLBC %.1f %s %p %p %ld\n", (float)self.layer.contentsScale,
+ NSStringFromSize(self.frame.size).UTF8String, colorspace, newCtx,
+ self.tkLayerBitmapContext ?
+ (long)CFGetRetainCount(self.tkLayerBitmapContext) : INT_MIN);
+ fprintf(stderr, "rTkLBC %p %ld\n", self.tkLayerBitmapContext,
+ (long)(self.tkLayerBitmapContext ?
+ CFGetRetainCount(self.tkLayerBitmapContext) : LONG_MIN));
+#endif
+ // The context is also released in TkWmDeadWindow.
+ CGContextRelease(self.tkLayerBitmapContext);
+ self.tkLayerBitmapContext = newCtx;
+}
+
@end
/*
diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c
index 403025d..fbea56b 100644
--- a/macosx/tkMacOSXWm.c
+++ b/macosx/tkMacOSXWm.c
@@ -112,7 +112,7 @@ static const struct {
.forceOnAttrs = kWindowNoTitleBarAttribute |
kWindowDoesNotCycleAttribute,
.flags = WM_TOPMOST,
- .styleMask = 0},
+ .styleMask = 0},
[kSheetWindowClass] = {
.validAttrs = kWindowResizableAttribute,
.forceOnAttrs = kWindowNoTitleBarAttribute |
@@ -291,6 +291,7 @@ static void syncLayout(NSWindow *macWindow)
contentRect.size.width;
wmPtr->parentHeight = winPtr->changes.height + frameRect.size.height -
contentRect.size.height;
+ TkMacOSXInvalClipRgns((Tk_Window)winPtr);
}
}
#endif
@@ -587,6 +588,8 @@ static void placeAsTab(TKWindow *macWindow) {
- (void) tkLayoutChanged
{
syncLayout(self);
+ [[self contentView] setNeedsDisplay:YES];
+ Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL);
}
@end
@@ -606,6 +609,8 @@ static void placeAsTab(TKWindow *macWindow) {
- (void) tkLayoutChanged
{
syncLayout(self);
+ [[self contentView] setNeedsDisplay:YES];
+ Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL);
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
@@ -621,7 +626,7 @@ static void placeAsTab(TKWindow *macWindow) {
#endif
- (NSSize)windowWillResize:(NSWindow *)sender
- toSize:(NSSize)frameSize
+ toSize:(NSSize)frameSize
{
NSRect currentFrame = [sender frame];
TkWindow *winPtr = TkMacOSXGetTkWindow(sender);
@@ -818,30 +823,29 @@ FrontWindowAtPoint(
int y)
{
NSPoint p = NSMakePoint(x, TkMacOSXZeroScreenHeight() - y);
- NSArray *windows = [NSApp orderedWindows];
- TkWindow *winPtr = NULL;
- for (NSWindow *w in windows) {
- winPtr = TkMacOSXGetTkWindow(w);
+ for (NSWindow *w in [NSApp orderedWindows]) {
+ TkWindow *winPtr = TkMacOSXGetTkWindow(w);
if (winPtr) {
- WmInfo *wmPtr = winPtr->wmInfoPtr;
NSRect windowFrame = [w frame];
- NSRect contentFrame = [w frame];
+ NSRect contentFrame = windowFrame;
- contentFrame.size.height = [[w contentView] frame].size.height;
/*
* For consistency with other platforms, points in the
* title bar are not considered to be contained in the
* window.
*/
- if ((wmPtr->hints.initial_state == NormalState ||
- wmPtr->hints.initial_state == ZoomState)) {
- if (NSMouseInRect(p, contentFrame, NO)) {
- return winPtr;
- } else if (NSMouseInRect(p, windowFrame, NO)) {
- return NULL;
- }
+ contentFrame.size.height = [[w contentView] frame].size.height;
+ if (NSMouseInRect(p, contentFrame, NO)) {
+ return winPtr;
+ } else if (NSMouseInRect(p, windowFrame, NO)) {
+ /*
+ * The pointer is in the title bar of the highest NSWindow
+ * containing it, and therefore it should not be considered
+ * to be contained in any Tk window.
+ */
+ return NULL;
}
}
}
@@ -1100,12 +1104,15 @@ TkWmUnmapWindow(
*
* This procedure is invoked when a top-level window is about to be
* deleted. It cleans up the wm-related data structures for the window.
+ * If the dead window contains the pointer, TkUpdatePointer is called
+ * to tell Tk which window will be the new pointer window.
*
* Results:
* None.
*
* Side effects:
- * The WmInfo structure for winPtr gets freed up.
+ * The WmInfo structure for winPtr gets freed. Tk's cached pointer
+ * window may change.
*
*----------------------------------------------------------------------
*/
@@ -1114,13 +1121,15 @@ void
TkWmDeadWindow(
TkWindow *winPtr) /* Top-level window that's being deleted. */
{
+ TkWindow *winPtr2;
+ NSWindow *w;
WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2;
- TKWindow *deadNSWindow;
-
- if (wmPtr == NULL) {
- return;
+ TKWindow *deadNSWindow = NULL;
+ if (Tk_WindowId(winPtr) == None) {
+ fprintf(stderr, "TkWmDeadWindow: no window id\n");
+ } else {
+ deadNSWindow = (TKWindow *)TkMacOSXGetNSWindowForDrawable(Tk_WindowId(winPtr));
}
-
/*
*If the dead window is a transient, remove it from the container's list.
*/
@@ -1172,11 +1181,10 @@ TkWmDeadWindow(
for (Transient *transientPtr = wmPtr->transientPtr;
transientPtr != NULL; transientPtr = transientPtr->nextPtr) {
- TkWindow *winPtr2 = transientPtr->winPtr;
- TkWindow *containerPtr = (TkWindow *)TkMacOSXGetContainer(winPtr2);
-
+ TkWindow *containerPtr = (TkWindow *)TkMacOSXGetContainer(
+ transientPtr->winPtr);
if (containerPtr == winPtr) {
- wmPtr2 = winPtr2->wmInfoPtr;
+ wmPtr2 = transientPtr->winPtr->wmInfoPtr;
wmPtr2->container = NULL;
}
}
@@ -1188,29 +1196,48 @@ TkWmDeadWindow(
ckfree(transientPtr);
}
- deadNSWindow = (TKWindow *)wmPtr->window;
-
/*
* Remove references to the Tk window from the mouse event processing
- * state which is recorded in the NSApplication object.
+ * state which is recorded in the NSApplication object and notify Tk
+ * of the new pointer window.
*/
- if (winPtr == [NSApp tkPointerWindow]) {
- NSWindow *w;
- NSPoint mouse = [NSEvent mouseLocation];
- [NSApp setTkPointerWindow:nil];
- for (w in [NSApp orderedWindows]) {
- if (w == deadNSWindow) {
- continue;
- }
- if (NSPointInRect(mouse, [w frame])) {
- TkWindow *winPtr2 = TkMacOSXGetTkWindow(w);
- int x = mouse.x, y = TkMacOSXZeroScreenHeight() - mouse.y;
- [NSApp setTkPointerWindow:winPtr2];
- Tk_UpdatePointer((Tk_Window) winPtr2, x, y,
- [NSApp tkButtonState]);
- break;
- }
+ NSPoint mouse = [NSEvent mouseLocation];
+ [NSApp setTkPointerWindow:nil];
+ winPtr2 = NULL;
+
+ for (w in [NSApp orderedWindows]) {
+ if (w == deadNSWindow || w == NULL) {
+ continue;
+ }
+ winPtr2 = TkMacOSXGetTkWindow(w);
+ if (winPtr2 == NULL) {
+ continue;
+ }
+ if (NSPointInRect(mouse, [w frame])) {
+ [NSApp setTkPointerWindow: winPtr2];
+ break;
+ }
+ }
+ if (winPtr2) {
+ /*
+ * We now know which toplevel will contain the pointer when the window
+ * is destroyed. We need to know which Tk window within the
+ * toplevel will contain the pointer.
+ */
+ NSPoint local = [w tkConvertPointFromScreen: mouse];
+ int top_x = floor(local.x),
+ top_y = floor(w.frame.size.height - local.y);
+ int root_x = floor(mouse.x),
+ root_y = floor(TkMacOSXZeroScreenHeight() - mouse.y);
+ int win_x, win_y;
+ Tk_Window target = Tk_TopCoordsToWindow((Tk_Window) winPtr2, top_x, top_y, &win_x, &win_y);
+ /*
+ * A non-toplevel window can have a NULL parent while it is in the process of
+ * being destroyed. We should not call Tk_UpdatePointer in that case.
+ */
+ if (Tk_Parent(target) != NULL || Tk_IsTopLevel(target)) {
+ Tk_UpdatePointer(target, root_x, root_y, [NSApp tkButtonState]);
}
}
@@ -1223,9 +1250,9 @@ TkWmDeadWindow(
if (deadNSWindow && !Tk_IsEmbedded(winPtr)) {
NSWindow *parent = [deadNSWindow parentWindow];
[deadNSWindow setTkWindow:None];
- if (winPtr->window) {
- ((MacDrawable *)winPtr->window)->view = nil;
- }
+ if (winPtr->window) {
+ ((MacDrawable *)winPtr->window)->view = nil;
+ }
wmPtr->window = NULL;
if (parent) {
@@ -1262,9 +1289,10 @@ TkWmDeadWindow(
* set tkEventTarget to NULL when there is no window to send Tk events to.
*/
TkWindow *newTkEventTarget = NULL;
+ winPtr2 = NULL;
- for (NSWindow *w in [NSApp orderedWindows]) {
- TkWindow *winPtr2 = TkMacOSXGetTkWindow(w);
+ for (w in [NSApp orderedWindows]) {
+ winPtr2 = TkMacOSXGetTkWindow(w);
BOOL isOnScreen;
if (!winPtr2 || !winPtr2->wmInfoPtr) {
@@ -1290,6 +1318,14 @@ TkWmDeadWindow(
[NSApp _setKeyWindow:nil];
[NSApp _setMainWindow:nil];
}
+
+ /*
+ * Avoid redrawing the view after it is released.
+ */
+
+ TKContentView *deadView = [deadNSWindow contentView];
+ Tcl_CancelIdleCall(TkMacOSXRedrawViewIdleTask,(void *) deadView);
+ CGContextRelease(deadView.tkLayerBitmapContext);
[deadNSWindow close];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
@@ -1749,7 +1785,7 @@ WmSetAttribute(
} else if (![macWindow isKindOfClass: [NSPanel class]] &&
styleMaskBits[index].allowed == NSWindowClass_panel) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "styleMask bit \"%s\" can only be used with an NSPanel",
+ "styleMask bit \"%s\" can only be used with an NSPanel",
styleMaskBits[index].bitname));
Tcl_SetErrorCode(interp, "TK", "INVALID_STYLEMASK_BIT", NULL);
return TCL_ERROR;
@@ -1794,15 +1830,15 @@ WmSetAttribute(
fprintf(stderr, "Current styleMask: %lx\n", [macWindow styleMask]);
fprintf(stderr, "Setting styleMask to %lx\n", styleMaskValue);
#endif
- macWindow.styleMask = (unsigned long) styleMaskValue;
+ macWindow.styleMask = (unsigned long) styleMaskValue;
NSRect newFrame = [macWindow frame];
int heightDiff = newFrame.size.height - oldFrame.size.height;
int newHeight = heightDiff < 0 ? newFrame.size.height :
newFrame.size.height - heightDiff;
[(TKWindow *)macWindow tkLayoutChanged];
if (heightDiff) {
- //Calling XMoveResizeWindow twice is a hack to force a relayout
- //of the window.
+ // Calling XMoveResizeWindow twice is a hack to force a relayout
+ // of the window.
XMoveResizeWindow(winPtr->display, winPtr->window,
winPtr->changes.x, winPtr->changes.y,
newFrame.size.width, newHeight - 1);
@@ -2390,8 +2426,7 @@ WmDeiconifyCmd(
Tcl_Obj *const objv[]) /* Argument objects. */
{
WmInfo *wmPtr = winPtr->wmInfoPtr;
- NSWindow *win = TkMacOSXGetNSWindowForDrawable(winPtr->window);
-
+ NSWindow *win = nil;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "window");
return TCL_ERROR;
@@ -2410,11 +2445,17 @@ WmDeiconifyCmd(
return TCL_ERROR;
}
+ if (winPtr->window) {
+ win = TkMacOSXGetNSWindowForDrawable(winPtr->window);
+ }
TkpWmSetState(winPtr, TkMacOSXIsWindowZoomed(winPtr) ?
ZoomState : NormalState);
- [win setExcludedFromWindowsMenu:NO];
- TkMacOSXApplyWindowAttributes(winPtr, win);
- [win orderFront:NSApp];
+ if (win) {
+ [win setExcludedFromWindowsMenu:NO];
+ TkMacOSXApplyWindowAttributes(winPtr, win);
+ [win orderFront:NSApp];
+ [[win contentView] setTkNeedsDisplay:YES];
+ }
if (wmPtr->icon) {
Tk_UnmapWindow((Tk_Window)wmPtr->icon);
}
@@ -2439,7 +2480,6 @@ WmDeiconifyCmd(
}
}
- [[win contentView] setNeedsDisplay:YES];
Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL);
return TCL_OK;
}
@@ -2541,19 +2581,18 @@ WmForgetCmd(
macWin->toplevel->referenceCount++;
macWin->flags &= ~TK_HOST_EXISTS;
- TkWmDeadWindow(winPtr);
RemapWindows(winPtr, (MacDrawable *)winPtr->parentPtr->window);
- /*
- * Make sure wm no longer manages this window
- */
- Tk_ManageGeometry(frameWin, NULL, NULL);
+ /*
+ * Make sure wm no longer manages this window
+ */
+ Tk_ManageGeometry(frameWin, NULL, NULL);
winPtr->flags &= ~(TK_TOP_HIERARCHY|TK_TOP_LEVEL|TK_HAS_WRAPPER|TK_WIN_MANAGED);
/*
- * Flags (above) must be cleared before calling TkMapTopFrame (below).
- */
+ * Flags (above) must be cleared before calling TkMapTopFrame (below).
+ */
TkMapTopFrame(frameWin);
} else {
@@ -2632,11 +2671,13 @@ WmGeometryCmd(
Tcl_Obj *const objv[]) /* Argument objects. */
{
WmInfo *wmPtr = winPtr->wmInfoPtr;
- NSWindow *win = TkMacOSXGetNSWindowForDrawable(winPtr->window);
+ NSWindow *win = nil;
char xSign = '+', ySign = '+';
int width, height, x = wmPtr->x, y= wmPtr->y;
char *argv3;
-
+ if (winPtr && winPtr->window) {
+ win = TkMacOSXGetNSWindowForDrawable(winPtr->window);
+ }
if ((objc != 3) && (objc != 4)) {
Tcl_WrongNumArgs(interp, 2, objv, "window ?newGeometry?");
return TCL_ERROR;
@@ -3382,18 +3423,23 @@ WmIconwindowCmd(
return TCL_ERROR;
}
if (wmPtr->icon != NULL) {
+ NSWindow *win = nil;
TkWindow *oldIcon = (TkWindow *)wmPtr->icon;
- WmInfo *wmPtr3 = oldIcon->wmInfoPtr;
- NSWindow *win = TkMacOSXGetNSWindowForDrawable(oldIcon->window);
-
+ if (winPtr && winPtr->window) {
+ win = TkMacOSXGetNSWindowForDrawable(winPtr->window);
+ }
/*
* The old icon should be withdrawn.
*/
-
- TkpWmSetState(oldIcon, WithdrawnState);
+ if (oldIcon) {
+ WmInfo *wmPtr3 = oldIcon->wmInfoPtr;
+ TkpWmSetState(oldIcon, WithdrawnState);
+ if (wmPtr3) {
+ wmPtr3->iconFor = NULL;
+ }
+ }
[win orderOut:NSApp];
- [win setExcludedFromWindowsMenu:YES];
- wmPtr3->iconFor = NULL;
+ [win setExcludedFromWindowsMenu:YES];
}
Tk_MakeWindowExist(tkwin2);
wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
@@ -3488,6 +3534,7 @@ WmManageCmd(
} else if (Tk_IsTopLevel(frameWin)) {
/* Already managed by wm - ignore it */
}
+ Tk_ManageGeometry((Tk_Window)winPtr, &wmMgrType, NULL);
return TCL_OK;
}
@@ -3626,7 +3673,11 @@ WmOverrideredirectCmd(
{
Bool boolValue;
XSetWindowAttributes atts;
- TKWindow *win = (TKWindow *)TkMacOSXGetNSWindowForDrawable(winPtr->window);
+ NSWindow *win = nil;
+ if (winPtr && winPtr->window) {
+ win = TkMacOSXGetNSWindowForDrawable(winPtr->window);
+ }
+
if ((objc != 3) && (objc != 4)) {
Tcl_WrongNumArgs(interp, 2, objv, "window ?boolean?");
@@ -4311,12 +4362,12 @@ WmTransientCmd(
RemoveTransient(winPtr);
containerPtr = (TkWindow*) container;
while (!Tk_TopWinHierarchy(containerPtr)) {
- /*
- * Ensure that the container window is actually a Tk toplevel.
- */
+ /*
+ * Ensure that the container window is actually a Tk toplevel.
+ */
- containerPtr = containerPtr->parentPtr;
- }
+ containerPtr = containerPtr->parentPtr;
+ }
Tk_MakeWindowExist((Tk_Window)containerPtr);
if (wmPtr->iconFor != NULL) {
@@ -5216,7 +5267,7 @@ Tk_GetRootCoords(
*/
winPtr = otherPtr;
- continue;
+ continue;
}
winPtr = winPtr->parentPtr;
}
@@ -5619,6 +5670,15 @@ Tk_MoveToplevelWindow(
*
*----------------------------------------------------------------------
*/
+#define PRINT_STACK \
+ for (NSWindow *w in [NSApp orderedWindows]) { \
+ TkWindow *winPtr2 = TkMacOSXGetTkWindow(w); \
+ if (winPtr2) { \
+ fprintf(stderr, "%s ", Tk_PathName(winPtr2)); \
+ } \
+ } \
+ fprintf(stderr, "\n"); \
+ fflush(stderr)
void
TkWmRestackToplevel(
@@ -5676,8 +5736,14 @@ TkWmRestackToplevel(
* Just let the Mac window manager deal with all the subtleties of keeping
* track of off-screen windows, etc.
*/
-
+#if 0
+ fprintf(stderr, "window order: "); PRINT_STACK;
+#endif
[macWindow orderWindow:macAboveBelow relativeTo:otherNumber];
+#if 0
+ fprintf(stderr, "new window order: "); PRINT_STACK;
+#endif
+#undef PRINT_STACK
}
/*
@@ -6027,7 +6093,7 @@ Tk_Window
TkMacOSXGetContainer(
TkWindow *winPtr)
{
- if (winPtr->wmInfoPtr != NULL) {
+ if (Tk_PathName(winPtr)) {
return (Tk_Window)winPtr->wmInfoPtr->container;
}
return NULL;
@@ -6072,7 +6138,7 @@ TkMacOSXGetXWindow(
* void*.
*
* Results:
- * A Tk_Window, or NULL if the NSWindow is not associated with
+ * A Tk_Window, or None if the NSWindow is not associated with
* any Tk window.
*
* Side effects:
@@ -6088,13 +6154,12 @@ Tk_MacOSXGetTkWindow(
Window window = None;
if ([(NSWindow *)w respondsToSelector: @selector (tkWindow)]) {
window = [(TKWindow *)w tkWindow];
- }
- if (window) {
TkDisplay *dispPtr = TkGetDisplayList();
- return Tk_IdToWindow(dispPtr->display, window);
- } else {
- return NULL;
+ if (window && dispPtr && dispPtr->display) {
+ return Tk_IdToWindow(dispPtr->display, window);
+ }
}
+ return NULL;
}
/*
@@ -6119,7 +6184,10 @@ MODULE_SCOPE int
TkMacOSXIsWindowZoomed(
TkWindow *winPtr)
{
- NSWindow *macWindow = TkMacOSXGetNSWindowForDrawable(winPtr->window);
+ NSWindow *macWindow = nil;
+ if (winPtr && winPtr->window) {
+ macWindow = TkMacOSXGetNSWindowForDrawable(winPtr->window);
+ }
return [macWindow isZoomed];
}
@@ -6240,7 +6308,7 @@ TkUnsupported1ObjCmd(
case TKMWS_APPEARANCE:
if ([NSApp macOSVersion] < 100900) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "Window appearances did not exist until OSX 10.9.", TCL_INDEX_NONE));
+ "Window appearances did not exist until OSX 10.9.", TCL_INDEX_NONE));
Tcl_SetErrorCode(interp, "TK", "WINDOWSTYLE", "APPEARANCE", NULL);
return TCL_ERROR;
}
@@ -6794,7 +6862,7 @@ TkMacOSXMakeRealWindowExist(
}
if ((styleMask & (NSTexturedBackgroundWindowMask|NSHUDWindowMask)) &&
!(styleMask & NSDocModalWindowMask)) {
- /*
+ /*
* Workaround for [Bug 2824538]: Textured windows are draggable from
* opaque content.
*/
@@ -6832,9 +6900,11 @@ TkMacOSXMakeRealWindowExist(
*
* TkpRedrawWidget --
*
- * Mark the bounding rectangle of this widget as needing display so the
- * widget will be drawn by [NSView drawRect:]. If this is called within
- * the drawRect method, do nothing.
+ * This is a stub called only from tkTextDisp.c. It was introduced
+ * to deal with an issue in macOS 10.14 and is not needed
+ * even for that OS with updateLayer in use. It would add the widget bounds
+ * to the dirtyRect, which is not currently used, and set the
+ * TkNeedsDisplay flag. Now it is a no-op.
*
* Results:
* None.
@@ -6847,15 +6917,16 @@ TkMacOSXMakeRealWindowExist(
void
TkpRedrawWidget(Tk_Window tkwin) {
+ (void) tkwin;
+#if 0
TkWindow *winPtr = (TkWindow *)tkwin;
- NSWindow *w;
+ NSWindow *w = nil;
Rect tkBounds;
NSRect bounds;
- if ([NSApp isDrawing]) {
- return;
+ if (winPtr && winPtr->window) {
+ w = TkMacOSXGetNSWindowForDrawable(winPtr->window);
}
- w = TkMacOSXGetNSWindowForDrawable(winPtr->window);
if (w) {
TKContentView *view = [w contentView];
TkMacOSXWinBounds(winPtr, &tkBounds);
@@ -6864,7 +6935,9 @@ TkpRedrawWidget(Tk_Window tkwin) {
tkBounds.right - tkBounds.left,
tkBounds.bottom - tkBounds.top);
[view addTkDirtyRect:bounds];
+ [view setNeedsDisplay:YES];
}
+#endif
}
@@ -6987,14 +7060,15 @@ TkpWmSetState(
* or WithdrawnState. */
{
WmInfo *wmPtr = winPtr->wmInfoPtr;
- NSWindow *macWin;
+ NSWindow *macWin = nil;
wmPtr->hints.initial_state = state;
if (wmPtr->flags & WM_NEVER_MAPPED) {
goto setStateEnd;
}
-
- macWin = TkMacOSXGetNSWindowForDrawable(winPtr->window);
+ if (winPtr && winPtr->window) {
+ macWin = TkMacOSXGetNSWindowForDrawable(winPtr->window);
+ }
/*
* Make sure windows are updated before the state change. As an exception,
@@ -7181,7 +7255,10 @@ TkpChangeFocus(
* didn't originally belong to topLevelPtr's
* application. */
{
- if (winPtr->atts.override_redirect) {
+ if (!winPtr ||
+ (winPtr->flags & TK_ALREADY_DEAD) ||
+ !Tk_IsMapped(winPtr) ||
+ winPtr->atts.override_redirect) {
return 0;
}
@@ -7570,9 +7647,9 @@ ApplyContainerOverrideChanges(
wmPtr->attributes &= ~kWindowNoActivatesAttribute;
if ([NSApp macOSVersion] == 100600) {
styleMask = NSTitledWindowMask |
- NSClosableWindowMask |
- NSMiniaturizableWindowMask |
- NSResizableWindowMask;
+ NSClosableWindowMask |
+ NSMiniaturizableWindowMask |
+ NSResizableWindowMask;
} else {
styleMask |= NSTitledWindowMask;
}
diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c
index ff850f0..2d8d3da 100644
--- a/macosx/ttkMacOSXTheme.c
+++ b/macosx/ttkMacOSXTheme.c
@@ -214,9 +214,9 @@ static GrayPalette LookupGrayPalette(
{
const PaletteStateTable *entry = design->palettes;
while ((state & entry->onBits) != entry->onBits ||
- (~state & entry->offBits) != entry->offBits)
+ (~state & entry->offBits) != entry->offBits)
{
- ++entry;
+ ++entry;
}
return isDark ? entry->dark : entry->light;
}
@@ -356,12 +356,12 @@ static void GetBackgroundColorRGBA(
rgba[i] -= Ttk_ContrastDelta*contrast / 255.0;
}
}
- if (save && winPtr->privatePtr) {
- winPtr->privatePtr->flags |= TTK_HAS_CONTRASTING_BG;
- for (int i = 0; i < 4; i++) {
- winPtr->privatePtr->fillRGBA[i] = rgba[i];
- }
- }
+ if (save && winPtr->privatePtr) {
+ winPtr->privatePtr->flags |= TTK_HAS_CONTRASTING_BG;
+ for (int i = 0; i < 4; i++) {
+ winPtr->privatePtr->fillRGBA[i] = rgba[i];
+ }
+ }
}
}
@@ -931,8 +931,8 @@ DrawHelpSymbol(
NSColor *foreground = state & TTK_STATE_DISABLED ?
[NSColor disabledControlTextColor] : [NSColor controlTextColor];
NSDictionary *attrs = @{
- NSForegroundColorAttributeName : foreground,
- NSFontAttributeName : font
+ NSForegroundColorAttributeName : foreground,
+ NSFontAttributeName : font
};
NSAttributedString *attributedString = [[NSAttributedString alloc]
initWithString:@"?"
@@ -1505,10 +1505,10 @@ DrawTab(
if (!(state & TTK_STATE_SELECTED)) {
DrawGrayButton(context, bounds, &tabDesign, state, tkwin);
- /*
- * Draw a separator line on the left side of the tab if it
- * not first.
- */
+ /*
+ * Draw a separator line on the left side of the tab if it
+ * not first.
+ */
if (!(state & TTK_STATE_FIRST)) {
CGContextSaveGState(context);
@@ -1653,20 +1653,20 @@ static void ButtonElementMinSize(
if (params->heightMetric != NoThemeMetric) {
ChkErr(GetThemeMetric, params->heightMetric, minHeight);
- /*
- * The theme height does not include the 1-pixel border around
- * the button, although it does include the 1-pixel shadow at
- * the bottom.
- */
+ /*
+ * The theme height does not include the 1-pixel border around
+ * the button, although it does include the 1-pixel shadow at
+ * the bottom.
+ */
*minHeight += 2;
- /*
- * For buttons with labels the minwidth must be 0 to force the
- * correct text layout. For example, a non-zero value will cause the
- * text to be left justified, no matter what -anchor setting is used in
- * the style.
- */
+ /*
+ * For buttons with labels the minwidth must be 0 to force the
+ * correct text layout. For example, a non-zero value will cause the
+ * text to be left justified, no matter what -anchor setting is used in
+ * the style.
+ */
if (params->widthMetric != NoThemeMetric) {
ChkErr(GetThemeMetric, params->widthMetric, minWidth);
@@ -1700,10 +1700,10 @@ static void ButtonElementSize(
return;
case TkGradientButton:
*paddingPtr = Ttk_MakePadding(1, 1, 1, 1);
- /* Fall through. */
+ /* Fall through. */
case kThemeArrowButton:
case kThemeRoundButtonHelp:
- return;
+ return;
/* Buttons which are sized like PushButtons but unknown to HITheme. */
case TkRoundedRectButton:
case TkRecessedButton:
@@ -1711,7 +1711,7 @@ static void ButtonElementSize(
info.kind = kThemePushButton;
break;
default:
- break;
+ break;
}
/*
@@ -2152,14 +2152,14 @@ static void EntryElementDraw(
.isFocused = state & TTK_STATE_FOCUS,
};
- /*
- * Earlier versions of the Aqua theme ignored the -fieldbackground
- * option and used the -background as if it were -fieldbackground.
- * Here we are enabling -fieldbackground. For backwards
- * compatibility, if -fieldbackground is set to the default color and
- * -background is set to a different color then we use -background as
- * -fieldbackground.
- */
+ /*
+ * Earlier versions of the Aqua theme ignored the -fieldbackground
+ * option and used the -background as if it were -fieldbackground.
+ * Here we are enabling -fieldbackground. For backwards
+ * compatibility, if -fieldbackground is set to the default color and
+ * -background is set to a different color then we use -background as
+ * -fieldbackground.
+ */
if (0 != strcmp(Tcl_GetString(e->fieldbackgroundObj), defaultBG)) {
backgroundPtr =
@@ -2828,14 +2828,14 @@ static void ThumbElementDraw(
CGRect troughBounds = {{macWin->xOff, macWin->yOff},
{Tk_Width(tkwin), Tk_Height(tkwin)}};
- /*
- * The info struct has integer fields, which will be converted to
- * floats in the drawing routine. All of values provided in the info
- * struct, namely min, max, value, and viewSize are only defined up to
- * an arbitrary scale factor. To avoid roundoff error we scale so
- * that the viewSize is a large float which is smaller than the
- * largest int.
- */
+ /*
+ * The info struct has integer fields, which will be converted to
+ * floats in the drawing routine. All of values provided in the info
+ * struct, namely min, max, value, and viewSize are only defined up to
+ * an arbitrary scale factor. To avoid roundoff error we scale so
+ * that the viewSize is a large float which is smaller than the
+ * largest int.
+ */
HIThemeTrackDrawInfo info = {
.version = 0,
@@ -2941,7 +2941,7 @@ static void SeparatorElementDraw(
CGRect bounds = BoxToRect(d, b);
const HIThemeSeparatorDrawInfo info = {
.version = 0,
- /* Separator only supports kThemeStateActive, kThemeStateInactive */
+ /* Separator only supports kThemeStateActive, kThemeStateInactive */
.state = Ttk_StateTableLookup(ThemeStateTable,
state & TTK_STATE_BACKGROUND),
};
@@ -3004,7 +3004,7 @@ static void SizegripElementDraw(
CGRect bounds = BoxToRect(d, b);
HIThemeGrowBoxDrawInfo info = {
.version = 0,
- /* Grow box only supports kThemeStateActive, kThemeStateInactive */
+ /* Grow box only supports kThemeStateActive, kThemeStateInactive */
.state = Ttk_StateTableLookup(ThemeStateTable,
state & TTK_STATE_BACKGROUND),
.kind = kHIThemeGrowBoxKindNormal,
@@ -3295,10 +3295,10 @@ static void TreeHeaderElementDraw(
BEGIN_DRAWING(d)
if ([NSApp macOSVersion] > 100800) {
- /*
- * Compensate for the padding added in TreeHeaderElementSize, so
- * the larger heading will be drawn at the top of the widget.
- */
+ /*
+ * Compensate for the padding added in TreeHeaderElementSize, so
+ * the larger heading will be drawn at the top of the widget.
+ */
bounds.origin.y -= 4;
DrawListHeader(bounds, dc.context, tkwin, state);
@@ -3484,13 +3484,13 @@ TTK_LAYOUT("TSpinbox",
TTK_LAYOUT("TEntry",
TTK_GROUP("Entry.field", TTK_FILL_BOTH|TTK_BORDER,
- TTK_GROUP("Entry.padding", TTK_FILL_BOTH,
+ TTK_GROUP("Entry.padding", TTK_FILL_BOTH,
TTK_NODE("Entry.textarea", TTK_FILL_BOTH))))
/* Searchbox */
TTK_LAYOUT("Searchbox",
TTK_GROUP("Searchbox.field", TTK_FILL_BOTH|TTK_BORDER,
- TTK_GROUP("Entry.padding", TTK_FILL_BOTH,
+ TTK_GROUP("Entry.padding", TTK_FILL_BOTH,
TTK_NODE("Entry.textarea", TTK_FILL_BOTH))))
/* Progress bars -- track only */
diff --git a/macosx/ttkMacOSXTheme.h b/macosx/ttkMacOSXTheme.h
index 1e2b7ae..2092b02 100644
--- a/macosx/ttkMacOSXTheme.h
+++ b/macosx/ttkMacOSXTheme.h
@@ -561,7 +561,7 @@ static ThemeFrameParams
#define CHECK_RADIUS(radius, bounds) \
if ((radius) > (bounds).size.width / 2 || (radius) > (bounds).size.height / 2) { \
- return; \
+ return; \
}
/*
diff --git a/tests/event.test b/tests/event.test
index c56d4d8..b43f2d3 100644
--- a/tests/event.test
+++ b/tests/event.test
@@ -265,6 +265,7 @@ test event-2.5(keypress) {type into text widget and then delete some text} -setu
test event-2.6(keypress) {type into text widget, triple click,
hit Delete key, and then type some more} -setup {
deleteWindows
+ update idletasks
} -body {
set t [toplevel .t]
set e [text $t.e]
@@ -843,9 +844,9 @@ test event-9.1 {enter . window by destroying a toplevel - bug b1d115fa60} -setup
test event-9.2 {enter toplevel window by destroying a toplevel - bug b1d115fa60} -setup {
set iconified false
if {[winfo ismapped .]} {
- wm iconify .
- update
- set iconified true
+ wm iconify .
+ update
+ set iconified true
}
} -body {
toplevel .top1
@@ -869,12 +870,318 @@ test event-9.2 {enter toplevel window by destroying a toplevel - bug b1d115fa60}
} -cleanup {
deleteWindows ; # destroy all children of ".", this already includes .top1
if {$iconified} {
- wm deiconify .
- update
+ wm deiconify .
+ update
}
} -result {.top1}
+proc waitForWindowEvent {w event {timeout 1000}} {
+# This proc is intended to overcome latency of windowing system
+# notifications when toplevel windows are involved. These latencies vary
+# considerably with the window manager in use, with the system load,
+# with configured scheduling priorities for processes, etc ...
+# Waiting for the corresponding window events evades the trouble that is
+# associated with the alternative: waiting or halting the Tk process for a
+# fixed amount of time (using "after ms"). With the latter strategy it's
+# always a gamble how much waiting time is enough on an end user's system.
+# It also leads to long fixed waiting times in order to be on the safe side.
+
+ variable _windowEvent
+
+ # Use counter as a unique ID to prevent subsequent waits
+ # from interfering with each other.
+ set counter [incr _windowEvent(counter)]
+ set _windowEvent($counter) 1
+ set savedBinding [bind $w $event]
+ bind $w $event [list +waitForWindowEvent.signal $counter]
+ set afterID [after $timeout [list set _windowEvent($counter) -1]]
+ vwait _windowEvent($counter)
+ set late [expr {$_windowEvent($counter) == -1}]
+ bind $w $event $savedBinding
+ unset _windowEvent($counter)
+ if {$late} {
+ puts stderr "wait for $event event on $w timed out (> $timeout ms)"
+ } else {
+ after cancel $afterID
+ }
+}
+proc waitForWindowEvent.signal {counter} {
+# Helper proc that records the triggering of a window event.
+ incr ::_windowEvent($counter)
+}
+
+proc create_and_pack_frames {{w {}}} {
+ frame $w.f1 -bg blue -width 200 -height 200
+ pack propagate $w.f1 0
+ frame $w.f1.f2 -bg yellow -width 100 -height 100
+ pack $w.f1.f2 $w.f1 -side bottom -anchor se
+ update idletasks
+}
+
+proc setup_win_mousepointer {w} {
+# Position the window and the mouse pointer as an initial state for some tests.
+# The so-called "pointer window" is the $w window that will now contain the mouse pointer.
+ wm geometry . +700+400; # root window out of our way - must not cover windows from event-9.1*
+ toplevel $w
+ pack propagate $w 0
+ wm geometry $w 300x300+100+100
+ tkwait visibility $w
+ update; # service remaining screen drawing events (e.g. <Expose>)
+ set pointerWin [winfo containing [winfo pointerx $w] [winfo pointery $w]]
+ event generate $w <Motion> -warp 1 -x 250 -y 250
+ if {($pointerWin ne $w) && ([tk windowingsystem] ne "aqua")} {
+ waitForWindowEvent $w <Enter>
+ } else {
+ controlPointerWarpTiming
+ }
+}
+
+test event-9.11 {pointer window container = parent} -setup {
+ setup_win_mousepointer .one
+ wm withdraw .one
+ create_and_pack_frames .one
+ wm deiconify .one
+ tkwait visibility .one.f1.f2
+ _pause 200; # needed for Windows
+ update idletasks; # finish display of window
+ set result "|"
+} -body {
+ bind all <Leave> {append result "<Leave> %d %W|"}
+ bind all <Enter> {append result "<Enter> %d %W|"}
+ destroy .one.f1.f2
+ update
+ set result
+} -cleanup {
+ bind all <Leave> {}
+ bind all <Enter> {}
+ destroy .one
+ unset result
+} -result {|<Enter> NotifyInferior .one.f1|}
+
+test event-9.12 {pointer window container != parent} -setup {
+ setup_win_mousepointer .one
+ wm withdraw .one
+ create_and_pack_frames .one
+ pack propagate .one.f1.f2 0
+ pack [frame .one.g -bg orange -width 80 -height 80] -anchor se -side bottom -in .one.f1.f2
+ wm deiconify .one
+ tkwait visibility .one.g
+ event generate .one <Motion> -warp 1 -x 250 -y 250
+ _pause 200; # needed for Windows
+ set result "|"
+} -body {
+ bind all <Leave> {append result "<Leave> %d %W|"}
+ bind all <Enter> {append result "<Enter> %d %W|"}
+ destroy .one.g
+ update
+ set result
+} -cleanup {
+ bind all <Leave> {}
+ bind all <Enter> {}
+ destroy .one
+ unset result
+} -result {|<Enter> NotifyNonlinearVirtual .one.f1|<Enter> NotifyNonlinear .one.f1.f2|}
+
+test event-9.13 {pointer window is a toplevel, toplevel destination} -setup {
+ setup_win_mousepointer .one
+ toplevel .two
+ wm geometry .two 300x300+150+150
+ wm withdraw .two
+ wm deiconify .two
+ waitForWindowEvent .two <Enter>
+ update idletasks; # finish displaying windows
+ set result |
+} -body {
+ bind all <Leave> {append result "<Leave> %d %W|"}
+ bind all <Enter> {append result "<Enter> %d %W|"}
+ destroy .two
+ waitForWindowEvent .one <Enter>
+ update
+ set result
+} -cleanup {
+ bind all <Leave> {}
+ bind all <Enter> {}
+ destroy .one
+ unset result
+} -result {|<Enter> NotifyNonlinear .one|}
+
+test event-9.14 {pointer window is a toplevel, tk internal destination} -setup {
+ setup_win_mousepointer .one
+ wm withdraw .one
+ create_and_pack_frames .one
+ toplevel .two
+ wm geometry .two 300x300+150+150
+ wm withdraw .two
+ wm deiconify .one
+ wm deiconify .two
+ waitForWindowEvent .two <Enter>
+ set result "|"
+} -body {
+ bind all <Leave> {append result "<Leave> %d %W|"}
+ bind all <Enter> {append result "<Enter> %d %W|"}
+ destroy .two
+ waitForWindowEvent .one.f1.f2 <Enter>
+ set result
+} -cleanup {
+ bind all <Leave> {}
+ bind all <Enter> {}
+ destroy .one
+ unset result
+} -result {|<Enter> NotifyNonlinearVirtual .one|<Enter> NotifyNonlinearVirtual .one.f1|<Enter> NotifyNonlinear .one.f1.f2|}
+
+test event-9.15 {pointer window is a toplevel, destination is screen root} -setup {
+ setup_win_mousepointer .one; # ensure the mouse pointer is where we want it to be (the .one toplevel is not itself used in this test)
+# destroy .one
+ toplevel .two
+ wm geometry .two 300x300+150+150
+ wm deiconify .two
+ waitForWindowEvent .two <Enter>
+ update idletasks; # finish displaying .two
+ event generate .two <Motion> -warp 1 -x 275 -y 275
+ controlPointerWarpTiming
+ set result "|"
+} -body {
+ bind all <Leave> {append result "<Leave> %d %W|"}
+ bind all <Enter> {append result "<Enter> %d %W|"}
+ destroy .two
+ set result
+} -cleanup {
+ bind all <Leave> {}
+ bind all <Enter> {}
+ destroy .one
+ unset result
+} -result {|}
+
+test event-9.16 {Successive destructions (pointer window + parent), single generation of crossing events} -setup {
+ # Tests correctness of overwriting the dead window struct in
+ # TkPointerDeadWindow() and subsequent reading in GenerateEnterLeave().
+ setup_win_mousepointer .one
+ wm withdraw .one
+ create_and_pack_frames .one
+ wm deiconify .one
+ tkwait visibility .one.f1.f2
+ update idletasks; # finish displaying window
+ _pause 200; # needed for Windows
+ set result "|"
+} -body {
+ bind all <Leave> {append result "<Leave> %d %W|"}
+ bind all <Enter> {append result "<Enter> %d %W|"}
+ destroy .one.f1
+ update
+ set result
+} -cleanup {
+ bind all <Leave> {}
+ bind all <Enter> {}
+ destroy .one
+ unset result
+} -result {|<Enter> NotifyInferior .one|}
+
+test event-9.17 {Successive destructions (pointer window + parent), separate crossing events} -setup {
+ # Tests correctness of overwriting the dead window struct in
+ # TkPointerDeadWindow() and subsequent reading in GenerateEnterLeave().
+ setup_win_mousepointer .one
+ wm withdraw .one
+ create_and_pack_frames .one
+ wm deiconify .one
+ tkwait visibility .one.f1.f2
+ update idletasks; # finish displaying window
+ _pause 200; # needed for Windows
+ set result "|"
+} -body {
+ bind all <Leave> {append result "<Leave> %d %W|"}
+ bind all <Enter> {append result "<Enter> %d %W|"}
+ destroy .one.f1.f2
+ update; # make sure window is gone
+ destroy .one.f1
+ update; # make sure window is gone
+ set result
+} -cleanup {
+ bind all <Leave> {}
+ bind all <Enter> {}
+ destroy .one
+ unset result
+} -result {|<Enter> NotifyInferior .one.f1|<Enter> NotifyInferior .one|}
+
+test event-9.18 {Successive destructions (pointer window + ancestors including its toplevel), destination is non-root toplevel} -setup {
+ setup_win_mousepointer .one
+ toplevel .two
+ pack propagate .two 0
+ wm geometry .two 300x300+100+100
+ create_and_pack_frames .two
+ wm deiconify .two
+ waitForWindowEvent .two.f1.f2 <Enter>
+ set result "|"
+} -body {
+ bind all <Leave> {append result "<Leave> %d %W|"}
+ bind all <Enter> {append result "<Enter> %d %W|"}
+ destroy .two
+ waitForWindowEvent .one <Enter>
+ set result
+} -cleanup {
+ bind all <Leave> {}
+ bind all <Enter> {}
+ destroy .one
+ unset result
+} -result {|<Enter> NotifyNonlinear .one|}
+
+test event-9.19 {Successive destructions (pointer window + ancestors including its toplevel), destination is internal window, bypass root win} -setup {
+ setup_win_mousepointer .one; # ensure the mouse pointer is where we want it to be (the .one toplevel is not itself used in this test)
+# destroy .one
+ toplevel .two
+ pack propagate .two 0
+ wm geometry .two 300x300+100+100
+ create_and_pack_frames .two
+ wm deiconify .two
+ toplevel .three
+ pack propagate .three 0
+ wm geometry .three 300x300+110+110
+ create_and_pack_frames .three
+ wm deiconify .three
+ waitForWindowEvent .three.f1.f2 <Enter>
+ update idletasks; # finish displaying windows
+ set result "|"
+} -body {
+ bind all <Leave> {append result "<Leave> %d %W|"}
+ bind all <Enter> {append result "<Enter> %d %W|"}
+ destroy .three
+ waitForWindowEvent .two.f1.f2 <Enter>
+ update idletasks; #finish destroying .two
+ set result
+} -cleanup {
+ bind all <Leave> {}
+ bind all <Enter> {}
+ destroy .one
+ destroy .two
+ unset result
+} -result {|<Enter> NotifyNonlinearVirtual .two|<Enter> NotifyNonlinearVirtual .two.f1|<Enter> NotifyNonlinear .two.f1.f2|}
+
+test event-9.20 {Successive destructions (pointer window + ancestors including its toplevel), destination is screen root} -setup {
+ setup_win_mousepointer .one; # ensure the mouse pointer is where we want it to be (the .one toplevel is not itself used in this test)
+ destroy .one
+ toplevel .two
+ pack propagate .two 0
+ wm geometry .two 300x300+100+100
+ create_and_pack_frames .two
+ wm deiconify .two
+ waitForWindowEvent .two.f1.f2 <Enter>
+ set result "|"
+} -body {
+ bind all <Leave> {append result "<Leave> %d %W|"}
+ bind all <Enter> {append result "<Enter> %d %W|"}
+ destroy .two
+ update idletasks; #finish destroying .two
+ set result
+} -cleanup {
+ bind all <Leave> {}
+ bind all <Enter> {}
+ unset result
+} -result {|}
+
# cleanup
+# macOS sometimes has trouble deleting the test window,
+# causing a failure in focus.test.
+_pause 200;
+deleteWindows
update
unset -nocomplain keypress_lookup
rename _init_keypress_lookup {}
@@ -883,6 +1190,8 @@ rename _keypress {}
rename _pause {}
rename _text_ind_to_x_y {}
rename _get_selection {}
+rename create_and_pack_frames {}
+rename setup_win_mousepointer {}
cleanupTests
return
diff --git a/tests/focus.test b/tests/focus.test
index 03563bc..17cdd58 100644
--- a/tests/focus.test
+++ b/tests/focus.test
@@ -43,10 +43,8 @@ proc focusSetupAlt {} {
# the X server and possibly also the window manager.
proc focusClear {} {
- global x;
- after 200 {set x 1}
- tkwait variable x
- dobg {focus -force .; update}
+ dobg {after 200; focus -force .; update}
+ after 400
update
}
diff --git a/tests/font.test b/tests/font.test
index ca38269..4c1f0de 100644
--- a/tests/font.test
+++ b/tests/font.test
@@ -2434,15 +2434,15 @@ test font-47.2 {Bug 3049518 - Canvas} -body {
set twidth [font measure MyFont $text]
set theight [font metrics MyFont -linespace]
set circid [$c create polygon \
- 15 15 \
- [expr {15 + $twidth}] 15 \
- [expr {15 + $twidth}] [expr {15 + $theight}] \
- 15 [expr {15 + $theight}] \
- -width 1 -joinstyle round -smooth true -fill {} -outline blue]
+ 15 15 \
+ [expr {15 + $twidth}] 15 \
+ [expr {15 + $twidth}] [expr {15 + $theight}] \
+ 15 [expr {15 + $theight}] \
+ -width 1 -joinstyle round -smooth true -fill {} -outline blue]
pack $c -fill both -expand 1 -side top
update
- # Lamda test functions
+ # Lambda test functions
set circle_text {{w user_data text circ} {
if {[winfo class $w] ne "Canvas"} {
puts "Wrong widget type: $w"
@@ -2468,6 +2468,7 @@ test font-47.2 {Bug 3049518 - Canvas} -body {
apply $circle_text $c FontChanged $textid $circid
update
bind $c <<TkWorldChanged>> [list apply $circle_text %W %d $textid $circid]
+ update idletasks
# Begin test:
set results {}
diff --git a/tests/image.test b/tests/image.test
index c7b6511..cdac20d 100644
--- a/tests/image.test
+++ b/tests/image.test
@@ -370,10 +370,6 @@ test image-9.1 {Tk_ImageChanged procedure} -constraints testImageType -setup {
foo changed 5 6 7 8 30 15
update idletasks
update
- # On MacOS we need to wait for the test image display procedure to run.
- while {"timed out" ni $x && [lindex $x end 1] ne "display"} {
- vwait x
- }
after cancel $timer
return $x
} -cleanup {
diff --git a/tests/pack.test b/tests/pack.test
index 0731125..201bf9f 100644
--- a/tests/pack.test
+++ b/tests/pack.test
@@ -1553,6 +1553,11 @@ test pack-17.2 {PackLostContentProc procedure} -setup {
# into account while the window is unmapped.
# pack-18.1.2 checks that, on Windows, width/height changes are taken into
# account on window remapping.
+#
+# While these tests pass on macOS, one can see by watching the tests
+# that the window .pack is sometimes black, even though the frame is
+# colored. So, evidently, even though the size changes are honored,
+# the window is sometimes not completely configured.
test pack-18.1.1 {unmap content when container unmapped} -constraints {
macOrUnix failsOnUbuntu failsOnXQuarz
} -setup {
@@ -1562,7 +1567,8 @@ test pack-18.1.1 {unmap content when container unmapped} -constraints {
# as the screen (screen switch causes scale and other tests to fail).
wm geometry .pack +100+100
} -body {
- frame .pack.a -width 100 -height 50 -relief raised -bd 2
+ frame .pack.a -width 100 -height 50 -relief raised -bd 2 -bg green
+ after 100
pack .pack.a
update
set result [winfo ismapped .pack.a]
@@ -1585,7 +1591,7 @@ test pack-18.1.2 {unmap content when container unmapped} -constraints {
# as the screen (screen switch causes scale and other tests to fail).
wm geometry .pack +100+100
} -body {
- frame .pack.a -width 100 -height 50 -relief raised -bd 2
+ frame .pack.a -width 100 -height 50 -relief raised -bd 2 -bg green
pack .pack.a
update
set result [winfo ismapped .pack.a]
@@ -1606,8 +1612,8 @@ test pack-18.2 {unmap content when container unmapped} -constraints {failsOnUbun
# as the screen (screen switch causes scale and other tests to fail).
wm geometry .pack +100+100
} -body {
- frame .pack.a -relief raised -bd 2
- frame .pack.b -width 70 -height 30 -relief sunken -bd 2
+ frame .pack.a -relief raised -bd 2 -bg green
+ frame .pack.b -width 70 -height 30 -relief sunken -bd 2 -bg red
pack .pack.a
pack .pack.b -in .pack.a
update
diff --git a/tests/raise.test b/tests/raise.test
index 2e9e2c6..7e6b0bd 100644
--- a/tests/raise.test
+++ b/tests/raise.test
@@ -16,6 +16,7 @@ namespace import -force tcltest::test
# Procedure to create a bunch of overlapping windows, which should
# make it easy to detect differences in order.
+wm geometry . +400+400
proc raise_setup {} {
destroy {*}[winfo children .raise]
update idletasks
diff --git a/tests/textDisp.test b/tests/textDisp.test
index 7583bc4..67df965 100644
--- a/tests/textDisp.test
+++ b/tests/textDisp.test
@@ -1107,22 +1107,28 @@ test textDisp-6.9 {DisplayText, horizontal scrollbar updates} {
set scrollInfo
} [list 0.0 [expr {4.0/11}]]
test textDisp-6.10 {DisplayText, redisplay embedded windows after scroll} {aqua} {
+ # For this test to pass line 8 must be out of the text widget.
+ # With macOS 14 this requires making the buttons a little larger.
+ # So we set the pady option. This may depend on the OS version.
.t configure -wrap char
+ update
.t delete 1.0 end
+ update
.t insert 1.0 "Line 1"
foreach i {2 3 4} {
.t insert end "\nLine $i"
}
.t insert end "\n"
.t window create end -create {
- button %W.button_one -text "Button 1"}
+ button %W.button_one -text "Button 1" -pady 5}
.t insert end "\nLine 6\n"
.t window create end -create {
- button %W.button_two -text "Button 2"}
+ button %W.button_two -text "Button 2" -pady 5}
.t insert end "\nLine 8\n"
.t window create end -create {
- button %W.button_three -text "Button 3"}
+ button %W.button_three -text "Button 3" -pady 5}
update
+ set tk_textEmbWinDisplay {}
.t delete 2.0 3.0
update
list $tk_textEmbWinDisplay
diff --git a/tests/ttk/ttk.test b/tests/ttk/ttk.test
index 6963a2a..d099c40 100644
--- a/tests/ttk/ttk.test
+++ b/tests/ttk/ttk.test
@@ -136,6 +136,8 @@ test ttk-selfdestruct-ok-1 "Intentional self-destruction" -body {
# Basic tests.
#
test ttk-1.1 "Create multiline button showing justified text" -body {
+ wm geometry . +100+100
+ event generate . <Motion> -warp 1 -x 600 -y 600
pack [ttk::button .t -text "Hello\nWorld!!" -justify center] -expand true -fill both
update
}
@@ -152,6 +154,8 @@ test ttk-1.4 "Original style preserved" -body {
.t cget -style
} -result ""
+# Tests using this will fail if the top-level window contains the cursor
+
proc checkstate {w} {
foreach statespec {
{!active !disabled}
@@ -166,7 +170,6 @@ proc checkstate {w} {
set result
}
-# NB: this will fail if the top-level window pops up underneath the cursor
test ttk-2.0 "Check state" -body {
checkstate .t
} -result [list 1 0 0 0 0 0]
@@ -342,7 +345,7 @@ test ttk-8.1 "Test -compound options" -body {
# Exhaustively test each combination.
# Main goal is to make sure no code paths crash.
foreach image {icon ""} {
- foreach text {"Hi!" ""} {
+ foreach text {"Hi!" ""} {
foreach compound $::compoundStrings {
.ctb configure -image $image -text $text -compound $compound
update; tick
@@ -357,7 +360,7 @@ test ttk-8.2 "Test -compound options with regular button" -body {
pack .rtb
foreach image {"" icon} {
- foreach text {"Hi!" ""} {
+ foreach text {"Hi!" ""} {
foreach compound [lrange $::compoundStrings 2 end] {
.rtb configure -image $image -text $text -compound $compound
update; tick
@@ -369,7 +372,7 @@ tock
test ttk-8.3 "Rerun test 8.1" -body {
foreach image {icon ""} {
- foreach text {"Hi!" ""} {
+ foreach text {"Hi!" ""} {
foreach compound $::compoundStrings {
.ctb configure -image $image -text $text -compound $compound
update; tick
diff --git a/tests/unixWm.test b/tests/unixWm.test
index 2ad40e2..9194796 100644
--- a/tests/unixWm.test
+++ b/tests/unixWm.test
@@ -16,18 +16,6 @@ namespace import -force ::tk::test:loadTkCommand
testConstraint failsOnUbuntu [expr {![info exists ::env(CI)] || ![string match Linux $::tcl_platform(os)]}]
testConstraint failsOnXQuarz [expr {$tcl_platform(os) ne "Darwin" || [tk windowingsystem] ne "x11" }]
-# Starting with macOS Ventura it became necessary to wait for windows to be restacked
-# or to be raised after creation.
-
-if {[tk windowingsystem] eq "aqua"} {
- proc restackDelay {} {
- after 200;
- update idletasks
- }
-} else {
- proc restackDelay {} {}
-}
-
proc sleep ms {
global x
after $ms {set x 1}
@@ -105,6 +93,7 @@ foreach geom "+20+80 +80+$Y0 +0+$Y0 -0-0 +0-0 -0+$Y0 -10-5 -10+$Y5 +10-5" {
set i 1
foreach geom "+20+80 +80+$Y0 +0+$Y0 -0-0 +0-0 -0+$Y0 -10-5 -10+$Y5 +10-5" {
test unixWm-3.$i {moving window while iconified} unix {
+ update
wm iconify .t
update idletasks
wm geom .t $geom
@@ -1373,7 +1362,9 @@ test unixWm-40.1 {Tk_SetGrid procedure, set grid dimensions before turning on gr
wm geometry .t
} {30x10+0+0}
test unixWm-40.2 {Tk_SetGrid procedure, turning on grid when dimensions already set} unix {
+ update
destroy .t
+ update
toplevel .t
wm geometry .t 200x100+100+$Y0
listbox .t.l -height 20 -width 20
@@ -1798,6 +1789,8 @@ test unixWm-49.2 {Tk_GetRootCoords procedure, menubars} {unix testmenubar} {
} {52 7 12 62}
deleteWindows
+# Make sure that the root window is out of the way!
+wm geom . +700+700
wm withdraw .
if {[tk windowingsystem] eq "aqua"} {
# Modern mac windows have no border.
@@ -1834,14 +1827,12 @@ test unixWm-50.2 {Tk_CoordsToWindow procedure, finding a toplevel, y-coords and
tkwait visibility .t
wm geom .t +100+100
update
- restackDelay
toplevel .t2 -width 200 -height 100 -bg blue
wm overrideredirect .t2 1
tkwait visibility .t2
wm geom .t2 +200+200
update
raise .t2
- restackDelay
set x [winfo rootx .t]
set y [winfo rooty .t]
set y2 [winfo rooty .t2]
@@ -1855,11 +1846,10 @@ test unixWm-50.2 {Tk_CoordsToWindow procedure, finding a toplevel, y-coords and
[winfo containing [expr $x +200] [expr $y + 450]]
} {{} {} .t .t .t2 .t2 .t {}}
test unixWm-50.3 {
- Tk_CoordsToWindow procedure, finding a toplevel with embedding
+ Tk_CoordsToWindow procedure, finding a toplevel with embedding
} tempNotWin {
deleteWindows
catch {interp delete child}
-
toplevel .t -width 300 -height 400 -bg blue
wm geom .t +100+100
frame .t.f -container 1 -bg red
@@ -1888,7 +1878,6 @@ test unixWm-50.3 {
} {{} .x .t .t.f}
test unixWm-50.4 {Tk_CoordsToWindow procedure, window in other application} unix {
destroy .t
-
catch {interp delete child}
toplevel .t -width 200 -height 200 -bg green
tkwait visibility .t
@@ -1897,9 +1886,8 @@ test unixWm-50.4 {Tk_CoordsToWindow procedure, window in other application} unix
interp create child
load {} Tk child
child eval {wm geometry . 200x200+100+100; update}
- restackDelay
set result [list [winfo containing 200 200] \
- [child eval {winfo containing 200 200}]]
+ [child eval {winfo containing 200 200}]]
interp delete child
set result
} {{} .}
@@ -1979,21 +1967,22 @@ test unixWm-50.8 {Tk_CoordsToWindow procedure, more basics} unix {
test unixWm-50.9 {Tk_CoordsToWindow procedure, unmapped windows} {unix failsOnUbuntu failsOnXQuarz} {
destroy .t
destroy .t2
+ update
toplevel .t -width 200 -height 200 -bg green
tkwait visibility .t
- update
- wm geometry .t +0+0
+ wm geometry .t +20+20
+ after 200
update
toplevel .t2 -width 200 -height 200 -bg red
tkwait visibility .t2
+ wm geometry .t2 +20+20
+ after 200
update
- wm geometry .t2 +0+0
- update
- restackDelay
- set result [list [winfo containing 100 100]]
- wm iconify .t2
+ set result [list [winfo containing 120 120]]
+ destroy .t2
+ after 200
update
- lappend result [winfo containing 100 100]
+ lappend result [winfo containing 120 120]
} {.t2 .t}
test unixWm-50.10 {Tk_CoordsToWindow procedure, unmapped windows} unix {
destroy .t
@@ -2071,7 +2060,6 @@ test unixWm-51.6 {TkWmRestackToplevel procedure, window to be stacked isn't mapp
tkwait visibility .t
wm geometry .t +0+0
update
- restackDelay
destroy .t2
toplevel .t2 -width 200 -height 200 -bg red
# This test assumes that .t2 is not mapped yet, but that is not really guaranteed.
@@ -2083,15 +2071,15 @@ test unixWm-51.7 {TkWmRestackToplevel procedure, other window isn't mapped} {uni
toplevel $w -width 200 -height 200 -bg green
tkwait visibility $w
wm geometry $w +100+100
+ after 200
update
}
+ update
raise .t .t2
- restackDelay
update
set result [list [winfo containing 200 200]]
lower .t3
- restackDelay
- sleep 10
+ update
lappend result [winfo containing 200 200]
} {.t3 .t}
test unixWm-51.8 {TkWmRestackToplevel procedure, overrideredirect windows} unix {
@@ -2105,7 +2093,6 @@ test unixWm-51.8 {TkWmRestackToplevel procedure, overrideredirect windows} unix
wm overrideredirect .t2 1
wm geometry .t2 +0+0
tkwait visibility .t2
- restackDelay
# Need to use vrootx and vrooty to make tests work correctly with
# virtual root window measures managers: overrideredirect windows
@@ -2116,15 +2103,14 @@ test unixWm-51.8 {TkWmRestackToplevel procedure, overrideredirect windows} unix
set y [expr 100-[winfo vrooty .]]
set result [list [winfo containing $x $y]]
raise .t
- restackDelay
lappend result [winfo containing $x $y]
raise .t2
- restackDelay
lappend result [winfo containing $x $y]
} {.t2 .t .t2}
# The mac won't put an overrideredirect window above the root,
if {[tk windowingsystem] eq "aqua"} {
wm withdraw .
+ update
}
test unixWm-51.9 {TkWmRestackToplevel procedure, other window overrideredirect} unix {
foreach w {.t .t2 .t3} {
@@ -2132,12 +2118,11 @@ test unixWm-51.9 {TkWmRestackToplevel procedure, other window overrideredirect}
update
toplevel $w -width 200 -height 200 -bg green
wm overrideredirect $w 1
- wm geometry $w +0+0
tkwait visibility $w
+ wm geometry $w +0+0
update
}
lower .t3 .t2
- restackDelay
update
# Need to use vrootx and vrooty to make tests work correctly with
@@ -2149,11 +2134,12 @@ test unixWm-51.9 {TkWmRestackToplevel procedure, other window overrideredirect}
set y [expr 100-[winfo vrooty .]]
set result [list [winfo containing $x $y]]
lower .t2
- restackDelay
+ update
lappend result [winfo containing $x $y]
} {.t2 .t3}
if {[tk windowingsystem] eq "aqua"} {
wm deiconify .
+ update
}
test unixWm-51.10 {TkWmRestackToplevel procedure, don't move window that's already in the right place} unix {
makeToplevels
diff --git a/tests/window.test b/tests/window.test
index 8a56d5a..892ceea 100644
--- a/tests/window.test
+++ b/tests/window.test
@@ -11,7 +11,8 @@ tcltest::configure {*}$argv
tcltest::loadTestedCommands
namespace import ::tk::test::loadTkCommand
update
-
+# Move the mouse out of the way for window-2.1
+event generate {} <Motion> -warp 1 -x 640 -y 10
# XXX This file is woefully incomplete. Right now it only tests
# a few parts of a few procedures in tkWindow.c
diff --git a/tests/winfo.test b/tests/winfo.test
index d4cc1ff..908647b 100644
--- a/tests/winfo.test
+++ b/tests/winfo.test
@@ -441,8 +441,10 @@ test winfo-13.3 {destroying container window} -setup {
test winfo-13.4 {[winfo containing] with embedded windows} -setup {
deleteWindows
} -body {
+ wm geometry . +100+100
frame .con -container 1
pack .con -expand yes -fill both
+ update
toplevel .emb -use [winfo id .con] -bd 0 -highlightthickness 0
button .emb.b
pack .emb.b -expand yes -fill both
diff --git a/tests/wm.test b/tests/wm.test
index d913006..650292d 100644
--- a/tests/wm.test
+++ b/tests/wm.test
@@ -1084,6 +1084,8 @@ test wm-iconwindow-1.5 {usage} -setup {
} -result {.icon is already an icon for .t2}
test wm-iconwindow-2.1 {setting and reading values} -setup {
+ # without this macOS crashes for unknown reasons
+ wm iconwindow .t {}
destroy .icon
set result {}
} -body {
diff --git a/tests/xmfbox.test b/tests/xmfbox.test
index 89eda3c..0d3b4d3 100644
--- a/tests/xmfbox.test
+++ b/tests/xmfbox.test
@@ -54,6 +54,7 @@ proc cleanup {} {
}
catch {unset foo}
destroy .foo
+ update
}
# ----------------------------------------------------------------------
@@ -76,6 +77,7 @@ test xmfbox-1.2 {tk::MotifFDialog_Create, -parent switch} -constraints {
} -body {
toplevel .bar
wm geometry .bar +0+0
+ update
set x [tk::MotifFDialog_Create foo open {-parent .bar}]
} -cleanup {
destroy $x
@@ -89,6 +91,7 @@ test xmfbox-2.1 {tk::MotifFDialog_InterpFilter, ~ in dir names} -constraints {
cleanup
file mkdir ./~nosuchuser1
set x [tk::MotifFDialog_Create foo open {}]
+ update
$::tk::dialog::file::foo(fEnt) delete 0 end
$::tk::dialog::file::foo(fEnt) insert 0 [pwd]/~nosuchuser1
file normalize [file join {*}[tk::MotifFDialog_InterpFilter $x]]
@@ -100,6 +103,7 @@ test xmfbox-2.2 {tk::MotifFDialog_InterpFilter, ~ in file names} -constraints {
cleanup
close [open ./~nosuchuser1 {CREAT TRUNC WRONLY}]
set x [tk::MotifFDialog_Create foo open {}]
+ update
$::tk::dialog::file::foo(fEnt) delete 0 end
$::tk::dialog::file::foo(fEnt) insert 0 [pwd]/~nosuchuser1
file normalize [file join {*}[tk::MotifFDialog_InterpFilter $x]]
@@ -111,6 +115,7 @@ test xmfbox-2.3 {tk::MotifFDialog_Update, ~ in file names} -constraints {
cleanup
close [open ./~nosuchuser1 {CREAT TRUNC WRONLY}]
set x [tk::MotifFDialog_Create foo open {}]
+ update
$::tk::dialog::file::foo(fEnt) delete 0 end
$::tk::dialog::file::foo(fEnt) insert 0 [pwd]/~nosuchuser1
tk::MotifFDialog_InterpFilter $x
@@ -124,6 +129,7 @@ test xmfbox-2.4 {tk::MotifFDialog_LoadFile, ~ in file names} -constraints {
cleanup
close [open ./~nosuchuser1 {CREAT TRUNC WRONLY}]
set x [tk::MotifFDialog_Create foo open {}]
+ update
set i [lsearch [$::tk::dialog::file::foo(fList) get 0 end] ~nosuchuser1]
expr {$i >= 0}
} -result 1
@@ -134,6 +140,7 @@ test xmfbox-2.5 {tk::MotifFDialog_BrowseFList, ~ in file names} -constraints {
cleanup
close [open ./~nosuchuser1 {CREAT TRUNC WRONLY}]
set x [tk::MotifFDialog_Create foo open {}]
+ update
set i [lsearch [$::tk::dialog::file::foo(fList) get 0 end] ~nosuchuser1]
$::tk::dialog::file::foo(fList) selection clear 0 end
$::tk::dialog::file::foo(fList) selection set $i
diff --git a/win/tkWinWm.c b/win/tkWinWm.c
index 7938539..ba52b32 100644
--- a/win/tkWinWm.c
+++ b/win/tkWinWm.c
@@ -2461,6 +2461,33 @@ TkpWmGetState(
*--------------------------------------------------------------
*/
+static void CheckForPointer(TkWindow *winPtr)
+{
+ POINT mouse;
+ int x, y;
+ unsigned int state = TkWinGetModifierState();
+ TkWindow **windows = TkWmStackorderToplevel(winPtr->mainPtr->winPtr);
+ TkWindow **w;
+ TkGetPointerCoords(NULL, &x, &y);
+ mouse.x = x;
+ mouse.y = y;
+ if (windows != NULL) {
+ for (w = windows; *w ; w++) {
+ RECT windowRect;
+ HWND hwnd = Tk_GetHWND(Tk_WindowId((Tk_Window) *w));
+ if (GetWindowRect(hwnd, &windowRect) == 0) {
+ continue;
+ }
+ if (winPtr != *w && PtInRect(&windowRect, mouse)) {
+ Tk_Window target = Tk_CoordsToWindow(x, y, (Tk_Window) *w);
+ Tk_UpdatePointer((Tk_Window) target, x, y, state);
+ break;
+ }
+ }
+ ckfree(windows);
+ }
+}
+
void
TkWmDeadWindow(
TkWindow *winPtr) /* Top-level window that's being deleted. */
@@ -2599,6 +2626,13 @@ TkWmDeadWindow(
DecrIconRefCount(wmPtr->iconPtr);
}
+ /*
+ * Check if the dead window is a toplevel containing the pointer. If so,
+ * find the window which will inherit the pointer and call
+ * TkUpdatePointer.
+ */
+
+ CheckForPointer(winPtr);
ckfree(wmPtr);
winPtr->wmInfoPtr = NULL;
}
@@ -6590,8 +6624,6 @@ TkWmStackorderToplevelEnumProc(
TkWmStackorderToplevelPair *pair =
(TkWmStackorderToplevelPair *) lParam;
- /*fprintf(stderr, "Looking up HWND %d\n", hwnd);*/
-
hPtr = Tcl_FindHashEntry(pair->table, hwnd);
if (hPtr != NULL) {
childWinPtr = (TkWindow *)Tcl_GetHashValue(hPtr);