Imported Tk 8.6.9

This commit is contained in:
Steve Dower
2018-12-11 10:05:28 -08:00
parent 753ac6b037
commit 5ba5cbc9af
184 changed files with 6223 additions and 1994 deletions

View File

@@ -561,3 +561,12 @@ source and destination rectangles for the scrolling. The embedded
windows are redrawn within the DisplayText function by some
conditional code which is only used for macOS.
5.0 Virtual events on 10.14
~~~~~~~~~~~~~~~~~~~~~~~~~~~
10.14 supports system appearance changes, and has added a "Dark Mode"
that casts all window frames and menus as black. Tk 8.6.9 has added two
virtual events, <<LightAqua>> and <<DarkAqua>>, to allow you to update
your Tk app's appearance when the system appearance changes. Just bind
your appearance-updating code to these virtual events and you will see
it triggered when the system appearance toggles between dark and light.

View File

@@ -42,5 +42,5 @@ TCL_LIBRARY = $(LIBDIR)/tcl$(VERSION)
TCL_PACKAGE_PATH = "$(LIBDIR)"
TCL_DEFS = HAVE_TCL_CONFIG_H
TK_LIBRARY = $(LIBDIR)/tk$(VERSION)
TK_DEFS = HAVE_TK_CONFIG_H TCL_NO_DEPRECATED
TK_DEFS = HAVE_TK_CONFIG_H
VERSION = 8.6

127
macosx/configure vendored
View File

@@ -2287,7 +2287,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
TK_VERSION=8.6
TK_MAJOR_VERSION=8
TK_MINOR_VERSION=6
TK_PATCH_LEVEL=".8"
TK_PATCH_LEVEL=".9"
VERSION=${TK_VERSION}
LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv"
@@ -2376,11 +2376,13 @@ $as_echo "$as_me: WARNING: --with-tcl argument should refer to directory contain
for i in `ls -d ${libdir} 2>/dev/null` \
`ls -d ${exec_prefix}/lib 2>/dev/null` \
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
`ls -d /usr/local/lib/tcl8.6 2>/dev/null` \
`ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \
; do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig="`(cd $i; pwd)`"
@@ -4944,7 +4946,7 @@ $as_echo "$ac_cv_cygwin" >&6; }
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
SHLIB_CFLAGS="-fPIC"
SHLIB_SUFFIX=".so"
SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}'
SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared'
DL_OBJS="tclLoadDl.o"
DL_LIBS="-lroot"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnetwork" >&5
@@ -5266,7 +5268,7 @@ fi
# get rid of the warnings.
#CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES"
SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}'
SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared'
DL_OBJS="tclLoadDl.o"
DL_LIBS="-ldl"
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
@@ -5374,7 +5376,7 @@ fi
SHLIB_CFLAGS="-fpic"
;;
esac
SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
SHLIB_SUFFIX=".so"
DL_OBJS="tclLoadDl.o"
DL_LIBS=""
@@ -5401,7 +5403,7 @@ fi
NetBSD-*)
# NetBSD has ELF and can use 'cc -shared' to build shared libs
SHLIB_CFLAGS="-fPIC"
SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
SHLIB_SUFFIX=".so"
DL_OBJS="tclLoadDl.o"
DL_LIBS=""
@@ -5420,7 +5422,7 @@ fi
fi
;;
FreeBSD-*)
DragonFly-*|FreeBSD-*)
# This configuration from FreeBSD Ports.
SHLIB_CFLAGS="-fPIC"
SHLIB_LD="${CC} -shared"
@@ -6236,7 +6238,7 @@ fi
BSD/OS*) ;;
CYGWIN_*|MINGW32_*) ;;
IRIX*) ;;
NetBSD-*|FreeBSD-*|OpenBSD-*) ;;
NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;;
Darwin-*) ;;
SCO_SV-3.2*) ;;
*) SHLIB_CFLAGS="-fPIC" ;;
@@ -6702,6 +6704,40 @@ $as_echo "#define HAVE_STRUCT_DIRENT64 1" >>confdefs.h
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for DIR64" >&5
$as_echo_n "checking for DIR64... " >&6; }
if ${tcl_cv_DIR64+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <dirent.h>
int
main ()
{
struct dirent64 *p; DIR64 d = opendir64(".");
p = readdir64(d); rewinddir64(d); closedir64(d);
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
tcl_cv_DIR64=yes
else
tcl_cv_DIR64=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_DIR64" >&5
$as_echo "$tcl_cv_DIR64" >&6; }
if test "x${tcl_cv_DIR64}" = "xyes" ; then
$as_echo "#define HAVE_DIR64 1" >>confdefs.h
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct stat64" >&5
$as_echo_n "checking for struct stat64... " >&6; }
if ${tcl_cv_struct_stat64+:} false; then :
@@ -7162,81 +7198,6 @@ $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
fi
#--------------------------------------------------------------------
# Under Solaris 2.4, strtod returns the wrong value for the
# terminating character under some conditions. Check for this
# and if the problem exists use a substitute procedure
# "fixstrtod" (provided by Tcl) that corrects the error.
#--------------------------------------------------------------------
ac_fn_c_check_func "$LINENO" "strtod" "ac_cv_func_strtod"
if test "x$ac_cv_func_strtod" = xyes; then :
tcl_strtod=1
else
tcl_strtod=0
fi
if test "$tcl_strtod" = 1; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Solaris2.4/Tru64 strtod bugs" >&5
$as_echo_n "checking for Solaris2.4/Tru64 strtod bugs... " >&6; }
if ${tcl_cv_strtod_buggy+:} false; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
tcl_cv_strtod_buggy=buggy
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern double strtod();
int main() {
char *infString="Inf", *nanString="NaN", *spaceString=" ";
char *term;
double value;
value = strtod(infString, &term);
if ((term != infString) && (term[-1] == 0)) {
exit(1);
}
value = strtod(nanString, &term);
if ((term != nanString) && (term[-1] == 0)) {
exit(1);
}
value = strtod(spaceString, &term);
if (term == (spaceString+1)) {
exit(1);
}
exit(0);
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :
tcl_cv_strtod_buggy=ok
else
tcl_cv_strtod_buggy=buggy
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_strtod_buggy" >&5
$as_echo "$tcl_cv_strtod_buggy" >&6; }
if test "$tcl_cv_strtod_buggy" = buggy; then
case " $LIBOBJS " in
*" fixstrtod.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS fixstrtod.$ac_objext"
;;
esac
USE_COMPAT=1
$as_echo "#define strtod fixstrtod" >>confdefs.h
fi
fi
#--------------------------------------------------------------------
# Check for various typedefs and provide substitutes if
# they don't exist.

View File

@@ -21,19 +21,16 @@
#include "tkMacOSXFont.h"
#include "tkMacOSXDebug.h"
#define FIRST_DRAW 2
#define ACTIVE 4
/*
* Default insets for controls
* Extra padding used for computing the content size that should
* be allowed when drawing the HITheme button.
*/
#define DEF_INSET_LEFT 12
#define DEF_INSET_RIGHT 12
#define DEF_INSET_TOP 1
#define DEF_INSET_BOTTOM 1
#define HI_PADX 2
#define HI_PADY 1
/*
* Some defines used to control what type of control is drawn.
@@ -318,9 +315,8 @@ TkpComputeButtonGeometry(
Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength,
butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
/*Remove extraneous padding around label widgets.*/
txtWidth = butPtr->textWidth;
txtHeight = butPtr->textHeight + DEF_INSET_BOTTOM + DEF_INSET_TOP;
txtHeight = butPtr->textHeight;
charWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
Tk_GetFontMetrics(butPtr->tkfont, &fm);
haveText = (txtWidth != 0 && txtHeight != 0);
@@ -364,8 +360,7 @@ TkpComputeButtonGeometry(
height = butPtr->height > 0 ? butPtr->height : height;
} else { /* Text only */
/*Add four pixels of padding to width for text-only buttons to improve appearance.*/
width = txtWidth + butPtr->indicatorSpace + 4;
width = txtWidth + butPtr->indicatorSpace;
height = txtHeight;
if (butPtr->width > 0) {
width = butPtr->width * charWidth;
@@ -396,7 +391,7 @@ TkpComputeButtonGeometry(
int paddingx = 0;
int paddingy = 0;
tmpRect = CGRectMake(0, 0, width, height);
tmpRect = CGRectMake(0, 0, width + 2*HI_PADX, height + 2*HI_PADY);
HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds);
/* If the content region has a minimum height, match it. */
@@ -425,6 +420,9 @@ TkpComputeButtonGeometry(
width += butPtr->inset*2;
height += butPtr->inset*2;
if ([NSApp macMinorVersion] == 6) {
width += 12;
}
Tk_GeometryRequest(butPtr->tkwin, width, height);
Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
@@ -649,7 +647,7 @@ DrawButtonImageAndText(
butPtr->textHeight, &x, &y);
x += butPtr->indicatorSpace;
Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout,
x, y - DEF_INSET_BOTTOM, 0, -1);
x, y, 0, -1);
}
/*
@@ -786,19 +784,6 @@ TkMacOSXDrawButton(
return;
}
if (mbPtr->btnkind == kThemePushButton) {
/*
* For some reason, pushbuttons get drawn a bit
* too low, normally. Correct for this.
*/
if (cntrRect.size.height < 22) {
cntrRect.origin.y -= 1;
} else if (cntrRect.size.height < 23) {
cntrRect.origin.y -= 2;
}
}
hiinfo.version = 0;
hiinfo.state = mbPtr->drawinfo.state;
hiinfo.kind = mbPtr->btnkind;
@@ -910,7 +895,10 @@ ButtonContentDrawCB (
return;
}
/*Overlay Tk elements over button native region: drawing elements within button boundaries/native region causes unpredictable metrics.*/
/*
* Overlay Tk elements over button native region: drawing elements
* within button boundaries/native region causes unpredictable metrics.
*/
DrawButtonImageAndText( butPtr);
}
@@ -1213,3 +1201,11 @@ PulseDefaultButtonProc(ClientData clientData)
PULSE_TIMER_MSECS, PulseDefaultButtonProc, clientData);
}
/*
* Local Variables:
* mode: objc
* c-basic-offset: 4
* fill-column: 79
* coding: utf-8
* End:
*/

View File

@@ -12,6 +12,7 @@
*/
#include "tkMacOSXPrivate.h"
#include "tkMacOSXConstants.h"
#include "tkSelect.h"
static NSInteger changeCount = -1;
@@ -70,10 +71,8 @@ static Tk_Window clipboardOwner = NULL;
if (clipboardOwner && [[NSPasteboard generalPasteboard] changeCount] !=
changeCount) {
TkDisplay *dispPtr = TkGetDisplayList();
if (dispPtr) {
XEvent event;
event.xany.type = SelectionClear;
event.xany.serial = NextRequest(Tk_Display(clipboardOwner));
event.xany.send_event = False;
@@ -125,8 +124,10 @@ TkSelGetSelection(
int result = TCL_ERROR;
TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
if (dispPtr && selection == dispPtr->clipboardAtom && (target == XA_STRING
|| target == dispPtr->utf8Atom)) {
int haveExternalClip = ([[NSPasteboard generalPasteboard] changeCount] != changeCount);
if (dispPtr && (haveExternalClip || dispPtr->clipboardActive)
&& selection == dispPtr->clipboardAtom
&& (target == XA_STRING || target == dispPtr->utf8Atom)) {
NSString *string = nil;
NSPasteboard *pb = [NSPasteboard generalPasteboard];
NSString *type = [pb availableTypeFromArray:[NSArray arrayWithObject:
@@ -176,7 +177,6 @@ XSetSelectionOwner(
clipboardOwner = owner ? Tk_IdToWindow(display, owner) : NULL;
if (!dispPtr->clipboardActive) {
NSPasteboard *pb = [NSPasteboard generalPasteboard];
changeCount = [pb declareTypes:[NSArray array] owner:NSApp];
}
}
@@ -289,28 +289,6 @@ TkSelPropProc(
{
}
/*
*----------------------------------------------------------------------
*
* TkSuspendClipboard --
*
* Handle clipboard conversion as required by the suppend event.
*
* Results:
* None.
*
* Side effects:
* The local scrap is moved to the global scrap.
*
*----------------------------------------------------------------------
*/
void
TkSuspendClipboard(void)
{
changeCount = [[NSPasteboard generalPasteboard] changeCount];
}
/*
* Local Variables:
* mode: objc

View File

@@ -41,3 +41,12 @@ TkpGetSystemDefault(
{
return NULL;
}
/*
* Local Variables:
* mode: objc
* c-basic-offset: 4
* fill-column: 79
* coding: utf-8
* End:
*/

121
macosx/tkMacOSXConstants.h Normal file
View File

@@ -0,0 +1,121 @@
/*
* tkMacOSXConstants.h --
*
* Macros which map the names of NS constants used in the Tk code to
* the new name that Apple came up with for subsequent versions of the
* operating system. (Each new OS release seems to come with a new
* naming convention for the same old constants.)
*
* Copyright (c) 2017 Marc Culler
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#ifndef _TKMACCONSTANTS
#define _TKMACCONSTANTS
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
#define NSFullScreenWindowMask (1 << 14)
#endif
/*
* Let's raise a glass for the project manager who improves our lives by
* generating deprecation warnings about pointless changes of the names
* of constants.
*/
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
#define kCTFontDefaultOrientation kCTFontOrientationDefault
#define kCTFontVerticalOrientation kCTFontOrientationVertical
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
#define NSOKButton NSModalResponseOK
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
#define kCTFontUserFixedPitchFontType kCTFontUIFontUserFixedPitch
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
#define NSAppKitDefined NSEventTypeAppKitDefined
#define NSApplicationDefined NSEventTypeApplicationDefined
#define NSApplicationActivatedEventType NSEventSubtypeApplicationActivated
#define NSApplicationDeactivatedEventType NSEventSubtypeApplicationDeactivated
#define NSWindowExposedEventType NSEventSubtypeWindowExposed
#define NSScreenChangedEventType NSEventSubtypeScreenChanged
#define NSWindowMovedEventType NSEventSubtypeWindowMoved
#define NSKeyUp NSEventTypeKeyUp
#define NSKeyDown NSEventTypeKeyDown
#define NSFlagsChanged NSEventTypeFlagsChanged
#define NSLeftMouseDown NSEventTypeLeftMouseDown
#define NSLeftMouseUp NSEventTypeLeftMouseUp
#define NSRightMouseDown NSEventTypeRightMouseDown
#define NSRightMouseUp NSEventTypeRightMouseUp
#define NSLeftMouseDragged NSEventTypeLeftMouseDragged
#define NSRightMouseDragged NSEventTypeRightMouseDragged
#define NSMouseMoved NSEventTypeMouseMoved
#define NSMouseEntered NSEventTypeMouseEntered
#define NSMouseExited NSEventTypeMouseExited
#define NSScrollWheel NSEventTypeScrollWheel
#define NSOtherMouseDown NSEventTypeOtherMouseDown
#define NSOtherMouseUp NSEventTypeOtherMouseUp
#define NSOtherMouseDragged NSEventTypeOtherMouseDragged
#define NSTabletPoint NSEventTypeTabletPoint
#define NSTabletProximity NSEventTypeTabletProximity
#define NSDeviceIndependentModifierFlagsMask NSEventModifierFlagDeviceIndependentFlagsMask
#define NSCommandKeyMask NSEventModifierFlagCommand
#define NSShiftKeyMask NSEventModifierFlagShift
#define NSAlphaShiftKeyMask NSEventModifierFlagCapsLock
#define NSAlternateKeyMask NSEventModifierFlagOption
#define NSControlKeyMask NSEventModifierFlagControl
#define NSNumericPadKeyMask NSEventModifierFlagNumericPad
#define NSFunctionKeyMask NSEventModifierFlagFunction
#define NSCursorUpdate NSEventTypeCursorUpdate
#define NSTexturedBackgroundWindowMask NSWindowStyleMaskTexturedBackground
#define NSCompositeCopy NSCompositingOperationCopy
#define NSWarningAlertStyle NSAlertStyleWarning
#define NSInformationalAlertStyle NSAlertStyleInformational
#define NSCriticalAlertStyle NSAlertStyleCritical
#define NSCenterTextAlignment NSTextAlignmentCenter
#define NSDeviceIndependentModifierFlagsMask NSEventModifierFlagDeviceIndependentFlagsMask
#define NSCommandKeyMask NSEventModifierFlagCommand
#define NSShiftKeyMask NSEventModifierFlagShift
#define NSAlphaShiftKeyMask NSEventModifierFlagCapsLock
#define NSAlternateKeyMask NSEventModifierFlagOption
#define NSControlKeyMask NSEventModifierFlagControl
#define NSNumericPadKeyMask NSEventModifierFlagNumericPad
#define NSFunctionKeyMask NSEventModifierFlagFunction
#define NSKeyUp NSEventTypeKeyUp
#define NSKeyDown NSEventTypeKeyDown
#define NSFlagsChanged NSEventTypeFlagsChanged
#define NSAlphaShiftKeyMask NSEventModifierFlagCapsLock
#define NSShiftKeyMask NSEventModifierFlagShift
#define NSAnyEventMask NSEventMaskAny
#define NSApplicationDefinedMask NSEventMaskApplicationDefined
#define NSTexturedBackgroundWindowMask NSWindowStyleMaskTexturedBackground
#define NSUtilityWindowMask NSWindowStyleMaskUtilityWindow
#define NSNonactivatingPanelMask NSWindowStyleMaskNonactivatingPanel
#define NSDocModalWindowMask NSWindowStyleMaskDocModalWindow
#define NSHUDWindowMask NSWindowStyleMaskHUDWindow
#define NSTitledWindowMask NSWindowStyleMaskTitled
#define NSClosableWindowMask NSWindowStyleMaskClosable
#define NSResizableWindowMask NSWindowStyleMaskResizable
#define NSUnifiedTitleAndToolbarWindowMask NSWindowStyleMaskUnifiedTitleAndToolbar
#define NSMiniaturizableWindowMask NSWindowStyleMaskMiniaturizable
#define NSBorderlessWindowMask NSWindowStyleMaskBorderless
#define NSFullScreenWindowMask NSWindowStyleMaskFullScreen
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
#define NSStringPboardType NSPasteboardTypeString
#define NSOnState NSControlStateValueOn
#define NSOffState NSControlStateValueOff
// Now we are also changing names of methods!
#define graphicsContextWithGraphicsPort graphicsContextWithCGContext
#endif
#endif

View File

@@ -117,7 +117,7 @@ enum alertIconOptions {
ICON_ERROR, ICON_INFO, ICON_QUESTION, ICON_WARNING
};
static const char *const alertButtonStrings[] = {
"abort", "retry", "ignore", "ok", "cancel", "yes", "no", NULL
"abort", "retry", "ignore", "ok", "cancel", "no", "yes", NULL
};
static const NSString *const alertButtonNames[][3] = {
@@ -147,8 +147,8 @@ static const short alertButtonIndexAndTypeToNativeButtonIndex[][7] = {
[TYPE_OK] = {0, 0, 0, 1, 0, 0, 0},
[TYPE_OKCANCEL] = {0, 0, 0, 1, 2, 0, 0},
[TYPE_RETRYCANCEL] = {0, 1, 0, 0, 2, 0, 0},
[TYPE_YESNO] = {0, 0, 0, 0, 0, 1, 2},
[TYPE_YESNOCANCEL] = {0, 0, 0, 0, 3, 1, 2},
[TYPE_YESNO] = {0, 0, 0, 0, 0, 2, 1},
[TYPE_YESNOCANCEL] = {0, 0, 0, 0, 3, 2, 1},
};
/*
@@ -161,8 +161,8 @@ static const short alertNativeButtonIndexAndTypeToButtonIndex[][3] = {
[TYPE_OK] = {3, 0, 0},
[TYPE_OKCANCEL] = {3, 4, 0},
[TYPE_RETRYCANCEL] = {1, 4, 0},
[TYPE_YESNO] = {5, 6, 0},
[TYPE_YESNOCANCEL] = {5, 6, 4},
[TYPE_YESNO] = {6, 5, 0},
[TYPE_YESNOCANCEL] = {6, 5, 4},
};
/*
@@ -746,7 +746,7 @@ Tk_GetOpenFileObjCmd(
/*
* The -typevariable must be set to the selected file type, if the dialog was not cancelled
*/
NSInteger selectedFilterIndex = filterInfo.fileTypeIndex;
NSUInteger selectedFilterIndex = filterInfo.fileTypeIndex;
NSString *selectedFilter = NULL;
if (filterInfo.userHasSelectedFilter) {
selectedFilterIndex = filterInfo.fileTypeIndex;
@@ -772,7 +772,7 @@ Tk_GetOpenFileObjCmd(
selectedFilter = [filterInfo.fileTypeNames objectAtIndex:selectedFilterIndex];
} else {
// scan the list
int i;
NSUInteger i;
for (i = 0; i < [filterInfo.fileTypeNames count]; i++) {
if (filterCompatible(extension, i)) {
selectedFilterIndex = i;
@@ -1198,36 +1198,42 @@ TkAboutDlg(void)
NSString *year = [dateFormatter stringFromDate:[NSDate date]];
[dateFormatter release];
NSMutableParagraphStyle *style =
[[[NSParagraphStyle defaultParagraphStyle] mutableCopy]
autorelease];
[style setAlignment:NSCenterTextAlignment];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
@"Tcl & Tk", @"ApplicationName",
@"Tcl " TCL_VERSION " & Tk " TK_VERSION, @"ApplicationVersion",
@TK_PATCH_LEVEL, @"Version",
image, @"ApplicationIcon",
[NSString stringWithFormat:@"Copyright %1$C 1987-%2$@.", 0xA9,
year], @"Copyright",
[[[NSAttributedString alloc] initWithString:
[NSString stringWithFormat:
@"%1$C 1987-%2$@ Tcl Core Team." "\n\n"
"%1$C 1989-%2$@ Contributors." "\n\n"
"%1$C 2011-%2$@ Kevin Walzer/WordTech Communications LLC." "\n\n"
"%1$C 2014-%2$@ Marc Culler." "\n\n"
"%1$C 2002-%2$@ Daniel A. Steffen." "\n\n"
"%1$C 2001-2009 Apple Inc." "\n\n"
"%1$C 2001-2002 Jim Ingham & Ian Reid" "\n\n"
"%1$C 1998-2000 Jim Ingham & Ray Johnson" "\n\n"
"%1$C 1998-2000 Scriptics Inc." "\n\n"
"%1$C 1996-1997 Sun Microsystems Inc.", 0xA9, year] attributes:
[NSDictionary dictionaryWithObject:style
forKey:NSParagraphStyleAttributeName]] autorelease], @"Credits",
nil];
[NSApp orderFrontStandardAboutPanelWithOptions:options];
/*
* This replaces the old about dialog with a standard alert that displays
* correctly on 10.14.
*/
NSString *version = @"Tcl " TCL_PATCH_LEVEL " & Tk " TCL_PATCH_LEVEL;
NSString *url = @"www.tcl-lang.org";
NSTextView *credits = [[NSTextView alloc] initWithFrame:NSMakeRect(0,0,300,300)];
NSFont *font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
NSDictionary *textAttributes = [NSDictionary dictionaryWithObject:font
forKey:NSFontAttributeName];
[credits insertText: [[NSAttributedString alloc]
initWithString:[NSString stringWithFormat: @"\n"
"Tcl and Tk are distributed under a modified BSD license: "
"www.tcl.tk/software/tcltk/license.html\n\n"
"%1$C 1987-%2$@ Tcl Core Team and Contributers.\n\n"
"%1$C 2011-%2$@ Kevin Walzer/WordTech Communications LLC.\n\n"
"%1$C 2014-%2$@ Marc Culler.\n\n"
"%1$C 2002-2012 Daniel A. Steffen.\n\n"
"%1$C 2001-2009 Apple Inc.\n\n"
"%1$C 2001-2002 Jim Ingham & Ian Reid\n\n"
"%1$C 1998-2000 Jim Ingham & Ray Johnson\n\n"
"%1$C 1998-2000 Scriptics Inc.\n\n"
"%1$C 1996-1997 Sun Microsystems Inc.", 0xA9, year]
attributes:textAttributes]
replacementRange:NSMakeRange(0,0)];
[credits setDrawsBackground:NO];
[credits setEditable:NO];
NSAlert *about = [[NSAlert alloc] init];
[[about window] setTitle:@"About Tcl & Tk"];
[about setMessageText: version];
[about setInformativeText:url];
about.accessoryView = credits;
[about runModal];
[about release];
}
/*
@@ -1257,7 +1263,7 @@ TkMacOSXStandardAboutPanelObjCmd(
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
[NSApp orderFrontStandardAboutPanelWithOptions:[NSDictionary dictionary]];
TkAboutDlg();
return TCL_OK;
}
@@ -1330,7 +1336,7 @@ Tk_MessageBoxObjCmd(
case ALERT_ICON:
if (Tcl_GetIndexFromObjStruct(interp, objv[i + 1], alertIconStrings,
sizeof(char *), "value", TCL_EXACT, &iconIndex) != TCL_OK) {
sizeof(char *), "-icon value", TCL_EXACT, &iconIndex) != TCL_OK) {
goto end;
}
break;
@@ -1360,7 +1366,7 @@ Tk_MessageBoxObjCmd(
case ALERT_TYPE:
if (Tcl_GetIndexFromObjStruct(interp, objv[i + 1], alertTypeStrings,
sizeof(char *), "value", TCL_EXACT, &typeIndex) != TCL_OK) {
sizeof(char *), "-type value", TCL_EXACT, &typeIndex) != TCL_OK) {
goto end;
}
break;
@@ -1376,7 +1382,7 @@ Tk_MessageBoxObjCmd(
*/
if (Tcl_GetIndexFromObjStruct(interp, objv[indexDefaultOption + 1],
alertButtonStrings, sizeof(char *), "value", TCL_EXACT, &index) != TCL_OK) {
alertButtonStrings, sizeof(char *), "-default value", TCL_EXACT, &index) != TCL_OK) {
goto end;
}

View File

@@ -18,6 +18,12 @@
#include "tkMacOSXDebug.h"
#include "tkButton.h"
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
#define GET_CGCONTEXT [[NSGraphicsContext currentContext] CGContext]
#else
#define GET_CGCONTEXT [[NSGraphicsContext currentContext] graphicsPort]
#endif
/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_DRAWING
@@ -105,6 +111,25 @@ TkMacOSXInitCGDrawing(
*
* Extract bitmap data from a MacOSX drawable as an NSBitmapImageRep.
*
* This is only used by XGetImage, which is never called. And this
* implementation does not work correctly. Originally it relied on
* [NSBitmapImageRep initWithFocusedViewRect:view_rect] which was
* deprecated by Apple in OSX 10.14 and also required the use of other
* deprecated functions such as [NSView lockFocus]. Apple's suggested
* replacement is [NSView cacheDisplayInRect: toBitmapImageRep:] and that
* is what is being used here. However, that method only works when the
* view has a valid CGContext, and a view is only guaranteed to have a
* valid context during a call to [NSView drawRect]. To further
* complicate matters, cacheDisplayInRect calls [NSView drawRect].
* Essentially it is asking the view to draw a subrectangle of itself into
* a special graphics context which is linked to the BitmapImageRep. But
* our implementation of [NSView drawRect] does not allow recursive calls.
* If called recursively it returns immediately without doing any drawing.
* So the bottom line is that this function either returns a NULL pointer
* or a black image. To make it useful would require a significant amount
* of rewriting of the drawRect method. Perhaps the next release of OSX
* will include some more helpful ways of doing this.
*
* Results:
* Returns an NSBitmapRep representing the image of the given
* rectangle of the given drawable. This object is retained.
@@ -128,15 +153,16 @@ TkMacOSXBitmapRepFromDrawableRect(
unsigned int height)
{
MacDrawable *mac_drawable = (MacDrawable *) drawable;
CGContextRef cg_context=NULL;
CGImageRef cg_image=NULL, sub_cg_image=NULL;
NSBitmapImageRep *bitmap_rep=NULL;
CGContextRef cg_context = NULL;
CGImageRef cg_image=NULL, sub_cg_image = NULL;
NSBitmapImageRep *bitmap_rep = NULL;
NSView *view=NULL;
if ( mac_drawable->flags & TK_IS_PIXMAP ) {
/*
* This means that the MacDrawable is functioning as a
* Tk Pixmap, so its view field is NULL.
*/
* This MacDrawable is a bitmap, so its view is NULL.
*/
cg_context = TkMacOSXGetCGContextForDrawable(drawable);
CGRect image_rect = CGRectMake(x, y, width, height);
cg_image = CGBitmapContextCreateImage( (CGContextRef) cg_context);
@@ -149,22 +175,32 @@ TkMacOSXBitmapRepFromDrawableRect(
CGImageRelease(cg_image);
}
} else if ( (view = TkMacOSXDrawableView(mac_drawable)) ) {
/*
* Convert Tk top-left to NSView bottom-left coordinates.
*/
int view_height = [view bounds].size.height;
NSRect view_rect = NSMakeRect(x + mac_drawable->xOff,
view_height - height - y - mac_drawable->yOff,
width, height);
if ( [view lockFocusIfCanDraw] ) {
bitmap_rep = [NSBitmapImageRep alloc];
bitmap_rep = [bitmap_rep initWithFocusedViewRect:view_rect];
[view unlockFocus];
} else {
TkMacOSXDbgMsg("Could not lock focus on view.");
}
/*
* Attempt to copy from the view to a bitmapImageRep. If the view does
* not have a valid CGContext, doing this will silently corrupt memory
* and make a big mess. So, in that case, we mark the view as needing
* display and return NULL.
*/
if (view == [NSView focusView]) {
bitmap_rep = [view bitmapImageRepForCachingDisplayInRect: view_rect];
[bitmap_rep retain];
[view cacheDisplayInRect:view_rect toBitmapImageRep:bitmap_rep];
} else {
TkMacOSXDbgMsg("No CGContext - cannot copy from screen to bitmap.");
[view setNeedsDisplay:YES];
return NULL;
}
} else {
TkMacOSXDbgMsg("Invalid source drawable");
}
@@ -205,26 +241,24 @@ XCopyArea(
MacDrawable *srcDraw = (MacDrawable *) src;
NSBitmapImageRep *bitmap_rep = NULL;
CGImageRef img = NULL;
CGRect bounds, srcRect, dstRect;
display->request++;
if (!width || !height) {
/* This happens all the time.
TkMacOSXDbgMsg("Drawing of empty area requested");
*/
return;
}
if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
return;
/*TkMacOSXDbgMsg("Failed to setup drawing context.");*/
TkMacOSXDbgMsg("Failed to setup drawing context.");
}
if ( dc.context ) {
if (srcDraw->flags & TK_IS_PIXMAP) {
img = TkMacOSXCreateCGImageWithDrawable(src);
}else if (TkMacOSXDrawableWindow(src)) {
bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(src, src_x, src_y, width, height);
bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(src,
src_x, src_y, width, height);
if ( bitmap_rep ) {
img = [bitmap_rep CGImage];
}
@@ -233,13 +267,12 @@ XCopyArea(
}
if (img) {
TkMacOSXDrawCGImage(dst, gc, dc.context, img, gc->foreground, gc->background,
CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height),
CGRectMake(src_x, src_y, width, height),
CGRectMake(dest_x, dest_y, width, height));
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);
CFRelease(img);
} else {
TkMacOSXDbgMsg("Failed to construct CGImage.");
}
@@ -288,7 +321,7 @@ XCopyPlane(
TkMacOSXDrawingContext dc;
MacDrawable *srcDraw = (MacDrawable *) src;
MacDrawable *dstDraw = (MacDrawable *) dst;
CGRect bounds, srcRect, dstRect;
display->request++;
if (!width || !height) {
/* TkMacOSXDbgMsg("Drawing of empty area requested"); */
@@ -308,7 +341,7 @@ XCopyPlane(
TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask;
unsigned long imageBackground = gc->background;
if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP){
CGRect srcRect = CGRectMake(src_x, src_y, width, height);
srcRect = CGRectMake(src_x, src_y, width, height);
CGImageRef mask = TkMacOSXCreateCGImageWithDrawable(clipPtr->value.pixmap);
CGImageRef submask = CGImageCreateWithImageInRect(img, srcRect);
CGRect rect = CGRectMake(dest_x, dest_y, width, height);
@@ -333,10 +366,11 @@ XCopyPlane(
CGImageRelease(submask);
CGImageRelease(subimage);
} else {
TkMacOSXDrawCGImage(dst, gc, dc.context, img, gc->foreground, imageBackground,
CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height),
CGRectMake(src_x, src_y, width, height),
CGRectMake(dest_x, dest_y, width, height));
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);
CGImageRelease(img);
}
} else { /* no image */
@@ -440,10 +474,8 @@ TkMacOSXGetNSImageWithTkImage(
int height)
{
Pixmap pixmap = Tk_GetPixmap(display, None, width, height, 0);
MacDrawable *macDraw = (MacDrawable *) pixmap;
NSImage *nsImage;
macDraw->flags |= TK_USE_XIMAGE_ALPHA;
Tk_RedrawImage(image, 0, 0, width, height, pixmap, 0, 0);
nsImage = CreateNSImageWithPixmap(pixmap, width, height);
Tk_FreePixmap(display, pixmap);
@@ -596,11 +628,13 @@ TkMacOSXDrawCGImage(
}
}
dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff);
if (CGImageIsMask(image)) {
/*CGContextSaveGState(context);*/
if (macDraw->flags & TK_IS_BW_PIXMAP) {
/* Set fill color to black, background comes from the context, or is transparent. */
/* Set fill color to black; background comes from the context,
* or is transparent.
*/
if (imageBackground != TRANSPARENT_PIXEL << 24) {
CGContextClearRect(context, dstBounds);
}
@@ -1448,7 +1482,7 @@ TkMacOSXSetUpGraphicsPort(
*----------------------------------------------------------------------
*/
int
Bool
TkMacOSXSetupDrawingContext(
Drawable d,
GC gc,
@@ -1456,41 +1490,71 @@ TkMacOSXSetupDrawingContext(
TkMacOSXDrawingContext *dcPtr)
{
MacDrawable *macDraw = ((MacDrawable*)d);
int dontDraw = 0, isWin = 0;
Bool canDraw = true;
NSWindow *win = NULL;
TkMacOSXDrawingContext dc = {};
CGRect clipBounds;
dc.clipRgn = TkMacOSXGetClipRgn(d);
if (!dontDraw) {
ClipToGC(d, gc, &dc.clipRgn);
dontDraw = dc.clipRgn ? HIShapeIsEmpty(dc.clipRgn) : 0;
/*
* If we are simulating drawing for tests, just return false.
*/
if ([NSApp simulateDrawing]) {
return false;
}
if (dontDraw) {
/*
* If the drawable is not a pixmap and it has an associated
* NSWindow then we know we are drawing to a window.
*/
if (!(macDraw->flags & TK_IS_PIXMAP)) {
win = TkMacOSXDrawableWindow(d);
}
/*
* Check that we have a non-empty clipping region.
*/
dc.clipRgn = TkMacOSXGetClipRgn(d);
ClipToGC(d, gc, &dc.clipRgn);
if (dc.clipRgn && HIShapeIsEmpty(dc.clipRgn)) {
canDraw = false;
goto end;
}
if (useCG) {
dc.context = TkMacOSXGetCGContextForDrawable(d);
}
if (!dc.context || !(macDraw->flags & TK_IS_PIXMAP)) {
isWin = (TkMacOSXDrawableWindow(d) != nil);
}
/*
* If we already have a CGContext, use it. Otherwise, if we
* are drawing to a window then we can get one from the
* window.
*/
dc.context = TkMacOSXGetCGContextForDrawable(d);
if (dc.context) {
dc.portBounds = clipBounds = CGContextGetClipBoundingBox(dc.context);
} else if (isWin) {
} else if (win) {
NSView *view = TkMacOSXDrawableView(macDraw);
if (view) {
if (view != [NSView focusView]) {
dc.focusLocked = [view lockFocusIfCanDraw];
dontDraw = !dc.focusLocked;
} else {
dontDraw = ![view canDraw];
}
if (dontDraw) {
goto end;
}
[[view window] disableFlushWindow];
/*
* We can only draw into the view when the current CGContext is
* valid and belongs to the view. Validity can only be guaranteed
* inside of a view's drawRect or setFrame methods. The isDrawing
* attribute tells us whether we are being called from one of those
* methods.
*
* If the CGContext is not valid, or belongs to a different View,
* then we mark our view as needing display and return failure.
* It should get drawn in a later call to drawRect.
*/
if (view != [NSView focusView]) {
[view setNeedsDisplay:YES];
canDraw = false;
goto end;
}
dc.view = view;
dc.context = [[NSGraphicsContext currentContext] graphicsPort];
dc.context = GET_CGCONTEXT;
dc.portBounds = NSRectToCGRect([view bounds]);
if (dc.clipRgn) {
clipBounds = CGContextGetClipBoundingBox(dc.context);
@@ -1503,14 +1567,17 @@ TkMacOSXSetupDrawingContext(
Tcl_Panic("TkMacOSXSetupDrawingContext(): "
"no context to draw into !");
}
/*
* Configure the drawing context.
*/
if (dc.context) {
CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
.ty = dc.portBounds.size.height};
dc.portBounds.origin.x += macDraw->xOff;
dc.portBounds.origin.y += macDraw->yOff;
if (!dc.focusLocked) {
CGContextSaveGState(dc.context);
}
CGContextSaveGState(dc.context);
CGContextSetTextDrawingMode(dc.context, kCGTextFill);
CGContextConcatCTM(dc.context, t);
if (dc.clipRgn) {
@@ -1545,7 +1612,7 @@ TkMacOSXSetupDrawingContext(
double w = gc->line_width;
TkMacOSXSetColorInContext(gc, gc->foreground, dc.context);
if (isWin) {
if (win) {
CGContextSetPatternPhase(dc.context, CGSizeMake(
dc.portBounds.size.width, dc.portBounds.size.height));
}
@@ -1583,13 +1650,21 @@ TkMacOSXSetupDrawingContext(
}
}
}
end:
if (dontDraw && dc.clipRgn) {
#ifdef TK_MAC_DEBUG_DRAWING
if (!canDraw && win != NULL) {
TkWindow *winPtr = TkMacOSXGetTkWindow(win);
if (winPtr) fprintf(stderr, "Cannot draw in %s - postponing.\n",
Tk_PathName(winPtr));
}
#endif
if (!canDraw && dc.clipRgn) {
CFRelease(dc.clipRgn);
dc.clipRgn = NULL;
}
*dcPtr = dc;
return !dontDraw;
return canDraw;
}
/*
@@ -1614,13 +1689,7 @@ TkMacOSXRestoreDrawingContext(
{
if (dcPtr->context) {
CGContextSynchronize(dcPtr->context);
[[dcPtr->view window] setViewsNeedDisplay:YES];
[[dcPtr->view window] enableFlushWindow];
if (dcPtr->focusLocked) {
[dcPtr->view unlockFocus];
} else {
CGContextRestoreGState(dcPtr->context);
}
CGContextRestoreGState(dcPtr->context);
}
if (dcPtr->clipRgn) {
CFRelease(dcPtr->clipRgn);
@@ -1659,17 +1728,13 @@ TkMacOSXGetClipRgn(
#ifdef TK_MAC_DEBUG_DRAWING
TkMacOSXDbgMsg("%s", macDraw->winPtr->pathName);
NSView *view = TkMacOSXDrawableView(macDraw);
if ([view lockFocusIfCanDraw]) {
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
CGContextSaveGState(context);
CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0,
-1.0, 0.0, [view bounds].size.height));
ChkErr(HIShapeReplacePathInCGContext, macDraw->visRgn, context);
CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 0.1);
CGContextEOFillPath(context);
CGContextRestoreGState(context);
[view unlockFocus];
}
CGContextSaveGState(context);
CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0,
-1.0, 0.0, [view bounds].size.height));
ChkErr(HIShapeReplacePathInCGContext, macDraw->visRgn, context);
CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 0.1);
CGContextEOFillPath(context);
CGContextRestoreGState(context);
#endif /* TK_MAC_DEBUG_DRAWING */
}
@@ -1729,13 +1794,11 @@ TkpClipDrawableToRect(
int width, int height)
{
MacDrawable *macDraw = (MacDrawable *) d;
NSView *view = TkMacOSXDrawableView(macDraw);
if (macDraw->drawRgn) {
CFRelease(macDraw->drawRgn);
macDraw->drawRgn = NULL;
}
if (width >= 0 && height >= 0) {
CGRect clipRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff,
width, height);
@@ -1751,17 +1814,6 @@ TkpClipDrawableToRect(
} else {
macDraw->drawRgn = drawRgn;
}
if (view && view != [NSView focusView] && [view lockFocusIfCanDraw]) {
clipRect.origin.y = [view bounds].size.height -
(clipRect.origin.y + clipRect.size.height);
NSRectClip(NSRectFromCGRect(clipRect));
macDraw->flags |= TK_FOCUSED_VIEW;
}
} else {
if (view && (macDraw->flags & TK_FOCUSED_VIEW)) {
[view unlockFocus];
macDraw->flags &= ~TK_FOCUSED_VIEW;
}
}
}

View File

@@ -805,7 +805,7 @@ ContainerEventProc(
*/
return;
}
/*
* Ignore any X protocol errors that happen in this procedure (almost any
* operation could fail, for example, if the embedded application has

View File

@@ -112,14 +112,23 @@ enum {
*
* TkMacOSXFlushWindows --
*
* This routine flushes all the visible windows of the application. It is
* called by XSync().
* This routine is a stub called by XSync, which is called during the Tk
* update command. The language specification does not require that the
* update command be synchronous but many of the tests assume that is the
* case. It is not naturally the case on macOS since many idle tasks are
* run inside of the drawRect method of a window's contentView, and that
* method will not be called until after this function returns. To make
* the tests work, we attempt to force this to be synchronous by waiting
* until drawRect has been called for each window. The mechanism we use
* for this is to have drawRect post an ApplicationDefined NSEvent on the
* AppKit event queue when it finishes drawing, and wait for it here.
*
* Results:
* None.
*
* Side effects:
* Flushes all visible Cocoa windows
* Calls the drawRect method of the contentView of each visible
* window.
*
*----------------------------------------------------------------------
*/
@@ -128,11 +137,14 @@ MODULE_SCOPE void
TkMacOSXFlushWindows(void)
{
NSArray *macWindows = [NSApp orderedWindows];
if ([NSApp simulateDrawing]) {
[NSApp setSimulateDrawing:NO];
return;
}
for (NSWindow *w in macWindows) {
if (TkMacOSXGetXWindow(w)) {
[w flushWindow];
}
if (TkMacOSXGetXWindow(w)) {
[w displayIfNeeded];
}
}
}

View File

@@ -14,19 +14,11 @@
#include "tkMacOSXPrivate.h"
#include "tkMacOSXFont.h"
#include "tkMacOSXConstants.h"
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
#define defaultOrientation kCTFontDefaultOrientation
#define verticalOrientation kCTFontVerticalOrientation
#else
#define defaultOrientation kCTFontOrientationDefault
#define verticalOrientation kCTFontOrientationVertical
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
#define fixedPitch kCTFontUserFixedPitchFontType
#else
#define fixedPitch kCTFontUIFontUserFixedPitch
#endif
/*
#ifdef TK_MAC_DEBUG
@@ -259,7 +251,7 @@ InitFont(
}
fontPtr->nsFont = nsFont;
// some don't like antialiasing on fixed-width even if bigger than limit
// dontAA = [nsFont isFixedPitch] && fontPtr->font.fa.size <= 10;
// dontAA = [nsFont isFixedPitch] && fontPtr->font.fa.size <= 10;
if (antialiasedTextEnabled >= 0/* || dontAA*/) {
renderingMode = (antialiasedTextEnabled == 0/* || dontAA*/) ?
NSFontIntegerAdvancementsRenderingMode :
@@ -819,15 +811,6 @@ TkpMeasureCharsInContext(
*lengthPtr = 0;
return 0;
}
#if 0
/* Back-compatibility with ATSUI renderer, appears not to be needed */
if (rangeStart == 0 && maxLength == 1 && (flags & TK_ISOLATE_END) &&
!(flags & TK_AT_LEAST_ONE)) {
length = 0;
fit = 0;
goto done;
}
#endif
if (maxLength > 32767) {
maxLength = 32767;
}
@@ -860,6 +843,10 @@ TkpMeasureCharsInContext(
double maxWidth = maxLength + offset;
NSCharacterSet *cs;
/*
* Get a line breakpoint in the source string.
*/
index = start;
if (flags & TK_WHOLE_WORDS) {
index = CTTypesetterSuggestLineBreak(typesetter, start, maxWidth);
@@ -870,15 +857,43 @@ TkpMeasureCharsInContext(
if (index <= start && !(flags & TK_WHOLE_WORDS)) {
index = CTTypesetterSuggestClusterBreak(typesetter, start, maxWidth);
}
/*
* Trim right whitespace/lineending characters.
*/
cs = (index <= len && (flags & TK_WHOLE_WORDS)) ?
whitespaceCharacterSet : lineendingCharacterSet;
while (index > start &&
[cs characterIsMember:[string characterAtIndex:(index - 1)]]) {
index--;
}
/*
* If there is no line breakpoint in the source string between
* its start and the index position that fits in maxWidth, then
* CTTypesetterSuggestLineBreak() returns that very last index.
* However if the TK_WHOLE_WORDS flag is set, we want to break
* at a word boundary. In this situation, unless TK_AT_LEAST_ONE
* is set, we must report that zero chars actually fit (in other
* words the smallest word of the source string is still larger
* than maxWidth).
*/
if ((index >= start) && (index < len) &&
(flags & TK_WHOLE_WORDS) && !(flags & TK_AT_LEAST_ONE) &&
![cs characterIsMember:[string characterAtIndex:index]]) {
index = start;
}
if (index <= start && (flags & TK_AT_LEAST_ONE)) {
index = start + 1;
}
/*
* Now measure the string width in pixels.
*/
if (index > 0) {
range.length = index;
line = CTTypesetterCreateLine(typesetter, range);
@@ -921,7 +936,6 @@ done:
flags & TK_AT_LEAST_ONE ? "atLeastOne " : "",
flags & TK_ISOLATE_END ? "isolateEnd " : "",
length, fit);
//if (!(rangeLength==1 && rangeStart == 0)) fprintf(stderr, " measure len=%d (max=%d, w=%.0f) from %d (nb=%d): source=\"%s\": index=%d return %d\n",rangeLength,maxLength,width,rangeStart,numBytes, source+rangeStart, index, fit);
#endif
*lengthPtr = length;
return fit;

View File

@@ -279,7 +279,7 @@ tkMacOSXProcessFiles(
Tcl_Interp *interp,
const char* procedure)
{
Tcl_Encoding utf8 = Tcl_GetEncoding(NULL, "utf-8");
Tcl_Encoding utf8;
const AEDesc *fileSpecDesc = nil;
AEDesc contents;
char URLString[1 + URL_MAX_LENGTH];
@@ -331,6 +331,7 @@ tkMacOSXProcessFiles(
Tcl_DStringInit(&command);
Tcl_DStringAppend(&command, procedure, -1);
utf8 = Tcl_GetEncoding(NULL, "utf-8");
for (index = 1; index <= count; index++) {
if (noErr != AEGetNthPtr(fileSpecDesc, index, typeFileURL, &keyword,
@@ -349,6 +350,8 @@ tkMacOSXProcessFiles(
Tcl_DStringAppendElement(&command, Tcl_DStringValue(&pathName));
Tcl_DStringFree(&pathName);
}
Tcl_FreeEncoding(utf8);
AEDisposeDesc(&contents);
/*
@@ -361,7 +364,6 @@ tkMacOSXProcessFiles(
Tcl_BackgroundException(interp, code);
}
Tcl_DStringFree(&command);
return;
}
/*

584
macosx/tkMacOSXImage.c Normal file
View File

@@ -0,0 +1,584 @@
/*
* tkMacOSXImage.c --
*
* The code in this file provides an interface for XImages,
*
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
* Copyright 2017-2018 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tkMacOSXPrivate.h"
#include "xbytes.h"
#pragma mark XImage handling
int
_XInitImageFuncPtrs(
XImage *image)
{
return 0;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXCreateCGImageWithXImage --
*
* Create CGImage from XImage, copying the image data. Called
* in Tk_PutImage and (currently) nowhere else.
*
* Results:
* CGImage, release after use.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void ReleaseData(void *info, const void *data, size_t size) {
ckfree(info);
}
CGImageRef
TkMacOSXCreateCGImageWithXImage(
XImage *image)
{
CGImageRef img = NULL;
size_t bitsPerComponent, bitsPerPixel;
size_t len = image->bytes_per_line * image->height;
const CGFloat *decode = NULL;
CGBitmapInfo bitmapInfo;
CGDataProviderRef provider = NULL;
char *data = NULL;
CGDataProviderReleaseDataCallback releaseData = ReleaseData;
if (image->bits_per_pixel == 1) {
/*
* BW image
*/
/* Reverses the sense of the bits */
static const CGFloat decodeWB[2] = {1, 0};
decode = decodeWB;
bitsPerComponent = 1;
bitsPerPixel = 1;
if (image->bitmap_bit_order != MSBFirst) {
char *srcPtr = image->data + image->xoffset;
char *endPtr = srcPtr + len;
char *destPtr = (data = ckalloc(len));
while (srcPtr < endPtr) {
*destPtr++ = xBitReverseTable[(unsigned char)(*(srcPtr++))];
}
} else {
data = memcpy(ckalloc(len), image->data + image->xoffset, len);
}
if (data) {
provider = CGDataProviderCreateWithData(data, data, len, releaseData);
}
if (provider) {
img = CGImageMaskCreate(image->width, image->height, bitsPerComponent,
bitsPerPixel, image->bytes_per_line, provider, decode, 0);
}
} else if (image->format == ZPixmap && image->bits_per_pixel == 32) {
/*
* Color image
*/
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
bitsPerComponent = 8;
bitsPerPixel = 32;
bitmapInfo = (image->byte_order == MSBFirst ?
kCGBitmapByteOrder32Little : kCGBitmapByteOrder32Big);
bitmapInfo |= kCGImageAlphaLast;
data = memcpy(ckalloc(len), image->data + image->xoffset, len);
if (data) {
provider = CGDataProviderCreateWithData(data, data, len, releaseData);
}
if (provider) {
img = CGImageCreate(image->width, image->height, bitsPerComponent,
bitsPerPixel, image->bytes_per_line, colorspace, bitmapInfo,
provider, decode, 0, kCGRenderingIntentDefault);
CFRelease(provider);
}
if (colorspace) {
CFRelease(colorspace);
}
} else {
TkMacOSXDbgMsg("Unsupported image type");
}
return img;
}
/*
*----------------------------------------------------------------------
*
* XGetImage --
*
* This function copies data from a pixmap or window into an XImage. It
* is essentially never used. At one time it was called by
* pTkImgPhotoDisplay, but that is no longer the case. Currently it is
* called two places, one of which is requesting an XY image which we do
* not support. It probably does not work correctly -- see the comments
* for TkMacOSXBitmapRepFromDrawableRect.
*
* Results:
* Returns a newly allocated XImage containing the data from the given
* rectangle of the given drawable, or NULL if the XImage could not be
* constructed. NOTE: If we are copying from a window on a Retina
* display, the dimensions of the XImage will be 2*width x 2*height.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
struct pixel_fmt {int r; int g; int b; int a;};
static struct pixel_fmt bgra = {2, 1, 0, 3};
static struct pixel_fmt abgr = {3, 2, 1, 0};
XImage *
XGetImage(
Display *display,
Drawable drawable,
int x,
int y,
unsigned int width,
unsigned int height,
unsigned long plane_mask,
int format)
{
NSBitmapImageRep* bitmap_rep = NULL;
NSUInteger bitmap_fmt = 0;
XImage* imagePtr = NULL;
char* bitmap = NULL;
char R, G, B, A;
int depth = 32, offset = 0, bitmap_pad = 0;
unsigned int bytes_per_row, size, row, n, m;
unsigned int scalefactor=1, scaled_height=height, scaled_width=width;
NSWindow *win = TkMacOSXDrawableWindow(drawable);
static enum {unknown, no, yes} has_retina = unknown;
if (win && has_retina == unknown) {
#ifdef __clang__
has_retina = [win respondsToSelector:@selector(backingScaleFactor)]?
yes : no;
#else
has_retina = no;
#endif
}
if (has_retina == yes) {
/*
* We only allow scale factors 1 or 2, as Apple currently does.
*/
#ifdef __clang__
scalefactor = [win backingScaleFactor] == 2.0 ? 2 : 1;
#endif
scaled_height *= scalefactor;
scaled_width *= scalefactor;
}
if (format == ZPixmap) {
if (width == 0 || height == 0) {
return NULL;
}
bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(drawable,
x, y, width, height);
if (!bitmap_rep) {
TkMacOSXDbgMsg("XGetImage: Failed to construct NSBitmapRep");
return NULL;
}
bitmap_fmt = [bitmap_rep bitmapFormat];
size = [bitmap_rep bytesPerPlane];
bytes_per_row = [bitmap_rep bytesPerRow];
bitmap = ckalloc(size);
if (!bitmap ||
(bitmap_fmt != 0 && bitmap_fmt != 1) ||
[bitmap_rep samplesPerPixel] != 4 ||
[bitmap_rep isPlanar] != 0 ||
bytes_per_row < 4 * scaled_width ||
size != bytes_per_row*scaled_height ) {
TkMacOSXDbgMsg("XGetImage: Unrecognized bitmap format");
CFRelease(bitmap_rep);
return NULL;
}
memcpy(bitmap, (char *)[bitmap_rep bitmapData], size);
CFRelease(bitmap_rep);
/*
* When Apple extracts a bitmap from an NSView, it may be in
* either BGRA or ABGR format. For an XImage we need RGBA.
*/
struct pixel_fmt pixel = bitmap_fmt == 0 ? bgra : abgr;
for (row = 0, n = 0; row < scaled_height; row++, n += bytes_per_row) {
for (m = n; m < n + 4*scaled_width; m += 4) {
R = *(bitmap + m + pixel.r);
G = *(bitmap + m + pixel.g);
B = *(bitmap + m + pixel.b);
A = *(bitmap + m + pixel.a);
*(bitmap + m) = R;
*(bitmap + m + 1) = G;
*(bitmap + m + 2) = B;
*(bitmap + m + 3) = A;
}
}
imagePtr = XCreateImage(display, NULL, depth, format, offset,
(char*)bitmap, scaled_width, scaled_height,
bitmap_pad, bytes_per_row);
if (scalefactor == 2) {
imagePtr->pixelpower = 1;
}
} else {
/*
* There are some calls to XGetImage in the generic Tk
* code which pass an XYPixmap rather than a ZPixmap.
* XYPixmaps should be handled here.
*/
TkMacOSXDbgMsg("XGetImage does not handle XYPixmaps at the moment.");
}
return imagePtr;
}
/*
*----------------------------------------------------------------------
*
* DestroyImage --
*
* Destroys storage associated with an image.
*
* Results:
* None.
*
* Side effects:
* Deallocates the image.
*
*----------------------------------------------------------------------
*/
static int
DestroyImage(
XImage *image)
{
if (image) {
if (image->data) {
ckfree(image->data);
}
ckfree(image);
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* ImageGetPixel --
*
* Get a single pixel from an image.
*
* Results:
* Returns the 32 bit pixel value.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static unsigned long
ImageGetPixel(
XImage *image,
int x,
int y)
{
unsigned char r = 0, g = 0, b = 0;
if (image && image->data) {
unsigned char *srcPtr = ((unsigned char*) image->data)
+ (y * image->bytes_per_line)
+ (((image->xoffset + x) * image->bits_per_pixel) / NBBY);
switch (image->bits_per_pixel) {
case 32: {
r = (*((unsigned int*) srcPtr) >> 16) & 0xff;
g = (*((unsigned int*) srcPtr) >> 8) & 0xff;
b = (*((unsigned int*) srcPtr) ) & 0xff;
/*if (image->byte_order == LSBFirst) {
r = srcPtr[2]; g = srcPtr[1]; b = srcPtr[0];
} else {
r = srcPtr[1]; g = srcPtr[2]; b = srcPtr[3];
}*/
break;
}
case 16:
r = (*((unsigned short*) srcPtr) >> 7) & 0xf8;
g = (*((unsigned short*) srcPtr) >> 2) & 0xf8;
b = (*((unsigned short*) srcPtr) << 3) & 0xf8;
break;
case 8:
r = (*srcPtr << 2) & 0xc0;
g = (*srcPtr << 4) & 0xc0;
b = (*srcPtr << 6) & 0xc0;
r |= r >> 2 | r >> 4 | r >> 6;
g |= g >> 2 | g >> 4 | g >> 6;
b |= b >> 2 | b >> 4 | b >> 6;
break;
case 4: {
unsigned char c = (x % 2) ? *srcPtr : (*srcPtr >> 4);
r = (c & 0x04) ? 0xff : 0;
g = (c & 0x02) ? 0xff : 0;
b = (c & 0x01) ? 0xff : 0;
break;
}
case 1:
r = g = b = ((*srcPtr) & (0x80 >> (x % 8))) ? 0xff : 0;
break;
}
}
return (PIXEL_MAGIC << 24) | (r << 16) | (g << 8) | b;
}
/*
*----------------------------------------------------------------------
*
* ImagePutPixel --
*
* Set a single pixel in an image.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
ImagePutPixel(
XImage *image,
int x,
int y,
unsigned long pixel)
{
if (image && image->data) {
unsigned char *dstPtr = ((unsigned char*) image->data)
+ (y * image->bytes_per_line)
+ (((image->xoffset + x) * image->bits_per_pixel) / NBBY);
if (image->bits_per_pixel == 32) {
*((unsigned int*) dstPtr) = pixel;
} else {
unsigned char r = ((pixel & image->red_mask) >> 16) & 0xff;
unsigned char g = ((pixel & image->green_mask) >> 8) & 0xff;
unsigned char b = ((pixel & image->blue_mask) ) & 0xff;
switch (image->bits_per_pixel) {
case 16:
*((unsigned short*) dstPtr) = ((r & 0xf8) << 7) |
((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
break;
case 8:
*dstPtr = ((r & 0xc0) >> 2) | ((g & 0xc0) >> 4) |
((b & 0xc0) >> 6);
break;
case 4: {
unsigned char c = ((r & 0x80) >> 5) | ((g & 0x80) >> 6) |
((b & 0x80) >> 7);
*dstPtr = (x % 2) ? ((*dstPtr & 0xf0) | (c & 0x0f)) :
((*dstPtr & 0x0f) | ((c << 4) & 0xf0));
break;
}
case 1:
*dstPtr = ((r|g|b) & 0x80) ? (*dstPtr | (0x80 >> (x % 8))) :
(*dstPtr & ~(0x80 >> (x % 8)));
break;
}
}
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* XCreateImage --
*
* Allocates storage for a new XImage.
*
* Results:
* Returns a newly allocated XImage.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
XImage *
XCreateImage(
Display* display,
Visual* visual,
unsigned int depth,
int format,
int offset,
char* data,
unsigned int width,
unsigned int height,
int bitmap_pad,
int bytes_per_line)
{
XImage *ximage;
display->request++;
ximage = ckalloc(sizeof(XImage));
ximage->height = height;
ximage->width = width;
ximage->depth = depth;
ximage->xoffset = offset;
ximage->format = format;
ximage->data = data;
ximage->obdata = NULL;
/* The default pixelpower is 0. This must be explicitly set to 1 in the
* case of an XImage extracted from a Retina display.
*/
ximage->pixelpower = 0;
if (format == ZPixmap) {
ximage->bits_per_pixel = 32;
ximage->bitmap_unit = 32;
} else {
ximage->bits_per_pixel = 1;
ximage->bitmap_unit = 8;
}
if (bitmap_pad) {
ximage->bitmap_pad = bitmap_pad;
} else {
/* Use 16 byte alignment for best Quartz perfomance */
ximage->bitmap_pad = 128;
}
if (bytes_per_line) {
ximage->bytes_per_line = bytes_per_line;
} else {
ximage->bytes_per_line = ((width * ximage->bits_per_pixel +
(ximage->bitmap_pad - 1)) >> 3) &
~((ximage->bitmap_pad >> 3) - 1);
}
#ifdef WORDS_BIGENDIAN
ximage->byte_order = MSBFirst;
ximage->bitmap_bit_order = MSBFirst;
#else
ximage->byte_order = LSBFirst;
ximage->bitmap_bit_order = LSBFirst;
#endif
ximage->red_mask = 0x00FF0000;
ximage->green_mask = 0x0000FF00;
ximage->blue_mask = 0x000000FF;
ximage->f.create_image = NULL;
ximage->f.destroy_image = DestroyImage;
ximage->f.get_pixel = ImageGetPixel;
ximage->f.put_pixel = ImagePutPixel;
ximage->f.sub_image = NULL;
ximage->f.add_pixel = NULL;
return ximage;
}
/*
*----------------------------------------------------------------------
*
* TkPutImage --
*
* Copies a rectangular subimage of an XImage into a drawable.
* Currently this is only called by TkImgPhotoDisplay, using
* a Window as the drawable.
*
* Results:
* None.
*
* Side effects:
* Draws the image on the specified drawable.
*
*----------------------------------------------------------------------
*/
int
TkPutImage(
unsigned long *colors, /* Unused on Macintosh. */
int ncolors, /* Unused on Macintosh. */
Display* display, /* Display. */
Drawable drawable, /* Drawable to place image on. */
GC gc, /* GC to use. */
XImage* image, /* Image to place. */
int src_x, /* Source X & Y. */
int src_y,
int dest_x, /* Destination X & Y. */
int dest_y,
unsigned int width, /* Same width & height for both */
unsigned int height) /* distination and source. */
{
TkMacOSXDrawingContext dc;
MacDrawable *macDraw = (MacDrawable *) drawable;
display->request++;
if (!TkMacOSXSetupDrawingContext(drawable, gc, 1, &dc)) {
return BadDrawable;
}
if (dc.context) {
CGRect bounds, srcRect, dstRect;
CGImageRef img = TkMacOSXCreateCGImageWithXImage(image);
/*
* The CGContext for a pixmap is RGB only, with A = 0.
*/
if (!(macDraw->flags & TK_IS_PIXMAP)) {
CGContextSetBlendMode(dc.context, kCGBlendModeSourceAtop);
}
if (img) {
/* If the XImage has big pixels, the source is rescaled to reflect
* the actual pixel dimensions. This is not currently used, but
* could arise if the image were copied from a retina monitor and
* redrawn on an ordinary monitor.
*/
int pp = image->pixelpower;
bounds = CGRectMake(0, 0, image->width, image->height);
srcRect = CGRectMake(src_x<<pp, src_y<<pp, width<<pp, height<<pp);
dstRect = CGRectMake(dest_x, dest_y, width, height);
TkMacOSXDrawCGImage(drawable, gc, dc.context,
img, gc->foreground, gc->background,
bounds, srcRect, dstRect);
CFRelease(img);
} else {
TkMacOSXDbgMsg("Invalid source drawable");
}
} else {
TkMacOSXDbgMsg("Invalid destination drawable");
}
TkMacOSXRestoreDrawingContext(&dc);
return Success;
}
/*
* Local Variables:
* mode: objc
* c-basic-offset: 4
* fill-column: 79
* coding: utf-8
* End:
*/

View File

@@ -16,7 +16,6 @@
#include "tkMacOSXPrivate.h"
#include <sys/stat.h>
#include <sys/utsname.h>
#include <dlfcn.h>
#include <objc/objc-auto.h>
@@ -29,8 +28,6 @@ static char tkLibPath[PATH_MAX + 1] = "";
static char scriptPath[PATH_MAX + 1] = "";
long tkMacOSXMacOSXVersion = 0;
#pragma mark TKApplication(TKInit)
@interface TKApplication(TKKeyboard)
@@ -48,6 +45,9 @@ long tkMacOSXMacOSXVersion = 0;
@implementation TKApplication
@synthesize poolLock = _poolLock;
@synthesize macMinorVersion = _macMinorVersion;
@synthesize isDrawing = _isDrawing;
@synthesize simulateDrawing = _simulateDrawing;
@end
/*
@@ -152,6 +152,26 @@ long tkMacOSXMacOSXVersion = 0;
_mainPool = [NSAutoreleasePool new];
[NSApp setPoolLock:0];
/*
* Record the OS version we are running on.
*/
int minorVersion;
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
Gestalt(gestaltSystemVersionMinor, (SInt32*)&minorVersion);
#else
NSOperatingSystemVersion systemVersion;
systemVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
minorVersion = systemVersion.minorVersion;
#endif
[NSApp setMacMinorVersion: minorVersion];
/*
* We are not drawing yet.
*/
[NSApp setIsDrawing:NO];
[NSApp setSimulateDrawing:NO];
/*
* Be our own delegate.
*/
@@ -160,6 +180,7 @@ long tkMacOSXMacOSXVersion = 0;
/*
* Make sure we are allowed to open windows.
*/
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
/*
@@ -255,7 +276,6 @@ TkpInit(
*/
if (!initialized) {
struct utsname name;
struct stat st;
initialized = 1;
@@ -268,20 +288,6 @@ TkpInit(
# error Mac OS X 10.6 required
#endif
if (!uname(&name)) {
tkMacOSXMacOSXVersion = (strtod(name.release, NULL) + 96) * 10;
}
/*Check for new versioning scheme on Yosemite (10.10) and later.*/
if (MAC_OS_X_VERSION_MIN_REQUIRED > 100000) {
tkMacOSXMacOSXVersion = MAC_OS_X_VERSION_MIN_REQUIRED/100;
}
if (tkMacOSXMacOSXVersion && MAC_OS_X_VERSION_MIN_REQUIRED < 100000 &&
tkMacOSXMacOSXVersion/10 < MAC_OS_X_VERSION_MIN_REQUIRED/10) {
Tcl_Panic("Mac OS X 10.%d or later required !",
(MAC_OS_X_VERSION_MIN_REQUIRED/10)-100);
}
#ifdef TK_FRAMEWORK
/*
* When Tk is in a framework, force tcl_findLibrary to look in the

View File

@@ -83,11 +83,10 @@ typedef struct TkWindowPrivate MacDrawable;
#define TK_CLIP_INVALID 0x02
#define TK_HOST_EXISTS 0x04
#define TK_DRAWN_UNDER_MENU 0x08
#define TK_FOCUSED_VIEW 0x10
#define TK_IS_PIXMAP 0x20
#define TK_IS_BW_PIXMAP 0x40
#define TK_DO_NOT_DRAW 0x80
#define TK_USE_XIMAGE_ALPHA 0x100
#define TK_IS_PIXMAP 0x10
#define TK_IS_BW_PIXMAP 0x20
#define TK_DO_NOT_DRAW 0x40
/*
* I am reserving TK_EMBEDDED = 0x100 in the MacDrawable flags
* This is defined in tk.h. We need to duplicate the TK_EMBEDDED flag in the
@@ -199,6 +198,10 @@ MODULE_SCOPE void TkpClipDrawableToRect(Display *display, Drawable d, int x,
MODULE_SCOPE void TkpRetainRegion(TkRegion r);
MODULE_SCOPE void TkpReleaseRegion(TkRegion r);
MODULE_SCOPE void TkpShiftButton(NSButton *button, NSPoint delta);
MODULE_SCOPE Bool TkpAppIsDrawing(void);
MODULE_SCOPE void TkpDisplayWindow(Tk_Window tkwin);
MODULE_SCOPE void TkTestSimulateDrawing(Bool);
/*
* Include the stubbed internal platform-specific API.
*/

View File

@@ -41,6 +41,8 @@ static int caret_x = 0, caret_y = 0, caret_height = 0;
static void setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state);
static unsigned isFunctionKey(unsigned int code);
unsigned short releaseCode;
#pragma mark TKApplication(TKKeyEvent)
@@ -66,14 +68,22 @@ static unsigned isFunctionKey(unsigned int code);
processingCompose = NO;
}
w = [theEvent window];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
Tk_Window tkwin = (Tk_Window) winPtr;
XEvent xEvent;
if (!winPtr) {
return theEvent;
}
switch (type) {
case NSKeyUp:
if (finishedCompose)
{
// if we were composing, swallow the last release since we already sent
finishedCompose = NO;
return theEvent;
}
/*Fix for bug #1ba71a86bb: key release firing on key press.*/
setupXEvent(&xEvent, w, 0);
xEvent.xany.type = KeyRelease;
xEvent.xkey.keycode = releaseCode;
xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
case NSKeyDown:
repeat = [theEvent isARepeat];
characters = [theEvent characters];
@@ -82,10 +92,9 @@ static unsigned isFunctionKey(unsigned int code);
case NSFlagsChanged:
modifiers = [theEvent modifierFlags];
keyCode = [theEvent keyCode];
// w = [self windowWithWindowNumber:[theEvent windowNumber]];
w = [theEvent window];
#if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1
NSLog(@"-[%@(%p) %s] r=%d mods=%u '%@' '%@' code=%u c=%d %@ %d", [self class], self, _cmd, repeat, modifiers, characters, charactersIgnoringModifiers, keyCode,([charactersIgnoringModifiers length] == 0) ? 0 : [charactersIgnoringModifiers characterAtIndex: 0], w, type);
TKLog(@"-[%@(%p) %s] r=%d mods=%u '%@' '%@' code=%u c=%d %@ %d", [self class], self, _cmd, repeat, modifiers, characters, charactersIgnoringModifiers, keyCode,([charactersIgnoringModifiers length] == 0) ? 0 : [charactersIgnoringModifiers characterAtIndex: 0], w, type);
#endif
break;
@@ -171,7 +180,7 @@ static unsigned isFunctionKey(unsigned int code);
xEvent.xkey.keycode = (modifiers ^ savedModifiers);
} else {
if (type == NSKeyUp || repeat) {
xEvent.xany.type = KeyRelease;
xEvent.xany.type = KeyRelease;
} else {
xEvent.xany.type = KeyPress;
}
@@ -238,11 +247,9 @@ static unsigned isFunctionKey(unsigned int code);
{
int i, len = [(NSString *)aString length];
XEvent xEvent;
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
Tk_Window tkwin = (Tk_Window) winPtr;
if (NS_KEYLOG)
NSLog (@"insertText '%@'\tlen = %d", aString, len);
TKLog (@"insertText '%@'\tlen = %d", aString, len);
processingCompose = NO;
finishedCompose = YES;
@@ -255,20 +262,17 @@ static unsigned isFunctionKey(unsigned int code);
xEvent.xany.type = KeyPress;
for (i =0; i<len; i++)
{
xEvent.xkey.keycode = (UInt16) [aString characterAtIndex: i];
[[aString substringWithRange: NSMakeRange(i,1)]
getCString: xEvent.xkey.trans_chars
maxLength: XMaxTransChars encoding: NSUTF8StringEncoding];
xEvent.xkey.nbytes = strlen(xEvent.xkey.trans_chars);
xEvent.xany.type = KeyPress;
Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
xEvent.xany.type = KeyRelease;
xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
}
{
xEvent.xkey.keycode = (UInt16) [aString characterAtIndex: i];
[[aString substringWithRange: NSMakeRange(i,1)]
getCString: xEvent.xkey.trans_chars
maxLength: XMaxTransChars encoding: NSUTF8StringEncoding];
xEvent.xkey.nbytes = strlen(xEvent.xkey.trans_chars);
xEvent.xany.type = KeyPress;
releaseCode = (UInt16) [aString characterAtIndex: 0];
Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
}
releaseCode = (UInt16) [aString characterAtIndex: 0];
}
@@ -278,7 +282,7 @@ static unsigned isFunctionKey(unsigned int code);
NSString *str = [aString respondsToSelector: @selector (string)] ?
[aString string] : aString;
if (NS_KEYLOG)
NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu", str,
TKLog (@"setMarkedText '%@' len =%lu range %lu from %lu", str,
(unsigned long) [str length], (unsigned long) selRange.length,
(unsigned long) selRange.location);
@@ -305,7 +309,7 @@ static unsigned isFunctionKey(unsigned int code);
NSRange rng = privateWorkingText != nil
? NSMakeRange (0, [privateWorkingText length]) : NSMakeRange (NSNotFound, 0);
if (NS_KEYLOG)
NSLog (@"markedRange request");
TKLog (@"markedRange request");
return rng;
}
@@ -313,7 +317,7 @@ static unsigned isFunctionKey(unsigned int code);
- (void)unmarkText
{
if (NS_KEYLOG)
NSLog (@"unmark (accept) text");
TKLog (@"unmark (accept) text");
[self deleteWorkingText];
processingCompose = NO;
}
@@ -329,7 +333,7 @@ static unsigned isFunctionKey(unsigned int code);
pt.y = caret_y;
pt = [self convertPoint: pt toView: nil];
pt = [[self window] convertPointToScreen: pt];
pt = [[self window] tkConvertPointToScreen: pt];
pt.y -= caret_height;
rect.origin = pt;
@@ -348,7 +352,7 @@ static unsigned isFunctionKey(unsigned int code);
- (void)doCommandBySelector: (SEL)aSelector
{
if (NS_KEYLOG)
NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
TKLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
processingCompose = NO;
if (aSelector == @selector (deleteBackward:))
{
@@ -378,7 +382,7 @@ static unsigned isFunctionKey(unsigned int code);
- (NSRange)selectedRange
{
if (NS_KEYLOG)
NSLog (@"selectedRange request");
TKLog (@"selectedRange request");
return NSMakeRange (NSNotFound, 0);
}
@@ -386,7 +390,7 @@ static unsigned isFunctionKey(unsigned int code);
- (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
{
if (NS_KEYLOG)
NSLog (@"characterIndexForPoint request");
TKLog (@"characterIndexForPoint request");
return 0;
}
@@ -396,7 +400,7 @@ static unsigned isFunctionKey(unsigned int code);
static NSAttributedString *str = nil;
if (str == nil) str = [NSAttributedString new];
if (NS_KEYLOG)
NSLog (@"attributedSubstringFromRange request");
TKLog (@"attributedSubstringFromRange request");
return str;
}
/* End <NSTextInput> impl. */
@@ -410,7 +414,7 @@ static unsigned isFunctionKey(unsigned int code);
if (privateWorkingText == nil)
return;
if (NS_KEYLOG)
NSLog(@"deleteWorkingText len = %lu\n",
TKLog(@"deleteWorkingText len = %lu\n",
(unsigned long)[privateWorkingText length]);
[privateWorkingText release];
privateWorkingText = nil;
@@ -430,6 +434,9 @@ setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state)
{
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
Tk_Window tkwin = (Tk_Window) winPtr;
if (!winPtr) {
return;
}
memset(xEvent, 0, sizeof(XEvent));
xEvent->xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));

View File

@@ -690,7 +690,7 @@ TkpSetKeycodeAndState(
eventPtr->xkey.keycode = 0;
} else if ( modKeyArray[0] <= keysym &&
keysym <= modKeyArray[NUM_MOD_KEYCODES - 1]) {
/*
/*
* Keysyms for pure modifiers only arise in generated events.
* We should just copy them to the keycode.
*/

View File

@@ -773,7 +773,7 @@ TkpPostMenu(
int result;
inPostMenu = 1;
result = TkPreprocessMenu(menuPtr);
if (result != TCL_OK) {
inPostMenu = 0;
@@ -785,7 +785,7 @@ TkpPostMenu(
NSRect frame = NSMakeRect(x + 9, tkMacOSXZeroScreenHeight - y - 9, 1, 1);
frame.origin = [view convertPoint:
[win convertPointFromScreen:frame.origin] fromView:nil];
[win tkConvertPointFromScreen:frame.origin] fromView:nil];
NSMenu *menu = (NSMenu *) menuPtr->platformData;
NSPopUpButtonCell *popUpButtonCell = [[NSPopUpButtonCell alloc]
@@ -1139,7 +1139,7 @@ TkpComputeStandardMenuGeometry(
columnEntryPtr->x = x;
columnEntryPtr->entryFlags &= ~ENTRY_LAST_COLUMN;
}
x += maxIndicatorSpace + maxWidth + 2 * borderWidth;
x += maxIndicatorSpace + maxWidth + 2 * activeBorderWidth;
maxWidth = maxIndicatorSpace = 0;
lastColumnBreak = i;
y = borderWidth;
@@ -1625,8 +1625,7 @@ TkpDrawMenuEntry(
int height, /* Height of the current rectangle */
int strictMotif, /* Boolean flag */
int drawArrow) /* Whether or not to draw the cascade arrow
* for cascade items. Only applies to
* Windows. */
* for cascade items. */
{
}

View File

@@ -843,3 +843,11 @@ TkMacOSXComputeMenuButtonDrawParams(TkMenuButton * butPtr, DrawParams * dpPtr)
return 1;
}
/*
* Local Variables:
* mode: objc
* c-basic-offset: 4
* fill-column: 79
* coding: utf-8
* End:
*/

View File

@@ -379,13 +379,13 @@ GenerateEditEvent(
XVirtualEvent event;
int x, y;
TkWindow *winPtr = TkMacOSXGetTkWindow([NSApp keyWindow]);
Tk_Window tkwin = (Tk_Window) winPtr;
Tk_Window tkwin;
if (tkwin == NULL) {
if (!winPtr) {
return;
}
tkwin = (Tk_Window) winPtr->dispPtr->focusPtr;
if (tkwin == NULL) {
if (!tkwin) {
return;
}
bzero(&event, sizeof(XVirtualEvent));

View File

@@ -90,14 +90,14 @@ enum {
/* Create an Xevent to add to the Tk queue. */
NSPoint global, local = [theEvent locationInWindow];
if (eventWindow) { /* local will be in window coordinates. */
global = [eventWindow convertPointToScreen: local];
global = [eventWindow tkConvertPointToScreen: local];
local.y = [eventWindow frame].size.height - local.y;
global.y = tkMacOSXZeroScreenHeight - global.y;
} else { /* local will be in screen coordinates. */
if (_windowWithMouse ) {
eventWindow = _windowWithMouse;
global = local;
local = [eventWindow convertPointFromScreen: local];
local = [eventWindow tkConvertPointFromScreen: local];
local.y = [eventWindow frame].size.height - local.y;
global.y = tkMacOSXZeroScreenHeight - global.y;
} else { /* We have no window. Use the screen???*/
@@ -373,7 +373,7 @@ XQueryPointer(
if (win) {
NSPoint local;
local = [win convertPointFromScreen:global];
local = [win tkConvertPointFromScreen:global];
local.y = [win frame].size.height - local.y;
if (macWin->winPtr && macWin->winPtr->wmInfoPtr) {
local.x -= macWin->winPtr->wmInfoPtr->xInParent;
@@ -471,7 +471,7 @@ TkGenerateButtonEvent(
if (win) {
NSPoint local = NSMakePoint(x, tkMacOSXZeroScreenHeight - y);
local = [win convertPointFromScreen:local];
local = [win tkConvertPointFromScreen:local];
local.y = [win frame].size.height - local.y;
if (macWin->winPtr && macWin->winPtr->wmInfoPtr) {
local.x -= macWin->winPtr->wmInfoPtr->xInParent;

View File

@@ -32,6 +32,85 @@ static void TkMacOSXNotifyExitHandler(ClientData clientData);
static void TkMacOSXEventsSetupProc(ClientData clientData, int flags);
static void TkMacOSXEventsCheckProc(ClientData clientData, int flags);
#ifdef TK_MAC_DEBUG_EVENTS
static char* Tk_EventName[39] = {
"",
"",
"KeyPress", /*2*/
"KeyRelease", /*3*/
"ButtonPress", /*4*/
"ButtonRelease", /*5*/
"MotionNotify", /*6*/
"EnterNotify", /*7*/
"LeaveNotify", /*8*/
"FocusIn", /*9*/
"FocusOut", /*10*/
"KeymapNotify", /*11*/
"Expose", /*12*/
"GraphicsExpose", /*13*/
"NoExpose", /*14*/
"VisibilityNotify", /*15*/
"CreateNotify", /*16*/
"DestroyNotify", /*17*/
"UnmapNotify", /*18*/
"MapNotify", /*19*/
"MapRequest", /*20*/
"ReparentNotify", /*21*/
"ConfigureNotify", /*22*/
"ConfigureRequest", /*23*/
"GravityNotify", /*24*/
"ResizeRequest", /*25*/
"CirculateNotify", /*26*/
"CirculateRequest", /*27*/
"PropertyNotify", /*28*/
"SelectionClear", /*29*/
"SelectionRequest", /*30*/
"SelectionNotify", /*31*/
"ColormapNotify", /*32*/
"ClientMessage", /*33*/
"MappingNotify", /*34*/
"VirtualEvent", /*35*/
"ActivateNotify", /*36*/
"DeactivateNotify", /*37*/
"MouseWheelEvent" /*38*/
};
static Tk_RestrictAction
InspectQueueRestrictProc(
ClientData arg,
XEvent *eventPtr)
{
XVirtualEvent* ve = (XVirtualEvent*) eventPtr;
const char *name;
long serial = ve->serial;
long time = eventPtr->xkey.time;
if (eventPtr->type == VirtualEvent) {
name = ve->name;
} else {
name = Tk_EventName[eventPtr->type];
}
fprintf(stderr, " > %s;serial = %lu; time=%lu)\n",
name, serial, time);
return TK_DEFER_EVENT;
}
/*
* Debugging tool which prints the current Tcl queue.
*/
void DebugPrintQueue(void)
{
ClientData oldArg;
Tk_RestrictProc *oldProc;
oldProc = Tk_RestrictEvents(InspectQueueRestrictProc, NULL, &oldArg);
fprintf(stderr, "Current queue:\n");
while (Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT)) {};
Tk_RestrictEvents(oldProc, oldArg, &oldArg);
}
# endif
#pragma mark TKApplication(TKNotify)
@interface NSApplication(TKNotify)
@@ -39,31 +118,26 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags);
- (void) _modalSession: (NSModalSession) session sendEvent: (NSEvent *) event;
@end
@implementation NSWindow(TKNotify)
- (id) tkDisplayIfNeeded
{
if (![self isAutodisplay]) {
[self displayIfNeeded];
}
return nil;
}
@end
@implementation TKApplication(TKNotify)
/* Display all windows each time an event is removed from the queue.*/
- (NSEvent *) nextEventMatchingMask: (NSUInteger) mask
untilDate: (NSDate *) expiration inMode: (NSString *) mode
dequeue: (BOOL) deqFlag
{
NSEvent *event = [super nextEventMatchingMask:mask
untilDate:expiration
inMode:mode
dequeue:deqFlag];
/* Retain this event for later use. Must be released.*/
[event retain];
[NSApp makeWindowsPerform:@selector(tkDisplayIfNeeded) inOrder:NO];
return event;
}
/*
* Earlier versions of Tk would override nextEventMatchingMask here, adding a
* call to displayIfNeeded on all windows after calling super. This would cause
* windows to be redisplayed (if necessary) each time that an event was
* received. This was intended to replace Apple's default autoDisplay
* mechanism, which the earlier versions of Tk would disable. When autoDisplay
* is set to the default value of YES, the Apple event loop will call
* displayIfNeeded on all windows at the beginning of each iteration of their
* event loop. Since Tk does not call the Apple event loop, it was thought
* that the autoDisplay behavior needed to be replicated.
*
* However, as of OSX 10.14 (Mojave) the autoDisplay property became
* deprecated. Luckily it turns out that, even though we don't ever start the
* Apple event loop, the Apple window manager still calls displayIfNeeded on
* all windows on a regular basis, perhaps each time the queue is empty. So we
* no longer, and perhaps never did need to set autoDisplay to NO, nor call
* displayIfNeeded on our windows. We can just leave all of that to the window
* manager.
*/
/*
* Call super then check the pasteboard.
@@ -72,6 +146,10 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags);
{
[super sendEvent:theEvent];
[NSApp tkCheckPasteboard];
#ifdef TK_MAC_DEBUG_EVENTS
fprintf(stderr, "Sending event of type %d\n", (int)[theEvent type]);
DebugPrintQueue();
#endif
}
@end
@@ -91,7 +169,7 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags);
*----------------------------------------------------------------------
*/
static NSString *
NSString *
GetRunLoopMode(NSModalSession modalSession)
{
NSString *runLoopMode = nil;
@@ -229,7 +307,6 @@ TkMacOSXEventsSetupProc(
if (currentEvent.type > 0) {
Tcl_SetMaxBlockTime(&zeroBlockTime);
}
[currentEvent release];
}
}
}
@@ -298,7 +375,6 @@ TkMacOSXEventsCheckProc(
[NSApp sendEvent:currentEvent];
}
}
[currentEvent release];
} else {
break;
}

View File

@@ -131,7 +131,6 @@ typedef struct TkMacOSXDrawingContext {
NSView *view;
HIShapeRef clipRgn;
CGRect portBounds;
int focusLocked;
} TkMacOSXDrawingContext;
/*
@@ -190,8 +189,7 @@ MODULE_SCOPE int TkGenerateButtonEventForXPointer(Window window);
MODULE_SCOPE EventModifiers TkMacOSXModifierState(void);
MODULE_SCOPE NSBitmapImageRep* TkMacOSXBitmapRepFromDrawableRect(Drawable drawable,
int x, int y, unsigned int width, unsigned int height);
MODULE_SCOPE CGImageRef TkMacOSXCreateCGImageWithXImage(XImage *image,
int use_ximage_alpha);
MODULE_SCOPE CGImageRef TkMacOSXCreateCGImageWithXImage(XImage *image);
MODULE_SCOPE void TkMacOSXDrawCGImage(Drawable d, GC gc, CGContextRef context,
CGImageRef image, unsigned long imageForeground,
unsigned long imageBackground, CGRect imageBounds,
@@ -265,9 +263,15 @@ VISIBILITY_HIDDEN
#ifdef __i386__
/* The Objective C runtime used on i386 requires this. */
int _poolLock;
int _macMinorVersion;
Bool _isDrawing;
Bool _simulateDrawing;
#endif
}
@property int poolLock;
@property int macMinorVersion;
@property Bool isDrawing;
@property Bool simulateDrawing;
@end
@interface TKApplication(TKInit)
@@ -329,8 +333,7 @@ VISIBILITY_HIDDEN
@interface TKContentView(TKWindowEvent)
- (void) drawRect: (NSRect) rect;
- (void) generateExposeEvents: (HIShapeRef) shape;
- (void) viewDidEndLiveResize;
- (void) generateExposeEvents: (HIShapeRef) shape;
- (void) tkToolbarButton: (id) sender;
- (BOOL) isOpaque;
- (BOOL) wantsDefaultClipping;
@@ -343,8 +346,8 @@ VISIBILITY_HIDDEN
@end
@interface NSWindow(TKWm)
- (NSPoint) convertPointToScreen:(NSPoint)point;
- (NSPoint) convertPointFromScreen:(NSPoint)point;
- (NSPoint) tkConvertPointToScreen:(NSPoint)point;
- (NSPoint) tkConvertPointFromScreen:(NSPoint)point;
@end
#pragma mark NSMenu & NSMenuItem Utilities

View File

@@ -8,6 +8,7 @@
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
* Copyright (c) 2015 Kevin Walzer/WordTech Commununications LLC.
* Copyright (c) 2018 Marc Culler
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
@@ -26,25 +27,40 @@
#define MIN_SLIDER_LENGTH 5
/*Borrowed from ttkMacOSXTheme.c to provide appropriate scaling of scrollbar values.*/
/*Borrowed from ttkMacOSXTheme.c to provide appropriate scaling.*/
#ifdef __LP64__
#define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum))
#else
#define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum))
#endif /* __LP64__ */
#define MOUNTAIN_LION_STYLE (NSAppKitVersionNumber < 1138)
/*
* Apple reversed the scroll direction with the release of OSX 10.7 Lion.
*/
#define SNOW_LEOPARD_STYLE (NSAppKitVersionNumber < 1138)
/*
* Declaration of Mac specific scrollbar structure.
* Declaration of an extended scrollbar structure with Mac specific additions.
*/
typedef struct MacScrollbar {
TkScrollbar information; /* Generic scrollbar info. */
TkScrollbar information; /* Generic scrollbar info. */
GC troughGC; /* For drawing trough. */
GC copyGC; /* Used for copying from pixmap onto screen. */
Bool buttonDown; /* Is the mouse button down? */
Bool mouseOver; /* Is the pointer over the scrollbar. */
HIThemeTrackDrawInfo info; /* Controls how the scrollbar is drawn. */
} MacScrollbar;
/* Used to initialize a MacScrollbar's info field. */
HIThemeTrackDrawInfo defaultInfo = {
.version = 0,
.min = 0.0,
.max = 100.0,
.attributes = kThemeTrackShowThumb,
};
/*
* The class procedure table for the scrollbar widget. All fields except size
* are left initialized to NULL, which should happen automatically since the
@@ -59,31 +75,25 @@ const Tk_ClassProcs tkpScrollbarProcs = {
};
/*Information on scrollbar layout, metrics, and draw info.*/
/* Information on scrollbar layout, metrics, and draw info.*/
typedef struct ScrollbarMetrics {
SInt32 width, minThumbHeight;
int minHeight, topArrowHeight, bottomArrowHeight;
NSControlSize controlSize;
} ScrollbarMetrics;
static ScrollbarMetrics metrics[2] = {
{15, 54, 26, 14, 14, kControlSizeNormal}, /* kThemeScrollBarMedium */
{11, 40, 20, 10, 10, kControlSizeSmall}, /* kThemeScrollBarSmall */
};
HIThemeTrackDrawInfo info = {
.version = 0,
.min = 0.0,
.max = 100.0,
.attributes = kThemeTrackShowThumb,
static ScrollbarMetrics metrics = {
15, 54, 26, 14, 14, kControlSizeNormal /* kThemeScrollBarMedium */
};
/*
* Forward declarations for procedures defined later in this file:
* Declarations of static functions defined later in this file:
*/
static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr);
static int ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr);
static int ScrollbarEvent(TkScrollbar *scrollPtr, XEvent *eventPtr);
static void UpdateControlValues(TkScrollbar *scrollPtr);
/*
@@ -111,8 +121,19 @@ TkpCreateScrollbar(
scrollPtr->troughGC = None;
scrollPtr->copyGC = None;
Tk_CreateEventHandler(tkwin,ExposureMask|StructureNotifyMask|FocusChangeMask|ButtonPressMask|ButtonReleaseMask|EnterWindowMask|LeaveWindowMask|VisibilityChangeMask, ScrollbarEventProc, scrollPtr);
scrollPtr->info = defaultInfo;
scrollPtr->buttonDown = false;
Tk_CreateEventHandler(tkwin,
ExposureMask |
StructureNotifyMask |
FocusChangeMask |
ButtonPressMask |
ButtonReleaseMask |
EnterWindowMask |
LeaveWindowMask |
VisibilityChangeMask,
ScrollbarEventProc, scrollPtr);
return (TkScrollbar *) scrollPtr;
}
@@ -130,7 +151,7 @@ TkpCreateScrollbar(
* None.
*
* Side effects:
* Information appears on the screen.
* Draws a scrollbar on the screen.
*
*--------------------------------------------------------------
*/
@@ -140,6 +161,7 @@ TkpDisplayScrollbar(
ClientData clientData) /* Information about window. */
{
register TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
MacScrollbar *msPtr = (MacScrollbar *) scrollPtr;
register Tk_Window tkwin = scrollPtr->tkwin;
TkWindow *winPtr = (TkWindow *) tkwin;
TkMacOSXDrawingContext dc;
@@ -163,7 +185,7 @@ TkpDisplayScrollbar(
.ty = viewHeight};
CGContextConcatCTM(dc.context, t);
/*Draw Unix-style scroll trough to provide rect for native scrollbar.*/
/*Draw a 3D rectangle to provide a base for the native scrollbar.*/
if (scrollPtr->highlightWidth != 0) {
GC fgGC, bgGC;
@@ -187,12 +209,13 @@ TkpDisplayScrollbar(
Tk_Width(tkwin) - 2*scrollPtr->inset,
Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT);
/*Update values and draw in native rect.*/
/* Update values and then draw the native scrollbar over the rectangle.*/
UpdateControlValues(scrollPtr);
if (MOUNTAIN_LION_STYLE) {
HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationInverted);
if (SNOW_LEOPARD_STYLE) {
HIThemeDrawTrack (&(msPtr->info), 0, dc.context, kHIThemeOrientationInverted);
} else {
HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal);
HIThemeDrawTrack (&(msPtr->info), 0, dc.context, kHIThemeOrientationNormal);
}
TkMacOSXRestoreDrawingContext(&dc);
@@ -218,76 +241,89 @@ TkpDisplayScrollbar(
*/
extern void
extern void
TkpComputeScrollbarGeometry(
register TkScrollbar *scrollPtr)
/* Scrollbar whose geometry may have
* changed. */
register TkScrollbar *scrollPtr)
/* Scrollbar whose geometry may have
* changed. */
{
int variant, fieldLength;
/*
* The code below is borrowed from tkUnixScrlbr.c but has been adjusted to
* account for some differences between macOS and X11. The Unix scrollbar
* has an arrow button on each end. On macOS 10.6 (Snow Leopard) the
* scrollbars by default have both arrow buttons at the bottom or right.
* (There is a preferences setting to use the Unix layout, but we are not
* supporting that!) On more recent versions of macOS there are no arrow
* buttons at all. The case of no arrow buttons can be handled as a special
* case of having both buttons at the end, but where scrollPtr->arrowLength
* happens to be zero. To adjust for having both arrows at the same end we
* shift the scrollbar up by the arrowLength.
*/
int fieldLength;
if (scrollPtr->highlightWidth < 0) {
scrollPtr->highlightWidth = 0;
scrollPtr->highlightWidth = 0;
}
scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
variant = ((scrollPtr->vertical ? Tk_Width(scrollPtr->tkwin) :
Tk_Height(scrollPtr->tkwin)) - 2 * scrollPtr->inset
< metrics[0].width) ? 1 : 0;
scrollPtr->arrowLength = (metrics[variant].topArrowHeight +
metrics[variant].bottomArrowHeight) / 2;
fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
: Tk_Width(scrollPtr->tkwin))
- 2 * (scrollPtr->arrowLength + scrollPtr->inset);
if (fieldLength < 0) {
fieldLength = 0;
if ([NSApp macMinorVersion] == 6) {
scrollPtr->arrowLength = scrollPtr->width;
} else {
scrollPtr->arrowLength = 0;
}
scrollPtr->sliderFirst = fieldLength * scrollPtr->firstFraction;
scrollPtr->sliderLast = fieldLength * scrollPtr->lastFraction;
fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
: Tk_Width(scrollPtr->tkwin))
- 2*(scrollPtr->arrowLength + scrollPtr->inset);
if (fieldLength < 0) {
fieldLength = 0;
}
scrollPtr->sliderFirst = fieldLength*scrollPtr->firstFraction;
scrollPtr->sliderLast = fieldLength*scrollPtr->lastFraction;
/*
* Adjust the slider so that some piece of it is always
* displayed in the scrollbar and so that it has at least
* a minimal width (so it can be grabbed with the mouse).
* Adjust the slider so that some piece of it is always displayed in the
* scrollbar and so that it has at least a minimal width (so it can be
* grabbed with the mouse).
*/
if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) {
scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
if (scrollPtr->sliderFirst > fieldLength - MIN_SLIDER_LENGTH) {
scrollPtr->sliderFirst = fieldLength - MIN_SLIDER_LENGTH;
}
if (scrollPtr->sliderFirst < 0) {
scrollPtr->sliderFirst = 0;
scrollPtr->sliderFirst = 0;
}
if (scrollPtr->sliderLast < (scrollPtr->sliderFirst +
metrics[variant].minThumbHeight)) {
scrollPtr->sliderLast = scrollPtr->sliderFirst +
metrics[variant].minThumbHeight;
if (scrollPtr->sliderLast < scrollPtr->sliderFirst + MIN_SLIDER_LENGTH) {
scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH;
}
if (scrollPtr->sliderLast > fieldLength) {
scrollPtr->sliderLast = fieldLength;
scrollPtr->sliderLast = fieldLength;
}
scrollPtr->sliderFirst += -scrollPtr->arrowLength + scrollPtr->inset;
scrollPtr->sliderLast += scrollPtr->inset;
scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset;
scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset;
/* Register the desired geometry for the window (leave enough space
* for the two arrows plus a minimum-size slider, plus border around
* the whole window, if any). Then arrange for the window to be
* redisplayed.
/*
* Register the desired geometry for the window. Leave enough space for the
* two arrows, if there are any arrows, plus a minimum-size slider, plus
* border around the whole window, if any. Then arrange for the window to
* be redisplayed.
*/
if (scrollPtr->vertical) {
Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width + 2 * scrollPtr->inset, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics[variant].minThumbHeight);
if (scrollPtr->vertical) {
Tk_GeometryRequest(scrollPtr->tkwin,
scrollPtr->width + 2*scrollPtr->inset,
2*(scrollPtr->arrowLength + scrollPtr->borderWidth
+ scrollPtr->inset) + metrics.minThumbHeight);
} else {
Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics[variant].minThumbHeight, scrollPtr->width + 2 * scrollPtr->inset);
Tk_GeometryRequest(scrollPtr->tkwin,
2*(scrollPtr->arrowLength + scrollPtr->borderWidth
+ scrollPtr->inset) + metrics.minThumbHeight,
scrollPtr->width + 2*scrollPtr->inset);
}
Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset);
}
/*
*----------------------------------------------------------------------
*
@@ -316,8 +352,6 @@ TkpDestroyScrollbar(
if (macScrollPtr->copyGC != None) {
Tk_FreeGC(scrollPtr->display, macScrollPtr->copyGC);
}
macScrollPtr=NULL;
}
/*
@@ -327,13 +361,13 @@ TkpDestroyScrollbar(
*
* This procedure is called after the generic code has finished
* processing configuration options, in order to configure platform
* specific options.
* specific options. There are no such option on the Mac, however.
*
* Results:
* None.
*
* Side effects:
* Configuration info may get changed.
* Currently, none.
*
*----------------------------------------------------------------------
*/
@@ -341,8 +375,6 @@ TkpDestroyScrollbar(
void
TkpConfigureScrollbar(
register TkScrollbar *scrollPtr)
/* Information about widget; may or may not
* already have values for some fields. */
{
}
@@ -372,54 +404,51 @@ TkpScrollbarPosition(
int x, int y) /* Coordinates within scrollPtr's window. */
{
/*
* Using code from tkUnixScrlbr.c because Unix scroll bindings are
* driving the display at the script level. All the Mac scrollbar
* has to do is re-draw itself.
/*
* The code below is borrowed from tkUnixScrlbr.c and needs no adjustment
* since it does not involve the arrow buttons.
*/
int length, fieldlength, width, tmp;
int length, width, tmp;
register const int inset = scrollPtr->inset;
register const int arrowSize = scrollPtr->arrowLength + inset;
if (scrollPtr->vertical) {
length = Tk_Height(scrollPtr->tkwin);
fieldlength = length - 2 * arrowSize;
width = Tk_Width(scrollPtr->tkwin);
} else {
tmp = x;
x = y;
y = tmp;
length = Tk_Width(scrollPtr->tkwin);
fieldlength = length - 2 * arrowSize;
width = Tk_Height(scrollPtr->tkwin);
}
fieldlength = fieldlength < 0 ? 0 : fieldlength;
if (x<inset || x>=width-inset || y<inset || y>=length-inset) {
if (x < inset || x >= width - inset ||
y < inset || y >= length - inset) {
return OUTSIDE;
}
/*
* All of the calculations in this procedure mirror those in
* TkpDisplayScrollbar. Be sure to keep the two consistent.
* Here we assume that the scrollbar is layed out with both arrow buttons
* at the bottom (or right). Except on 10.6, however, the arrows do not
* actually exist, i.e. the arrowLength is 0. These are the same
* assumptions which are being made in TkpComputeScrollbarGeometry.
*/
if (y < scrollPtr->sliderFirst) {
if (y < scrollPtr->sliderFirst + scrollPtr->arrowLength) {
return TOP_GAP;
}
if (y < scrollPtr->sliderLast) {
}
if (y < scrollPtr->sliderLast) {
return SLIDER;
}
if (y < fieldlength){
}
if (y < length - (2*scrollPtr->arrowLength + inset)) {
return BOTTOM_GAP;
}
if (y < fieldlength + arrowSize) {
}
/* On systems newer than 10.6 we have already returned. */
if (y < length - (scrollPtr->arrowLength + inset)) {
return TOP_ARROW;
}
return BOTTOM_ARROW;
}
return BOTTOM_ARROW;
}
/*
@@ -429,7 +458,7 @@ TkpScrollbarPosition(
*
* This procedure updates the Macintosh scrollbar control to
* display the values defined by the Tk scrollbar. This is the
* key interface to the Mac-native * scrollbar; the Unix bindings
* key interface to the Mac-native scrollbar; the Unix bindings
* drive scrolling in the Tk window and all the Mac scrollbar has
* to do is redraw itself.
*
@@ -446,11 +475,11 @@ static void
UpdateControlValues(
TkScrollbar *scrollPtr) /* Scrollbar data struct. */
{
MacScrollbar *msPtr = (MacScrollbar *)scrollPtr;
Tk_Window tkwin = scrollPtr->tkwin;
MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin);
double dViewSize;
HIRect contrlRect;
int variant;
short width, height;
NSView *view = TkMacOSXDrawableView(macWin);
@@ -462,23 +491,21 @@ UpdateControlValues(
frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
contrlRect = NSRectToCGRect(frame);
info.bounds = contrlRect;
msPtr->info.bounds = contrlRect;
width = contrlRect.size.width;
height = contrlRect.size.height;
variant = contrlRect.size.width < metrics[0].width ? 1 : 0;
/*
* Ensure we set scrollbar control bounds only once all size adjustments
* have been computed.
*/
info.bounds = contrlRect;
msPtr->info.bounds = contrlRect;
if (scrollPtr->vertical) {
info.attributes &= ~kThemeTrackHorizontal;
msPtr->info.attributes &= ~kThemeTrackHorizontal;
} else {
info.attributes |= kThemeTrackHorizontal;
msPtr->info.attributes |= kThemeTrackHorizontal;
}
/*
@@ -495,25 +522,25 @@ UpdateControlValues(
factor = RangeToFactor(maximum);
dViewSize = (scrollPtr->lastFraction - scrollPtr->firstFraction)
* factor;
info.max = MIN_SCROLLBAR_VALUE +
msPtr->info.max = MIN_SCROLLBAR_VALUE +
factor - dViewSize;
info.trackInfo.scrollbar.viewsize = dViewSize;
msPtr->info.trackInfo.scrollbar.viewsize = dViewSize;
if (scrollPtr->vertical) {
if (MOUNTAIN_LION_STYLE) {
info.value = factor * scrollPtr->firstFraction;
if (SNOW_LEOPARD_STYLE) {
msPtr->info.value = factor * scrollPtr->firstFraction;
} else {
info.value = info.max - factor * scrollPtr->firstFraction;
msPtr->info.value = msPtr->info.max - factor * scrollPtr->firstFraction;
}
} else {
info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction;
msPtr->info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction;
}
if((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0)
|| height <= metrics[variant].minHeight) {
info.enableState = kThemeTrackHideTrack;
|| height <= metrics.minHeight) {
msPtr->info.enableState = kThemeTrackHideTrack;
} else {
info.enableState = kThemeTrackActive;
info.attributes = kThemeTrackShowThumb | kThemeTrackThumbRgnIsNotGhost;
msPtr->info.enableState = kThemeTrackActive;
msPtr->info.attributes = kThemeTrackShowThumb | kThemeTrackThumbRgnIsNotGhost;
}
}
@@ -521,29 +548,79 @@ UpdateControlValues(
/*
*--------------------------------------------------------------
*
* ScrollbarPress --
* ScrollbarEvent --
*
* This procedure is invoked in response to <ButtonPress>, <ButtonRelease>,
* <EnterNotify>, and <LeaveNotify> events. Scrollbar appearance is modified.
* <EnterNotify>, and <LeaveNotify> events. The Scrollbar appearance is
* modified for each event.
*
*--------------------------------------------------------------
*/
static int
ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr)
ScrollbarEvent(TkScrollbar *scrollPtr, XEvent *eventPtr)
{
MacScrollbar *msPtr = (MacScrollbar *)scrollPtr;
/* The pressState does not indicate whether the moused button was
* pressed at some location in the Scrollbar. Rather, it indicates
* that the scrollbar should appear as if it were pressed in that
* location. The standard Mac behavior is that once the button is
* pressed inside the Scrollbar the appearance should not change until
* the button is released, even if the mouse moves outside of the
* scrollbar. However, if the mouse lies over the scrollbar but the
* button is not pressed then the appearance should be the same as if
* the button had been pressed on the slider, i.e. kThemeThumbPressed.
* See the file Appearance.r, or HIToolbox.bridgesupport on 10.14.
*/
if (eventPtr->type == ButtonPress) {
UpdateControlValues(scrollPtr);
info.trackInfo.scrollbar.pressState = 1;
}
if (eventPtr->type == EnterNotify) {
info.trackInfo.scrollbar.pressState = 1;
}
if (eventPtr->type == ButtonRelease || eventPtr->type == LeaveNotify) {
info.trackInfo.scrollbar.pressState = 0;
}
return TCL_OK;
if (eventPtr->type == ButtonPress) {
msPtr->buttonDown = true;
UpdateControlValues(scrollPtr);
int where = TkpScrollbarPosition(scrollPtr,
eventPtr->xbutton.x,
eventPtr->xbutton.y);
switch(where) {
case OUTSIDE:
msPtr->info.trackInfo.scrollbar.pressState = 0;
break;
case TOP_GAP:
msPtr->info.trackInfo.scrollbar.pressState = kThemeTopTrackPressed;
break;
case SLIDER:
msPtr->info.trackInfo.scrollbar.pressState = kThemeThumbPressed;
break;
case BOTTOM_GAP:
msPtr->info.trackInfo.scrollbar.pressState = kThemeBottomTrackPressed;
break;
case TOP_ARROW:
/* This looks wrong and the docs say it is wrong but it works. */
msPtr->info.trackInfo.scrollbar.pressState = kThemeTopInsideArrowPressed;
break;
case BOTTOM_ARROW:
msPtr->info.trackInfo.scrollbar.pressState = kThemeBottomOutsideArrowPressed;
break;
}
}
if (eventPtr->type == ButtonRelease) {
msPtr->buttonDown = false;
if (!msPtr->mouseOver) {
msPtr->info.trackInfo.scrollbar.pressState = 0;
}
}
if (eventPtr->type == EnterNotify) {
msPtr->mouseOver = true;
if (!msPtr->buttonDown) {
msPtr->info.trackInfo.scrollbar.pressState = kThemeThumbPressed;
}
}
if (eventPtr->type == LeaveNotify) {
msPtr->mouseOver = false;
if (!msPtr->buttonDown) {
msPtr->info.trackInfo.scrollbar.pressState = 0;
}
}
return TCL_OK;
}
@@ -585,9 +662,18 @@ ScrollbarEventProc(
case ButtonRelease:
case EnterNotify:
case LeaveNotify:
ScrollbarPress(clientData, eventPtr);
ScrollbarEvent(clientData, eventPtr);
break;
default:
TkScrollbarEventProc(clientData, eventPtr);
}
}
/*
* Local Variables:
* mode: objc
* c-basic-offset: 4
* fill-column: 79
* coding: utf-8
* End:
*/

View File

@@ -205,6 +205,13 @@ XMapWindow(
event.xvisibility.type = VisibilityNotify;
event.xvisibility.state = VisibilityUnobscured;
NotifyVisibility(macWin->winPtr, &event);
/*
* Make sure that subwindows get displayed.
*/
GenerateConfigureNotify(macWin->winPtr, 1);
}
/*
@@ -295,10 +302,12 @@ XUnmapWindow(
event.xunmap.from_configure = false;
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
} else {
/*
* Rebuild the visRgn clip region for the parent so it will be allowed
* to draw in the space from which this subwindow was removed.
*/
if (parentPtr && parentPtr->privatePtr->visRgn) {
TkMacOSXInvalidateViewRegion(TkMacOSXDrawableView(parentPtr->privatePtr),
parentPtr->privatePtr->visRgn);
@@ -380,10 +389,12 @@ XMoveResizeWindow(
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
if (w) {
/* We explicitly convert everything to doubles so we don't get
* surprised (again) by what happens when you do arithmetic with
* unsigned ints.
*/
CGFloat X = (CGFloat)x;
CGFloat Y = (CGFloat)y;
CGFloat Width = (CGFloat)width;
@@ -470,6 +481,7 @@ MoveResizeWindow(
if (contWinPtr) {
macParent = contWinPtr->privatePtr;
} else {
/*
* Here we should handle out of process embedding. At this point,
* we are assuming that the changes.x,y is not maintained, if you
@@ -478,6 +490,7 @@ MoveResizeWindow(
*/
}
} else {
/*
* TODO: update all xOff & yOffs
*/
@@ -569,6 +582,7 @@ XRaiseWindow(
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
TkWmRestackToplevel(macWin->winPtr, Above, NULL);
} else {
/*
* TODO: this should generate damage
*/
@@ -603,7 +617,8 @@ XLowerWindow(
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
TkWmRestackToplevel(macWin->winPtr, Below, NULL);
} else {
/*
/*
* TODO: this should generate damage
*/
}
@@ -874,6 +889,7 @@ TkMacOSXUpdateClipRgn(
}
CFRelease(rgn);
} else {
/*
* An unmapped window has empty clip regions to prevent any
* (erroneous) drawing into it or its children from becoming
@@ -1134,6 +1150,7 @@ void *
TkMacOSXGetRootControl(
Drawable drawable)
{
/*
* will probably need to fix this up for embedding
*/
@@ -1314,6 +1331,7 @@ UpdateOffsets(
TkWindow *childPtr;
if (winPtr->privatePtr == NULL) {
/*
* We haven't called Tk_MakeWindowExist for this window yet. The offset
* information will be postponed and calulated at that time. (This will

View File

@@ -79,6 +79,35 @@ DebuggerObjCmd(
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TkTestSimulateDrawing --
*
* A test widget display procedure which records calls can use this to
* avoid duplicate calls which would occur due to fact that no valid
* graphics context is available to the idle task which is running the
* display proc. Note that no actual drawing to the screen will take
* place when this flag is set. This is just a wrapper for the NSApp
* property.
*
*
* Results:
* Calls to low level drawing routines will return without actually
* drawing anything to the screen.
*
* Side effects:
* None
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE void
TkTestSimulateDrawing(Bool yesno) {
[NSApp setSimulateDrawing:yesno];
}
/*
* Local Variables:
* mode: objc

View File

@@ -68,11 +68,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
BOOL movedOnly = [[notification name]
isEqualToString:NSWindowDidMoveNotification];
if (movedOnly) {
/* constraining to screen after move not needed with AppKit */
}
isEqualToString:NSWindowDidMoveNotification];
NSWindow *w = [notification object];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
@@ -96,6 +92,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
flags |= TK_SIZE_CHANGED;
}
if (Tcl_GetServiceMode() != TCL_SERVICE_NONE) {
/*
* Propagate geometry changes immediately.
*/
@@ -119,6 +116,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
TkMacOSXIsWindowZoomed(winPtr) ? ZoomState : NormalState;
Tk_MapWindow((Tk_Window) winPtr);
if (Tcl_GetServiceMode() != TCL_SERVICE_NONE) {
/*
* Process all Tk events generated by Tk_MapWindow().
*/
@@ -174,6 +172,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
return (winPtr ? NO : YES);
}
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
- (void) windowDragStart: (NSNotification *) notification
@@ -213,6 +212,8 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
//Tk_UnmapWindow((Tk_Window) winPtr);
}
}
#endif /* TK_MAC_DEBUG_NOTIFICATIONS */
- (void) _setupWindowNotifications
@@ -236,6 +237,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
observe(NSWindowDidOrderOffScreenNotification, windowUnmapped:);
#endif
#undef observe
}
@end
@@ -256,7 +258,6 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
TkSuspendClipboard();
}
- (void) applicationShowHide: (NSNotification *) notification
@@ -292,6 +293,31 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
@end
#pragma mark -
/*
*----------------------------------------------------------------------
*
* TkpAppIsDrawing --
*
* A widget display procedure can call this to determine whether it
* is being run inside of the drawRect method. This is needed for
* some tests, especially of the Text widget, which record data in
* a global Tcl variable and assume that display procedures will be
* run in a predictable sequence as Tcl idle tasks.
*
* Results:
* True only while running the drawRect method of a TKContentView;
*
* Side effects:
* None
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE Bool
TkpAppIsDrawing(void) {
return [NSApp isDrawing];
}
/*
*----------------------------------------------------------------------
@@ -299,7 +325,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
* GenerateUpdates --
*
* Given a Macintosh update region and a Tk window this function geneates
* a X Expose event for the window if it is within the update region. The
* an X Expose event for the window if it meets the update region. The
* function will then recursivly have each damaged window generate Expose
* events for its child windows.
*
@@ -360,7 +386,7 @@ GenerateUpdates(
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
#ifdef TK_MAC_DEBUG_DRAWING
NSLog(@"Expose %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x,
TKLog(@"Expose %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x,
event.xexpose.y, event.xexpose.width, event.xexpose.height);
#endif
@@ -579,10 +605,12 @@ TkGenWMConfigureEvent(
if ((flags & TK_SIZE_CHANGED) && !(wmPtr->flags & WM_SYNC_PENDING) &&
((width != Tk_Width(tkwin)) || (height != Tk_Height(tkwin)))) {
if ((wmPtr->width == -1) && (width == winPtr->reqWidth)) {
/*
* Don't set external width, since the user didn't change it
* from what the widgets asked for.
*/
} else if (wmPtr->gridWin != NULL) {
wmPtr->width = wmPtr->reqGridWidth
+ (width - winPtr->reqWidth)/wmPtr->widthInc;
@@ -594,10 +622,12 @@ TkGenWMConfigureEvent(
}
if ((wmPtr->height == -1) && (height == winPtr->reqHeight)) {
/*
* Don't set external height, since the user didn't change it
* from what the widgets asked for.
*/
} else if (wmPtr->gridWin != NULL) {
wmPtr->height = wmPtr->reqGridHeight
+ (height - winPtr->reqHeight)/wmPtr->heightInc;
@@ -796,131 +826,216 @@ ConfigureRestrictProc(
const NSRect *rectsBeingDrawn;
NSInteger rectsBeingDrawnCount;
[self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount];
#ifdef TK_MAC_DEBUG_DRAWING
TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, NSStringFromRect(rect));
[[NSColor colorWithDeviceRed:0.0 green:1.0 blue:0.0 alpha:.1] setFill];
NSRectFillListUsingOperation(rectsBeingDrawn, rectsBeingDrawnCount,
NSCompositeSourceOver);
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
if (winPtr) fprintf(stderr, "drawRect: drawing %s\n",
Tk_PathName(winPtr));
#endif
if ([NSApp simulateDrawing]) {
return;
}
/*
* We do not allow recursive calls to drawRect, but we only log
* them on OSX > 10.13, where they should never happen.
*/
if ([NSApp isDrawing] && [NSApp macMinorVersion] > 13) {
TKLog(@"WARNING: a recursive call to drawRect was aborted.");
return;
}
[NSApp setIsDrawing: YES];
[self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount];
CGFloat height = [self bounds].size.height;
HIMutableShapeRef drawShape = HIShapeCreateMutable();
while (rectsBeingDrawnCount--) {
CGRect r = NSRectToCGRect(*rectsBeingDrawn++);
#ifdef TK_MAC_DEBUG_DRAWING
fprintf(stderr, "drawRect: %dx%d@(%d,%d)\n", (int)r.size.width,
(int)r.size.height, (int)r.origin.x, (int)r.origin.y);
#endif
r.origin.y = height - (r.origin.y + r.size.height);
HIShapeUnionWithRect(drawShape, &r);
}
if (CFRunLoopGetMain() == CFRunLoopGetCurrent()) {
[self generateExposeEvents:(HIShapeRef)drawShape];
} else {
[self performSelectorOnMainThread:@selector(generateExposeEvents:)
withObject:(id)drawShape waitUntilDone:NO
modes:[NSArray arrayWithObjects:NSRunLoopCommonModes,
NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode,
nil]];
}
[self generateExposeEvents:(HIShapeRef)drawShape];
CFRelease(drawShape);
[NSApp setIsDrawing: NO];
#ifdef TK_MAC_DEBUG_DRAWING
fprintf(stderr, "drawRect: done.\n");
#endif
}
-(void) setFrameSize: (NSSize)newsize
{
[super setFrameSize: newsize];
if ([self inLiveResize]) {
NSWindow *w = [self window];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
Tk_Window tkwin = (Tk_Window) winPtr;
NSWindow *w = [self window];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
Tk_Window tkwin = (Tk_Window) winPtr;
if (winPtr) {
/* On OSX versions below 10.14 setFrame calls drawRect.
* On 10.14 it does its own drawing.
*/
if ([NSApp macMinorVersion] > 13) {
[NSApp setIsDrawing:YES];
}
unsigned int width = (unsigned int)newsize.width;
unsigned int height=(unsigned int)newsize.height;
ClientData oldArg;
Tk_RestrictProc *oldProc;
/* This can be called from outside the Tk event loop.
/*
* This can be called from outside the Tk event loop.
* Since it calls Tcl_DoOneEvent, we need to make sure we
* don't clobber the AutoreleasePool set up by the caller.
*/
[NSApp _lockAutoreleasePool];
/*
* Try to prevent flickers and flashes.
* Disable Tk drawing until the window has been completely configured.
*/
[w disableFlushWindow];
NSDisableScreenUpdates();
/* Disable Tk drawing until the window has been completely configured.*/
TkMacOSXSetDrawingEnabled(winPtr, 0);
/* Generate and handle a ConfigureNotify event for the new size.*/
/*
* Generate and handle a ConfigureNotify event for the new size.
*/
TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height,
TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY);
oldProc = Tk_RestrictEvents(ConfigureRestrictProc, NULL, &oldArg);
while (Tk_DoOneEvent(TK_X_EVENTS|TK_DONT_WAIT)) {}
Tk_RestrictEvents(oldProc, oldArg, &oldArg);
/* Now that Tk has configured all subwindows we can create the clip regions. */
/*
* Now that Tk has configured all subwindows, create the clip regions.
*/
TkMacOSXSetDrawingEnabled(winPtr, 1);
TkMacOSXInvalClipRgns(tkwin);
TkMacOSXUpdateClipRgn(winPtr);
/* Finally, generate and process expose events to redraw the window. */
/*
* Generate and process expose events to redraw the window.
*/
HIRect bounds = NSRectToCGRect([self bounds]);
HIShapeRef shape = HIShapeCreateWithRect(&bounds);
[self generateExposeEvents: shape];
while (Tk_DoOneEvent(TK_ALL_EVENTS|TK_DONT_WAIT)) {}
[w enableFlushWindow];
[w flushWindowIfNeeded];
NSEnableScreenUpdates();
[w displayIfNeeded];
/*
* Finally, unlock the main autoreleasePool.
*/
[NSApp _unlockAutoreleasePool];
}
}
/*
* As insurance against bugs that might cause layout glitches during a live
* resize, we redraw the window one more time at the end of the resize
* operation.
* Core method of this class: generates expose events for redrawing. The
* expose events are immediately removed from the Tcl event loop and processed.
* This causes drawing procedures to be scheduled as idle events. Then all
* pending idle events are processed so the drawing will actually take place.
*/
- (void)viewDidEndLiveResize
{
HIRect bounds = NSRectToCGRect([self bounds]);
HIShapeRef shape = HIShapeCreateWithRect(&bounds);
[super viewDidEndLiveResize];
[self generateExposeEvents: shape];
}
/* Core method of this class: generates expose events for redrawing. If the
* Tcl_ServiceMode is set to TCL_SERVICE_ALL then the expose events will be
* immediately removed from the Tcl event loop and processed. Typically, they
* should be queued, however.
*/
- (void) generateExposeEvents: (HIShapeRef) shape
{
unsigned long serial;
CGRect updateBounds;
int updatesNeeded;
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
ClientData oldArg;
Tk_RestrictProc *oldProc;
if (!winPtr) {
return;
return;
}
/* Generate Tk Expose events. */
/*
* Generate Tk Expose events.
*/
HIShapeGetBounds(shape, &updateBounds);
/* All of these events will share the same serial number. */
/*
* All of these events will share the same serial number.
*/
serial = LastKnownRequestProcessed(Tk_Display(winPtr));
updatesNeeded = GenerateUpdates(shape, &updateBounds, winPtr);
/* Process the Expose events if the service mode is TCL_SERVICE_ALL */
if (updatesNeeded && Tcl_GetServiceMode() == TCL_SERVICE_ALL) {
ClientData oldArg;
Tk_RestrictProc *oldProc = Tk_RestrictEvents(ExposeRestrictProc,
UINT2PTR(serial), &oldArg);
while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {}
if (updatesNeeded) {
/*
* First process all of the Expose events.
*/
oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg);
while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {};
Tk_RestrictEvents(oldProc, oldArg, &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 we can do the drawing by processing all of the idle events that
* were created when the expose events were processed.
*/
while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
}
}
/*
* This method is called when a user changes between light and dark mode.
* The implementation here generates a Tk virtual event which can be bound
* to a function that redraws the window in an appropriate style.
*/
- (void) viewDidChangeEffectiveAppearance
{
XVirtualEvent event;
int x, y;
NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
NSWindow *w = [self window];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
Tk_Window tkwin = (Tk_Window) winPtr;
if (!winPtr) {
return;
}
bzero(&event, sizeof(XVirtualEvent));
event.type = VirtualEvent;
event.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
event.send_event = false;
event.display = Tk_Display(tkwin);
event.event = Tk_WindowId(tkwin);
event.root = XRootWindow(Tk_Display(tkwin), 0);
event.subwindow = None;
event.time = TkpGetMS();
XQueryPointer(NULL, winPtr->window, NULL, NULL,
&event.x_root, &event.y_root, &x, &y, &event.state);
Tk_TopCoordsToWindow(tkwin, x, y, &event.x, &event.y);
event.same_screen = true;
if (osxMode == nil) {
event.name = Tk_GetUid("LightAqua");
Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
return;
}
if ([osxMode isEqual:@"Dark"]) {
event.name = Tk_GetUid("DarkAqua");
Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
return;
}
}
@@ -928,6 +1043,7 @@ ConfigureRestrictProc(
* This is no-op on 10.7 and up because Apple has removed this widget,
* but we are leaving it here for backwards compatibility.
*/
- (void) tkToolbarButton: (id) sender
{
#ifdef TK_MAC_DEBUG_EVENTS
@@ -937,6 +1053,9 @@ ConfigureRestrictProc(
int x, y;
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
Tk_Window tkwin = (Tk_Window) winPtr;
if (!winPtr){
return;
}
bzero(&event, sizeof(XVirtualEvent));
event.type = VirtualEvent;
event.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
@@ -957,7 +1076,6 @@ ConfigureRestrictProc(
- (BOOL) isOpaque
{
NSWindow *w = [self window];
return (w && (([w styleMask] & NSTexturedBackgroundWindowMask) ||
![w isOpaque]) ? NO : YES);
}

View File

@@ -204,16 +204,16 @@ static int windowHashInit = false;
@implementation NSWindow(TKWm)
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
- (NSPoint) convertPointToScreen: (NSPoint) point
- (NSPoint) tkConvertPointToScreen: (NSPoint) point
{
return [self convertBaseToScreen:point];
}
- (NSPoint) convertPointFromScreen: (NSPoint)point
- (NSPoint) tkConvertPointFromScreen: (NSPoint)point
{
return [self convertScreenToBase:point];
}
#else
- (NSPoint) convertPointToScreen: (NSPoint) point
- (NSPoint) tkConvertPointToScreen: (NSPoint) point
{
NSRect pointrect;
pointrect.origin = point;
@@ -221,7 +221,7 @@ static int windowHashInit = false;
pointrect.size.height = 0;
return [self convertRectToScreen:pointrect].origin;
}
- (NSPoint) convertPointFromScreen: (NSPoint)point
- (NSPoint) tkConvertPointFromScreen: (NSPoint)point
{
NSRect pointrect;
pointrect.origin = point;
@@ -231,6 +231,21 @@ static int windowHashInit = false;
}
#endif
- (NSSize)windowWillResize:(NSWindow *)sender
toSize:(NSSize)frameSize
{
NSRect currentFrame = [sender frame];
TkWindow *winPtr = TkMacOSXGetTkWindow(sender);
if (winPtr) {
if (winPtr->wmInfoPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
frameSize.width = currentFrame.size.width;
}
if (winPtr->wmInfoPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
frameSize.height = currentFrame.size.height;
}
}
return frameSize;
}
@end
#pragma mark -
@@ -372,20 +387,48 @@ static void RemapWindows(TkWindow *winPtr,
@implementation TKWindow: NSWindow
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_12
/*
* Override automatic fullscreen button on >10.12 because system fullscreen API
* confuses Tk window geometry.
*/
/* Custom fullscreen implementation on 10.13 and above. On older versions of
* macOS dating back to 10.7, the NSWindow fullscreen API was opt-in, requiring
* explicit calls to toggleFullScreen. On 10.13, the API became implicit,
* applying to all NSWindows unless they were marked non-resizable; this caused
* issues with Tk, which was not aware of changes in screen geometry. Here we
* override the toggleFullScreen call to hook directly into Tk's own fullscreen
* API, allowing Tk to function smoothly with the Mac's fullscreen button.
*/
NSStatusItem *exitFullScreen;
- (void)toggleFullScreen:(id)sender
{
if ([self isZoomed]) {
TkMacOSXZoomToplevel(self, inZoomIn);
} else {
TkMacOSXZoomToplevel(self, inZoomOut);
}
TkWindow *winPtr = TkMacOSXGetTkWindow(self);
if (!winPtr) {
return;
}
Tcl_Interp *interp = Tk_Interp((Tk_Window)winPtr);
if ([NSApp macMinorVersion] > 12) {
if (([self styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask) {
TkMacOSXMakeFullscreen(winPtr, self, 0, interp);
} else {
TkMacOSXMakeFullscreen(winPtr, self, 1, interp);
}
} else {
TKLog (@"toggleFullScreen is ignored by Tk on OSX versions < 10.13");
}
}
#endif
-(void)restoreOldScreen:(id)sender
{
TkWindow *winPtr = TkMacOSXGetTkWindow(self);
if (!winPtr) {
return;
}
Tcl_Interp *interp = Tk_Interp((Tk_Window)winPtr);
TkMacOSXMakeFullscreen(winPtr, self, 0, interp);
[[NSStatusBar systemStatusBar] removeStatusItem: exitFullScreen];
}
@end
@implementation TKWindow(TKWm)
@@ -393,14 +436,15 @@ static void RemapWindows(TkWindow *winPtr,
- (BOOL) canBecomeKeyWindow
{
TkWindow *winPtr = TkMacOSXGetTkWindow(self);
return (winPtr && winPtr->wmInfoPtr && (winPtr->wmInfoPtr->macClass ==
kHelpWindowClass || winPtr->wmInfoPtr->attributes &
kWindowNoActivatesAttribute)) ? NO : YES;
if (!winPtr) {
return NO;
}
return (winPtr->wmInfoPtr &&
(winPtr->wmInfoPtr->macClass == kHelpWindowClass ||
winPtr->wmInfoPtr->attributes & kWindowNoActivatesAttribute)
) ? NO : YES;
}
#if DEBUG_ZOMBIES
- (id) retain
{
@@ -410,7 +454,8 @@ static void RemapWindows(TkWindow *winPtr,
title = "unnamed window";
}
if (DEBUG_ZOMBIES > 1){
printf("Retained <%s>. Count is: %lu\n", title, [self retainCount]);
fprintf(stderr, "Retained <%s>. Count is: %lu\n",
title, [self retainCount]);
}
return result;
}
@@ -423,7 +468,8 @@ static void RemapWindows(TkWindow *winPtr,
title = "unnamed window";
}
if (DEBUG_ZOMBIES > 1){
printf("Autoreleased <%s>. Count is %lu\n", title, [self retainCount]);
fprintf(stderr, "Autoreleased <%s>. Count is %lu\n",
title, [self retainCount]);
}
return result;
}
@@ -434,7 +480,8 @@ static void RemapWindows(TkWindow *winPtr,
title = "unnamed window";
}
if (DEBUG_ZOMBIES > 1){
printf("Releasing <%s>. Count is %lu\n", title, [self retainCount]);
fprintf(stderr, "Releasing <%s>. Count is %lu\n",
title, [self retainCount]);
}
[super release];
}
@@ -445,7 +492,8 @@ static void RemapWindows(TkWindow *winPtr,
title = "unnamed window";
}
if (DEBUG_ZOMBIES > 0){
printf(">>>> Freeing <%s>. Count is %lu\n", title, [self retainCount]);
fprintf(stderr, ">>>> Freeing <%s>. Count is %lu\n",
title, [self retainCount]);
}
[super dealloc];
}
@@ -566,15 +614,15 @@ FrontWindowAtPoint(
{
NSPoint p = NSMakePoint(x, tkMacOSXZeroScreenHeight - y);
NSArray *windows = [NSApp orderedWindows];
TkWindow *front = NULL;
TkWindow *winPtr = NULL;
for (NSWindow *w in windows) {
if (w && NSMouseInRect(p, [w frame], NO)) {
front = TkMacOSXGetTkWindow(w);
break;
}
winPtr = TkMacOSXGetTkWindow(w);
if (winPtr && NSMouseInRect(p, [w frame], NO)) {
break;
}
return front;
}
return winPtr;
}
/*
@@ -702,7 +750,6 @@ TkWmMapWindow(
* mapped. */
{
WmInfo *wmPtr = winPtr->wmInfoPtr;
if (wmPtr->flags & WM_NEVER_MAPPED) {
/*
* Create the underlying Mac window for this Tk window.
@@ -774,7 +821,6 @@ TkWmMapWindow(
/*Add window to Window menu.*/
NSWindow *win = TkMacOSXDrawableWindow(winPtr->window);
[win setExcludedFromWindowsMenu:NO];
}
/*
@@ -3430,7 +3476,15 @@ WmTransientCmd(
if (TkGetWindowFromObj(interp, tkwin, objv[3], &master) != TCL_OK) {
return TCL_ERROR;
}
Tk_MakeWindowExist(master);
TkWindow* masterPtr = (TkWindow*) master;
while (!Tk_TopWinHierarchy(masterPtr)) {
/*
* Ensure that the master window is actually a Tk toplevel.
*/
masterPtr = masterPtr->parentPtr;
}
Tk_MakeWindowExist((Tk_Window)masterPtr);
if (wmPtr->iconFor != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
@@ -3440,8 +3494,7 @@ WmTransientCmd(
return TCL_ERROR;
}
wmPtr2 = ((TkWindow *) master)->wmInfoPtr;
wmPtr2 = masterPtr->wmInfoPtr;
/* Under some circumstances, wmPtr2 is NULL here */
if (wmPtr2 != NULL && wmPtr2->iconFor != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
@@ -3451,15 +3504,16 @@ WmTransientCmd(
return TCL_ERROR;
}
if ((TkWindow *) master == winPtr) {
if (masterPtr == winPtr) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"can't make \"%s\" its own master", Tk_PathName(winPtr)));
Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "SELF", NULL);
return TCL_ERROR;
}
wmPtr->master = Tk_WindowId(master);
masterWindowName = Tcl_GetStringFromObj(objv[3], &length);
wmPtr->master = Tk_WindowId(masterPtr);
masterWindowName = masterPtr->pathName;
length = strlen(masterWindowName);
if (wmPtr->masterWindowName != NULL) {
ckfree(wmPtr->masterWindowName);
}
@@ -4251,15 +4305,7 @@ Tk_GetRootCoords(
*/
winPtr = otherPtr;
/*
* Remember to offset by the container window here, since at the
* end of this if branch, we will pop out to the container's
* parent...
*/
x += winPtr->changes.x + winPtr->changes.border_width;
y += winPtr->changes.y + winPtr->changes.border_width;
continue;
}
winPtr = winPtr->parentPtr;
}
@@ -5612,20 +5658,18 @@ TkMacOSXMakeRealWindowExist(
}
TKContentView *contentView = [[TKContentView alloc]
initWithFrame:NSZeroRect];
[window setColorSpace:[NSColorSpace deviceRGBColorSpace]];
[window setContentView:contentView];
[contentView release];
[window setDelegate:NSApp];
[window setAcceptsMouseMovedEvents:YES];
[window setReleasedWhenClosed:NO];
[window setAutodisplay:NO];
if (styleMask & NSUtilityWindowMask) {
[(NSPanel*)window setFloatingPanel:YES];
}
if ((styleMask & (NSTexturedBackgroundWindowMask|NSHUDWindowMask)) &&
!(styleMask & NSDocModalWindowMask)) {
/*
* Workaround for [Bug 2824538]: Texured windows are draggable
* Workaround for [Bug 2824538]: Textured windows are draggable
* from opaque content.
*/
[window setMovableByWindowBackground:NO];
@@ -5641,11 +5685,38 @@ TkMacOSXMakeRealWindowExist(
geometry.size.height += structureRect.size.height;
geometry.origin.y = tkMacOSXZeroScreenHeight - (geometry.origin.y +
geometry.size.height);
[window setFrame:geometry display:NO];
[window setFrame:geometry display:YES];
TkMacOSXRegisterOffScreenWindow((Window) macWin, window);
macWin->flags |= TK_HOST_EXISTS;
}
/*
*----------------------------------------------------------------------
*
* TkpDisplayWindow --
*
* Mark the contentView of this window as needing display so the
* window will be drawn by the window manager. If this is called
* within the drawRect method, do nothing.
*
* Results:
* None.
*
* Side effects:
* The window's contentView is marked as needing display.
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE void
TkpDisplayWindow(Tk_Window tkwin) {
if (![NSApp isDrawing]) {
TkWindow *winPtr = (TkWindow*)tkwin;
NSWindow *w = TkMacOSXDrawableWindow(winPtr->window);
[[w contentView] setNeedsDisplay: YES];
}
}
/*
*----------------------------------------------------------------------
*
@@ -6268,12 +6339,15 @@ ApplyWindowAttributeFlagChanges(
[[macWindow standardWindowButton:NSWindowZoomButton]
setEnabled:(newAttributes & kWindowResizableAttribute) &&
(newAttributes & kWindowFullZoomAttribute)];
if (newAttributes & kWindowResizableAttribute) {
wmPtr->flags &= ~(WM_WIDTH_NOT_RESIZABLE |
WM_HEIGHT_NOT_RESIZABLE);
if (newAttributes & kWindowHorizontalZoomAttribute) {
wmPtr->flags &= ~(WM_WIDTH_NOT_RESIZABLE);
} else {
wmPtr->flags |= (WM_WIDTH_NOT_RESIZABLE |
WM_HEIGHT_NOT_RESIZABLE);
wmPtr->flags |= (WM_WIDTH_NOT_RESIZABLE);
}
if (newAttributes & kWindowVerticalZoomAttribute) {
wmPtr->flags &= ~(WM_HEIGHT_NOT_RESIZABLE);
} else {
wmPtr->flags |= (WM_HEIGHT_NOT_RESIZABLE);
}
WmUpdateGeom(wmPtr, winPtr);
}
@@ -6457,12 +6531,10 @@ TkMacOSXMakeFullscreen(
Tcl_Interp *interp)
{
WmInfo *wmPtr = winPtr->wmInfoPtr;
int result = TCL_OK, wasFullscreen = (wmPtr->flags & WM_FULLSCREEN);
static unsigned long prevMask = 0, prevPres = 0;
int screenWidth = WidthOfScreen(Tk_Screen(winPtr));
int screenHeight = HeightOfScreen(Tk_Screen(winPtr));
if (fullscreen) {
int screenWidth = WidthOfScreen(Tk_Screen(winPtr));
int screenHeight = HeightOfScreen(Tk_Screen(winPtr));
/*
* Check max width and height if set by the user.
@@ -6477,58 +6549,73 @@ TkMacOSXMakeFullscreen(
Tcl_SetErrorCode(interp, "TK", "FULLSCREEN",
"CONSTRAINT_FAILURE", NULL);
}
result = TCL_ERROR;
wmPtr->flags &= ~WM_FULLSCREEN;
} else {
Tk_UnmapWindow((Tk_Window) winPtr);
NSRect bounds = [window contentRectForFrameRect:[window frame]];
NSRect screenBounds = NSMakeRect(0, 0, screenWidth, screenHeight);
if (!NSEqualRects(bounds, screenBounds) && !wasFullscreen) {
wmPtr->configX = wmPtr->x;
wmPtr->configY = wmPtr->y;
wmPtr->configAttributes = wmPtr->attributes;
wmPtr->attributes &= ~kWindowResizableAttribute;
ApplyWindowAttributeFlagChanges(winPtr, window,
wmPtr->configAttributes, wmPtr->flags, 1, 0);
wmPtr->flags |= WM_SYNC_PENDING;
[window setFrame:[window frameRectForContentRect:
screenBounds] display:YES];
wmPtr->flags &= ~WM_SYNC_PENDING;
}
wmPtr->flags |= WM_FULLSCREEN;
return TCL_ERROR;
}
prevMask = [window styleMask];
prevPres = [NSApp presentationOptions];
[window setStyleMask: NSBorderlessWindowMask];
[NSApp setPresentationOptions: NSApplicationPresentationAutoHideDock
| NSApplicationPresentationAutoHideMenuBar];
Tk_MapWindow((Tk_Window) winPtr);
/*
* Save the current window state.
*/
wmPtr->cachedBounds = [window frame];
wmPtr->cachedStyle = [window styleMask];
wmPtr->cachedPresentation = [NSApp presentationOptions];
/*
* Adjust the window style so it looks like a Fullscreen window.
*/
[window setStyleMask: NSFullScreenWindowMask];
[NSApp setPresentationOptions: (NSApplicationPresentationAutoHideDock |
NSApplicationPresentationAutoHideMenuBar)];
/*For 10.13 and later add a button for exiting Fullscreen.*/
if ([NSApp macMinorVersion] > 12) {
#if MAC_OS_X_VERSION_MAX_ALLOWED > 101200
exitFullScreen = [[[NSStatusBar systemStatusBar]
statusItemWithLength:NSVariableStatusItemLength] retain];
NSImage *exitIcon = [NSImage imageNamed:@"NSExitFullScreenTemplate"];
exitFullScreen.button.image = exitIcon;
exitFullScreen.button.cell.highlighted = NO;
exitFullScreen.button.toolTip = @"Exit Full Screen";
exitFullScreen.button.target = window;
exitFullScreen.button.action = @selector(restoreOldScreen:);
#endif
}
/*
* Resize the window to fill the screen. (After setting the style!)
*/
wmPtr->flags |= WM_SYNC_PENDING;
NSRect screenBounds = NSMakeRect(0, 0, screenWidth, screenHeight);
[window setFrame:screenBounds display:YES];
wmPtr->flags &= ~WM_SYNC_PENDING;
wmPtr->flags |= WM_FULLSCREEN;
} else {
wmPtr->flags &= ~WM_FULLSCREEN;
[NSApp setPresentationOptions: prevPres];
[window setStyleMask: prevMask];
}
if (wasFullscreen && !(wmPtr->flags & WM_FULLSCREEN)) {
Tk_UnmapWindow((Tk_Window) winPtr);
/*
* Restore the previous styles and attributes.
*/
[NSApp setPresentationOptions: wmPtr->cachedPresentation];
[window setStyleMask: wmPtr->cachedStyle];
UInt64 oldAttributes = wmPtr->attributes;
NSRect bounds = NSMakeRect(wmPtr->configX, tkMacOSXZeroScreenHeight -
(wmPtr->configY + wmPtr->yInParent + wmPtr->configHeight),
wmPtr->xInParent + wmPtr->configWidth,
wmPtr->yInParent + wmPtr->configHeight);
wmPtr->flags &= ~WM_FULLSCREEN;
wmPtr->attributes |= wmPtr->configAttributes &
kWindowResizableAttribute;
ApplyWindowAttributeFlagChanges(winPtr, window, oldAttributes,
wmPtr->flags, 1, 0);
/*
* Resize the window to its previous size.
*/
wmPtr->flags |= WM_SYNC_PENDING;
[window setFrame:[window frameRectForContentRect:bounds] display:YES];
[window setFrame:wmPtr->cachedBounds display:YES];
wmPtr->flags &= ~WM_SYNC_PENDING;
Tk_MapWindow((Tk_Window) winPtr);
}
return result;
return TCL_OK;
}
/*

View File

@@ -185,6 +185,15 @@ typedef struct TkWmInfo {
TkWindow *scrollWinPtr; /* Ptr to scrollbar handling grow widget. */
TkMenu *menuPtr;
NSWindow *window;
/*
* Space to cache current window state when window becomes Fullscreen.
*/
unsigned long cachedStyle;
unsigned long cachedPresentation;
NSRect cachedBounds;
} WmInfo;
/*

View File

@@ -3,7 +3,7 @@
*
* This file contains most of the X calls called by Tk. Many of these
* calls are just stubs and either don't make sense on the Macintosh or
* their implamentation just doesn't do anything. Other calls will
* their implementation just doesn't do anything. Other calls will
* eventually be moved into other files.
*
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
@@ -40,10 +40,13 @@ CGFloat tkMacOSXZeroScreenTop = 0;
* Declarations of static variables used in this file.
*/
/* The unique Macintosh display. */
static TkDisplay *gMacDisplay = NULL;
/* Macintosh display. */
/* The default name of the Macintosh display. */
static const char *macScreenName = ":0";
/* Default name of macintosh display. */
/* Timestamp showing the last reset of the inactivity timer. */
static Time lastInactivityReset = 0;
/*
* Forward declarations of procedures used in this file.
@@ -175,7 +178,7 @@ TkpOpenDisplay(
{
int major, minor, patch;
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
Gestalt(gestaltSystemVersionMajor, (SInt32*)&major);
Gestalt(gestaltSystemVersionMinor, (SInt32*)&minor);
Gestalt(gestaltSystemVersionBugFix, (SInt32*)&patch);
@@ -200,7 +203,6 @@ TkpOpenDisplay(
screen->root_visual = ckalloc(sizeof(Visual));
screen->root_visual->visualid = 0;
screen->root_visual->class = TrueColor;
screen->root_visual->alpha_mask = 0xFF000000;
screen->root_visual->red_mask = 0x00FF0000;
screen->root_visual->green_mask = 0x0000FF00;
screen->root_visual->blue_mask = 0x000000FF;
@@ -874,13 +876,10 @@ TkGetDefaultScreenName(
Tcl_Interp *interp, /* Not used. */
const char *screenName) /* If NULL, use default string. */
{
#if 0
if ((screenName == NULL) || (screenName[0] == '\0')) {
screenName = macScreenName;
}
return screenName;
#endif
return macScreenName;
}
/*
@@ -928,27 +927,23 @@ Tk_GetUserInactiveTime(
timeObj = CFDictionaryGetValue(props, CFSTR("HIDIdleTime"));
if (timeObj) {
CFTypeID type = CFGetTypeID(timeObj);
if (type == CFDataGetTypeID()) { /* Jaguar */
CFDataGetBytes((CFDataRef) timeObj,
CFRangeMake(0, sizeof(time)), (UInt8 *) &time);
/* Convert nanoseconds to milliseconds. */
/* ret /= kMillisecondScale; */
ret = (long) (time/kMillisecondScale);
} else if (type == CFNumberGetTypeID()) { /* Panther+ */
CFNumberGetValue((CFNumberRef)timeObj,
kCFNumberSInt64Type, &time);
/* Convert nanoseconds to milliseconds. */
/* ret /= kMillisecondScale; */
ret = (long) (time/kMillisecondScale);
} else {
ret = -1l;
}
}
/* Cleanup */
CFRelease(props);
/*
* If the idle time reported by the system is larger than the elapsed
* time since the last reset, return the elapsed time.
*/
long elapsed = (long)(TkpGetMS() - lastInactivityReset);
if (ret > elapsed) {
ret = elapsed;
}
return ret;
}
@@ -973,28 +968,7 @@ void
Tk_ResetUserInactiveTime(
Display *dpy)
{
IOGPoint loc = {0, 0};
kern_return_t kr;
NXEvent nullEvent = {NX_NULLEVENT, {0, 0}, 0, -1, 0};
enum { kNULLEventPostThrottle = 10 };
static io_connect_t io_connection = MACH_PORT_NULL;
if (io_connection == MACH_PORT_NULL) {
io_service_t service = IOServiceGetMatchingService(
kIOMasterPortDefault, IOServiceMatching(kIOHIDSystemClass));
if (service == MACH_PORT_NULL) {
return;
}
kr = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType,
&io_connection);
IOObjectRelease(service);
if (kr != KERN_SUCCESS) {
return;
}
}
kr = IOHIDPostEvent(io_connection, NX_NULLEVENT, loc, &nullEvent.data,
FALSE, 0, FALSE);
lastInactivityReset = TkpGetMS();
}
/*