summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--README2
-rw-r--r--changes22
-rw-r--r--doc/bind.n11
-rw-r--r--generic/tk.h4
-rw-r--r--generic/tkBind.c48
-rw-r--r--generic/tkBitmap.c2
-rw-r--r--generic/tkCanvUtil.c2
-rw-r--r--generic/tkEntry.c4
-rw-r--r--generic/tkEvent.c2
-rw-r--r--generic/tkFont.c11
-rw-r--r--generic/tkGrid.c4
-rw-r--r--generic/tkInt.decls3
-rw-r--r--generic/tkIntPlatDecls.h6
-rw-r--r--generic/tkStubInit.c1
-rw-r--r--generic/tkText.c53
-rw-r--r--generic/tkText.h3
-rw-r--r--generic/tkTextBTree.c19
-rw-r--r--generic/tkTextDisp.c581
-rw-r--r--generic/tkTextIndex.c91
-rw-r--r--generic/tkUndo.c2
-rw-r--r--generic/ttk/ttkGenStubs.tcl6
-rw-r--r--generic/ttk/ttkLabel.c2
-rw-r--r--library/button.tcl3
-rw-r--r--library/choosedir.tcl4
-rw-r--r--library/clrpick.tcl22
-rw-r--r--library/comdlg.tcl6
-rw-r--r--library/console.tcl8
-rw-r--r--library/dialog.tcl2
-rw-r--r--library/entry.tcl4
-rw-r--r--library/fontchooser.tcl2
-rw-r--r--library/mkpsenc.tcl6
-rw-r--r--library/msgbox.tcl6
-rw-r--r--library/palette.tcl10
-rw-r--r--library/scrlbar.tcl2
-rw-r--r--library/spinbox.tcl4
-rw-r--r--library/tearoff.tcl2
-rw-r--r--library/tk.tcl10
-rw-r--r--library/unsupported.tcl2
-rw-r--r--library/xmfbox.tcl28
-rw-r--r--macosx/GNUmakefile2
-rw-r--r--macosx/tkMacOSXButton.c1973
-rw-r--r--macosx/tkMacOSXDefault.h36
-rw-r--r--macosx/tkMacOSXDraw.c64
-rw-r--r--macosx/tkMacOSXEmbed.c48
-rw-r--r--macosx/tkMacOSXHLEvents.c9
-rw-r--r--macosx/tkMacOSXInit.c15
-rw-r--r--macosx/tkMacOSXKeyEvent.c8
-rw-r--r--macosx/tkMacOSXKeyboard.c3
-rw-r--r--macosx/tkMacOSXMenu.c4
-rw-r--r--macosx/tkMacOSXMenubutton.c993
-rw-r--r--macosx/tkMacOSXPort.h10
-rw-r--r--macosx/tkMacOSXPrivate.h3
-rw-r--r--macosx/tkMacOSXScrlbr.c799
-rw-r--r--macosx/tkMacOSXWindowEvent.c98
-rw-r--r--macosx/tkMacOSXWm.c5
-rw-r--r--macosx/ttkMacOSXTheme.c24
-rw-r--r--tests/bind.test43
-rw-r--r--tests/bugs.tcl2
-rw-r--r--tests/butGeom2.tcl2
-rw-r--r--tests/canvPsGrph.tcl6
-rw-r--r--tests/canvPsImg.tcl2
-rw-r--r--tests/canvText.test4
-rw-r--r--tests/constraints.tcl6
-rw-r--r--tests/text.test60
-rw-r--r--tests/textBTree.test16
-rw-r--r--tests/textDisp.test334
-rw-r--r--tests/textImage.test11
-rw-r--r--tests/ttk/spinbox.test2
-rw-r--r--tests/winDialog.test18
-rwxr-xr-xunix/configure14
-rw-r--r--unix/configure.in2
-rw-r--r--unix/tk.spec2
-rw-r--r--unix/tkConfig.h.in22
-rw-r--r--unix/tkUnixButton.c2
-rwxr-xr-xwin/configure2
-rw-r--r--win/configure.in2
-rw-r--r--win/tkWinDialog.c117
-rw-r--r--win/tkWinTest.c2
79 files changed, 3313 insertions, 2460 deletions
diff --git a/ChangeLog b/ChangeLog
index 7eb5433..94cabc1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -33,7 +33,7 @@ a better first place to look now.
* library/ttk/progress.tcl: Bug [c597acdab3]: Call [$pb step]
in tail position in ttk::progressbar::Autoincrement, so that
the widget is in a consistent state when any write traces on
- the linked -variable are fired.
+ the linked -variable are fired.
2013-08-14 Jan Nijtmans <nijtmans@users.sf.net>
@@ -156,6 +156,12 @@ a better first place to look now.
* generic/tkTextIndex.c: [Bug 3588824]: bug in image index handling
* tests/textIndex.test: for weird image names
+2012-11-16 Joe Mistachkin <joe@mistachkin.com>
+
+ * generic/tkBind.c: Add support for an 'M' binding substitution
+ that is replaced with the number of script-based binding patterns
+ matched so far for the event.
+
2012-11-14 Jan Nijtmans <nijtmans@users.sf.net>
* win/tkWinDialog.c: [Bug 3500545]: tk_getOpenFile -multiple 1 wrong
diff --git a/README b/README
index 04034fb..1470c04 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
README: Tk
- This is the Tk 8.6.3 source distribution.
+ This is the Tk 8.6.4 source distribution.
http://sourceforge.net/projects/tcl/files/Tcl/
You can get any source release of Tk from the URL above.
diff --git a/changes b/changes
index a6373fd..81be9f1 100644
--- a/changes
+++ b/changes
@@ -7145,3 +7145,25 @@ Many revisions to better support a Cygwin environment (nijtmans)
2014-11-07 (bug)[3529885] [scale] handling of negative resolution (vogel)
--- Released 8.6.3, November 12, 2014 --- http://core.tcl.tk/tk/ for details
+
+2014-11-14 (bug)[d43a10] shimmer-related crash in [tk_getOpenFile] (nadkarni)
+
+2014-11-23 (bug)[1c0d6e] Win build trouble with SIGDN (keene)
+
+2014-12-03 (bug)[4a0451] [tk_getOpenFile] result (nadkarni)
+
+2014-12-13 fix header files installation on OS X (houben)
+
+2015-01-02 (bug) Stop bit loss in [winfo id] on 64-bit Cocoa (porter)
+
+2015-02-06 (bug) several fixes to elided context in [text] (vogel)
+
+2015-02-06 (new feature)[TIP 433] %M binding substitution (mistachkin)
+ *** POTENTIAL INCOMPATIBILITY ***
+
+2015-02-22 (bug)[ab6dab] corrupt dashed lines in postscript (porter)
+
+Tk Cocoa 2.0: App Store enabled (walzer,culler,desmera,owen,nyberg,reincke)
+ *** POTENTIAL INCOMPATIBILITY ***
+
+--- Released 8.6.4, March 12, 2015 --- http://core.tcl.tk/tk/ for details
diff --git a/doc/bind.n b/doc/bind.n
index 17acb52..d189376 100644
--- a/doc/bind.n
+++ b/doc/bind.n
@@ -205,9 +205,7 @@ always routed to the window that currently has focus. When the event
is received you can use the \fB%D\fR substitution to get the
\fIdelta\fR field for the event, which is a integer value describing how
the mouse wheel has moved. The smallest value for which the
-system will report is defined by the OS. On Windows 95 & 98 machines
-this value is at least 120 before it is reported. However, higher
-resolution devices may be available in the future. The sign of the
+system will report is defined by the OS. The sign of the
value determines which direction your widget should scroll. Positive
values should scroll up and negative values should scroll down.
.IP "\fBKeyPress\fR, \fBKeyRelease\fR" 5
@@ -527,9 +525,7 @@ The \fIborder_width\fR field from the event. Valid only for
.IP \fB%D\fR 5
This reports the \fIdelta\fR value of a \fBMouseWheel\fR event. The
\fIdelta\fR value represents the rotation units the mouse wheel has
-been moved. On Windows 95 & 98 systems the smallest value for the
-delta is 120. Future systems may support higher resolution values for
-the delta. The sign of the value represents the direction the mouse
+been moved. The sign of the value represents the direction the mouse
wheel was scrolled.
.IP \fB%E\fR 5
The \fIsend_event\fR field from the event. Valid for all event types.
@@ -541,6 +537,9 @@ event generated by \fBSendEvent\fR.
.IP \fB%K\fR 5
The keysym corresponding to the event, substituted as a textual
string. Valid only for \fBKeyPress\fR and \fBKeyRelease\fR events.
+.IP \fB%M\fR 5
+The number of script-based binding patterns matched so far for the
+event. Valid for all event types.
.IP \fB%N\fR 5
The keysym corresponding to the event, substituted as a decimal
number. Valid only for \fBKeyPress\fR and \fBKeyRelease\fR events.
diff --git a/generic/tk.h b/generic/tk.h
index bd3c4f1..4a655a4 100644
--- a/generic/tk.h
+++ b/generic/tk.h
@@ -75,10 +75,10 @@ extern "C" {
#define TK_MAJOR_VERSION 8
#define TK_MINOR_VERSION 6
#define TK_RELEASE_LEVEL TCL_FINAL_RELEASE
-#define TK_RELEASE_SERIAL 3
+#define TK_RELEASE_SERIAL 4
#define TK_VERSION "8.6"
-#define TK_PATCH_LEVEL "8.6.3"
+#define TK_PATCH_LEVEL "8.6.4"
/*
* A special definition used to allow this header file to be included from
diff --git a/generic/tkBind.c b/generic/tkBind.c
index fbac56d..9cd3b7b 100644
--- a/generic/tkBind.c
+++ b/generic/tkBind.c
@@ -16,9 +16,9 @@
#ifdef _WIN32
#include "tkWinInt.h"
-#endif
-
-#if !(defined(_WIN32) || defined(MAC_OSX_TK)) /* UNIX */
+#elif defined(MAC_OSX_TK)
+#include "tkMacOSXInt.h"
+#else
#include "tkUnixInt.h"
#endif
@@ -167,7 +167,7 @@ typedef struct {
* button (0 means any buttons are OK). For
* virtual events, specifies the Tk_Uid of the
* virtual event name (never 0). */
-} Pattern;
+} TkPattern;
/*
* The following structure defines a pattern sequence, which consists of one
@@ -209,7 +209,7 @@ typedef struct PatSeq {
* for end of list). Needed to implement
* Tk_DeleteAllBindings. In a virtual event
* table, always NULL. */
- Pattern pats[1]; /* Array of "numPats" patterns. Only one
+ TkPattern pats[1]; /* Array of "numPats" patterns. Only one
* element is declared here but in actuality
* enough space will be allocated for
* "numPats" patterns. To match, pats[0] must
@@ -612,7 +612,8 @@ static int DeleteVirtualEvent(Tcl_Interp *interp,
const char *eventString);
static void DeleteVirtualEventTable(VirtualEventTable *vetPtr);
static void ExpandPercents(TkWindow *winPtr, const char *before,
- XEvent *eventPtr,KeySym keySym,Tcl_DString *dsPtr);
+ XEvent *eventPtr,KeySym keySym,
+ unsigned int scriptCount, Tcl_DString *dsPtr);
static PatSeq * FindSequence(Tcl_Interp *interp,
Tcl_HashTable *patternTablePtr, ClientData object,
const char *eventString, int create,
@@ -635,7 +636,7 @@ static PatSeq * MatchPatterns(TkDisplay *dispPtr,
static int NameToWindow(Tcl_Interp *interp, Tk_Window main,
Tcl_Obj *objPtr, Tk_Window *tkwinPtr);
static int ParseEventDescription(Tcl_Interp *interp,
- const char **eventStringPtr, Pattern *patPtr,
+ const char **eventStringPtr, TkPattern *patPtr,
unsigned long *eventMaskPtr);
static void DoWarp(ClientData clientData);
@@ -1221,6 +1222,7 @@ Tk_BindEvent(
XEvent *ringPtr;
PatSeq *vMatchDetailList, *vMatchNoDetailList;
int flags, oldScreen;
+ unsigned int scriptCount;
Tcl_Interp *interp;
Tcl_DString scripts;
Tcl_InterpState interpState;
@@ -1372,6 +1374,7 @@ Tk_BindEvent(
* each object.
*/
+ scriptCount = 0;
Tcl_DStringInit(&scripts);
for ( ; numObjects > 0; numObjects--, objectPtr++) {
@@ -1421,7 +1424,7 @@ Tk_BindEvent(
if (matchPtr != NULL) {
ExpandPercents(winPtr, sourcePtr->script, eventPtr,
- detail.keySym, &scripts);
+ detail.keySym, scriptCount++, &scripts);
/*
* A "" is added to the scripts string to separate the various
@@ -1601,7 +1604,7 @@ MatchPatterns(
for ( ; psPtr != NULL; psPtr = psPtr->nextSeqPtr) {
XEvent *eventPtr = &bindPtr->eventRing[bindPtr->curEvent];
Detail *detailPtr = &bindPtr->detailRing[bindPtr->curEvent];
- Pattern *patPtr = psPtr->pats;
+ TkPattern *patPtr = psPtr->pats;
Window window = eventPtr->xany.window;
int patCount, ringCount, flags, state, modMask, i;
@@ -1815,7 +1818,7 @@ MatchPatterns(
*/
if (bestPtr != NULL) {
- Pattern *patPtr2;
+ TkPattern *patPtr2;
if (matchPtr->numPats != bestPtr->numPats) {
if (bestPtr->numPats > matchPtr->numPats) {
@@ -1903,6 +1906,8 @@ ExpandPercents(
* in % replacements. */
KeySym keySym, /* KeySym: only relevant for KeyPress and
* KeyRelease events). */
+ unsigned int scriptCount, /* The number of script-based binding patterns
+ * matched so far for this event. */
Tcl_DString *dsPtr) /* Dynamic string in which to append new
* command. */
{
@@ -2184,6 +2189,9 @@ ExpandPercents(
}
}
goto doString;
+ case 'M':
+ number = scriptCount;
+ goto doNumber;
case 'N':
if ((flags & KEY) && (eventPtr->type != MouseWheelEvent)) {
number = (int) keySym;
@@ -2879,7 +2887,7 @@ HandleEventGenerate(
const char *name, *windowName;
int count, flags, synch, i, number, warp;
Tcl_QueuePosition pos;
- Pattern pat;
+ TkPattern pat;
Tk_Window tkwin, tkwin2;
TkWindow *mainPtr;
unsigned long eventMask;
@@ -3618,10 +3626,10 @@ FindSequence(
unsigned long *maskPtr) /* *maskPtr is filled in with the event types
* on which this pattern sequence depends. */
{
- Pattern pats[EVENT_BUFFER_SIZE];
+ TkPattern pats[EVENT_BUFFER_SIZE];
int numPats, virtualFound;
const char *p;
- Pattern *patPtr;
+ TkPattern *patPtr;
PatSeq *psPtr;
Tcl_HashEntry *hPtr;
int flags, count, isNew;
@@ -3707,7 +3715,7 @@ FindSequence(
key.type = patPtr->eventType;
key.detail = patPtr->detail;
hPtr = Tcl_CreateHashEntry(patternTablePtr, (char *) &key, &isNew);
- sequenceSize = numPats*sizeof(Pattern);
+ sequenceSize = numPats*sizeof(TkPattern);
if (!isNew) {
for (psPtr = Tcl_GetHashValue(hPtr); psPtr != NULL;
psPtr = psPtr->nextSeqPtr) {
@@ -3733,7 +3741,7 @@ FindSequence(
return NULL;
}
- psPtr = ckalloc(sizeof(PatSeq) + (numPats-1)*sizeof(Pattern));
+ psPtr = ckalloc(sizeof(PatSeq) + (numPats-1)*sizeof(TkPattern));
psPtr->numPats = numPats;
psPtr->script = NULL;
psPtr->flags = flags;
@@ -3777,7 +3785,7 @@ ParseEventDescription(
const char **eventStringPtr,/* On input, holds a pointer to start of event
* string. On exit, gets pointer to rest of
* string after parsed event. */
- Pattern *patPtr, /* Filled with the pattern parsed from the
+ TkPattern *patPtr, /* Filled with the pattern parsed from the
* event string. */
unsigned long *eventMaskPtr)/* Filled with event mask of matched event. */
{
@@ -4065,7 +4073,7 @@ static Tcl_Obj *
GetPatternObj(
PatSeq *psPtr)
{
- Pattern *patPtr;
+ TkPattern *patPtr;
int patsLeft, needMods;
const ModInfo *modPtr;
const EventInfo *eiPtr;
@@ -4113,15 +4121,15 @@ GetPatternObj(
Tcl_AppendToObj(patternObj, "<", 1);
if ((psPtr->flags & PAT_NEARBY) && (patsLeft > 1)
- && (memcmp(patPtr, patPtr-1, sizeof(Pattern)) == 0)) {
+ && (memcmp(patPtr, patPtr-1, sizeof(TkPattern)) == 0)) {
patsLeft--;
patPtr--;
if ((patsLeft > 1) &&
- (memcmp(patPtr, patPtr-1, sizeof(Pattern)) == 0)) {
+ (memcmp(patPtr, patPtr-1, sizeof(TkPattern)) == 0)) {
patsLeft--;
patPtr--;
if ((patsLeft > 1) &&
- (memcmp(patPtr, patPtr-1, sizeof(Pattern)) == 0)) {
+ (memcmp(patPtr, patPtr-1, sizeof(TkPattern)) == 0)) {
patsLeft--;
patPtr--;
Tcl_AppendToObj(patternObj, "Quadruple-", 10);
diff --git a/generic/tkBitmap.c b/generic/tkBitmap.c
index 729fff4..88f3e2b 100644
--- a/generic/tkBitmap.c
+++ b/generic/tkBitmap.c
@@ -305,7 +305,7 @@ GetBitmap(
TkBitmap *bitmapPtr, *existingBitmapPtr;
TkPredefBitmap *predefPtr;
Pixmap bitmap;
- int isNew, width, height, dummy2;
+ int isNew, width = 0, height = 0, dummy2;
TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
ThreadSpecificData *tsdPtr =
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
diff --git a/generic/tkCanvUtil.c b/generic/tkCanvUtil.c
index 23c73e5..cbbc2b4 100644
--- a/generic/tkCanvUtil.c
+++ b/generic/tkCanvUtil.c
@@ -1432,7 +1432,7 @@ Tk_CanvasPsOutline(
char *p = ptr;
converted = Tcl_ObjPrintf("%d", *p++ & 0xff);
- for (i = dash->number-1 ; i>=0 ; i--) {
+ for (i = dash->number-1 ; i>0 ; i--) {
Tcl_AppendPrintfToObj(converted, " %d", *p++ & 0xff);
}
Tcl_AppendObjToObj(psObj, converted);
diff --git a/generic/tkEntry.c b/generic/tkEntry.c
index f68e1a3..3ad9acd 100644
--- a/generic/tkEntry.c
+++ b/generic/tkEntry.c
@@ -1337,7 +1337,7 @@ ConfigureEntry(
double dvalue;
- if (sscanf(entryPtr->string, "%lf", &dvalue) == 0) {
+ if (sscanf(entryPtr->string, "%lf", &dvalue) <= 0) {
/* Scan failure */
dvalue = sbPtr->fromValue;
} else if (dvalue > sbPtr->toValue) {
@@ -4254,7 +4254,7 @@ SpinboxInvoke(
} else if (!DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue)) {
double dvalue;
- if (sscanf(entryPtr->string, "%lf", &dvalue) == 0) {
+ if (sscanf(entryPtr->string, "%lf", &dvalue) <= 0) {
/*
* If the string doesn't scan as a double value, just
* use the -from value
diff --git a/generic/tkEvent.c b/generic/tkEvent.c
index 51eca3a..bcc6d98 100644
--- a/generic/tkEvent.c
+++ b/generic/tkEvent.c
@@ -356,7 +356,7 @@ CreateXIC(
/* XCreateIC failed. */
return;
}
-
+
/*
* Adjust the window's event mask if the IM requires it.
*/
diff --git a/generic/tkFont.c b/generic/tkFont.c
index a955c35..447f9e1 100644
--- a/generic/tkFont.c
+++ b/generic/tkFont.c
@@ -633,7 +633,7 @@ Tk_FontObjCmd(
return result;
}
return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr);
- }
+ }
case FONT_CREATE: {
int skip = 3, i;
const char *name;
@@ -2994,13 +2994,6 @@ PointInQuadrilateral(
}
static inline int
-sign(
- double value)
-{
- return (value < 0.0) ? -1 : (value > 0.0) ? 1 : 0;
-}
-
-static inline int
SidesIntersect(
double ax1, double ay1, double ax2, double ay2,
double bx1, double by1, double bx2, double by2)
@@ -3375,7 +3368,6 @@ ConfigAttributesObj(
for (i = 0; i < objc; i += 2) {
optionPtr = objv[i];
- valuePtr = objv[i + 1];
if (Tcl_GetIndexFromObj(interp, optionPtr, fontOpt, "option", 1,
&index) != TCL_OK) {
@@ -3396,6 +3388,7 @@ ConfigAttributesObj(
}
return TCL_ERROR;
}
+ valuePtr = objv[i + 1];
switch (index) {
case FONT_FAMILY:
diff --git a/generic/tkGrid.c b/generic/tkGrid.c
index 3e40875..2a88b76 100644
--- a/generic/tkGrid.c
+++ b/generic/tkGrid.c
@@ -2018,7 +2018,7 @@ ResolveConstraints(
if (slavePtr->numCols > 1) {
slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
layoutPtr[rightEdge].binNextPtr = slavePtr;
- } else {
+ } else if (rightEdge >= 0) {
int size = slavePtr->size + layoutPtr[rightEdge].pad;
if (size > layoutPtr[rightEdge].minSize) {
@@ -2037,7 +2037,7 @@ ResolveConstraints(
if (slavePtr->numRows > 1) {
slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
layoutPtr[rightEdge].binNextPtr = slavePtr;
- } else {
+ } else if (rightEdge >= 0) {
int size = slavePtr->size + layoutPtr[rightEdge].pad;
if (size > layoutPtr[rightEdge].minSize) {
diff --git a/generic/tkInt.decls b/generic/tkInt.decls
index b9356d2..ebbadba 100644
--- a/generic/tkInt.decls
+++ b/generic/tkInt.decls
@@ -1032,6 +1032,9 @@ declare 53 aqua {
declare 54 aqua {
void *TkMacOSXDrawable(Drawable drawable)
}
+declare 55 aqua {
+ int TkpScanWindowId(Tcl_Interp *interp, const char *string, Window *idPtr)
+}
##############################################################################
diff --git a/generic/tkIntPlatDecls.h b/generic/tkIntPlatDecls.h
index 15ed775..3a2a8aa 100644
--- a/generic/tkIntPlatDecls.h
+++ b/generic/tkIntPlatDecls.h
@@ -255,6 +255,9 @@ EXTERN void TkGenWMDestroyEvent(Tk_Window tkwin);
EXTERN unsigned long TkpGetMS(void);
/* 54 */
EXTERN void * TkMacOSXDrawable(Drawable drawable);
+/* 55 */
+EXTERN int TkpScanWindowId(Tcl_Interp *interp,
+ const char *string, Window *idPtr);
#endif /* AQUA */
#if !(defined(_WIN32) || defined(__CYGWIN__) || defined(MAC_OSX_TK)) /* X11 */
/* 0 */
@@ -395,6 +398,7 @@ typedef struct TkIntPlatStubs {
void (*reserved52)(void);
unsigned long (*tkpGetMS) (void); /* 53 */
void * (*tkMacOSXDrawable) (Drawable drawable); /* 54 */
+ int (*tkpScanWindowId) (Tcl_Interp *interp, const char *string, Window *idPtr); /* 55 */
#endif /* AQUA */
#if !(defined(_WIN32) || defined(__CYGWIN__) || defined(MAC_OSX_TK)) /* X11 */
void (*tkCreateXEventSource) (void); /* 0 */
@@ -622,6 +626,8 @@ extern const TkIntPlatStubs *tkIntPlatStubsPtr;
(tkIntPlatStubsPtr->tkpGetMS) /* 53 */
#define TkMacOSXDrawable \
(tkIntPlatStubsPtr->tkMacOSXDrawable) /* 54 */
+#define TkpScanWindowId \
+ (tkIntPlatStubsPtr->tkpScanWindowId) /* 55 */
#endif /* AQUA */
#if !(defined(_WIN32) || defined(__CYGWIN__) || defined(MAC_OSX_TK)) /* X11 */
#define TkCreateXEventSource \
diff --git a/generic/tkStubInit.c b/generic/tkStubInit.c
index 5a3e1ce..f621d82 100644
--- a/generic/tkStubInit.c
+++ b/generic/tkStubInit.c
@@ -559,6 +559,7 @@ static const TkIntPlatStubs tkIntPlatStubs = {
0, /* 52 */
TkpGetMS, /* 53 */
TkMacOSXDrawable, /* 54 */
+ TkpScanWindowId, /* 55 */
#endif /* AQUA */
#if !(defined(_WIN32) || defined(__CYGWIN__) || defined(MAC_OSX_TK)) /* X11 */
TkCreateXEventSource, /* 0 */
diff --git a/generic/tkText.c b/generic/tkText.c
index 386dac5..0d06233 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -881,7 +881,7 @@ TextWidgetObjCmd(
} else if (c == 'd' && (length > 8)
&& !strncmp("-displaylines", option, (unsigned) length)) {
TkTextLine *fromPtr, *lastPtr;
- TkTextIndex index;
+ TkTextIndex index, index2;
int compare = TkTextIndexCmp(indexFromPtr, indexToPtr);
value = 0;
@@ -916,35 +916,44 @@ TextWidgetObjCmd(
/*
* We're going to count up all display lines in the logical
* line of 'indexFromPtr' up to, but not including the logical
- * line of 'indexToPtr', and then subtract off what we didn't
- * want from 'from' and add on what we didn't count from 'to.
+ * line of 'indexToPtr' (except if this line is elided), and
+ * then subtract off what came in too much from elided lines,
+ * also subtract off what we didn't want from 'from' and add
+ * on what we didn't count from 'to'.
*/
- while (index.linePtr != indexToPtr->linePtr) {
- value += TkTextUpdateOneLine(textPtr, fromPtr,0,&index,0);
-
- /*
- * We might have skipped past indexToPtr, if we have
- * multiple logical lines in a single display line.
- */
- if (TkTextIndexCmp(&index,indexToPtr) > 0) {
- break;
- }
+ while (TkTextIndexCmp(&index,indexToPtr) < 0) {
+ value += TkTextUpdateOneLine(textPtr, index.linePtr,
+ 0, &index, 0);
}
- /*
- * Now we need to adjust the count to add on the number of
- * display lines in the last logical line, and subtract off
- * the number of display lines overcounted in the first
- * logical line. This logic is still ok if both indices are in
- * the same logical line.
- */
+ index2 = index;
+
+ /*
+ * Now we need to adjust the count to:
+ * - subtract off the number of display lines between
+ * indexToPtr and index2, since we might have skipped past
+ * indexToPtr, if we have several logical lines in a
+ * single display line
+ * - subtract off the number of display lines overcounted
+ * in the first logical line
+ * - add on the number of display lines in the last logical
+ * line
+ * This logic is still ok if both indexFromPtr and indexToPtr
+ * are in the same logical line.
+ */
+ index = *indexToPtr;
+ index.byteIndex = 0;
+ while (TkTextIndexCmp(&index,&index2) < 0) {
+ value -= TkTextUpdateOneLine(textPtr, index.linePtr,
+ 0, &index, 0);
+ }
index.linePtr = indexFromPtr->linePtr;
index.byteIndex = 0;
while (1) {
TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL);
- if (index.byteIndex >= indexFromPtr->byteIndex) {
+ if (TkTextIndexCmp(&index,indexFromPtr) >= 0) {
break;
}
TkTextIndexForwBytes(textPtr, &index, 1, &index);
@@ -956,7 +965,7 @@ TextWidgetObjCmd(
index.byteIndex = 0;
while (1) {
TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL);
- if (index.byteIndex >= indexToPtr->byteIndex) {
+ if (TkTextIndexCmp(&index,indexToPtr) >= 0) {
break;
}
TkTextIndexForwBytes(textPtr, &index, 1, &index);
diff --git a/generic/tkText.h b/generic/tkText.h
index fb9eab2..99a4888 100644
--- a/generic/tkText.h
+++ b/generic/tkText.h
@@ -1066,6 +1066,9 @@ MODULE_SCOPE void TkTextIndexBackChars(const TkText *textPtr,
TkTextIndex *dstPtr, TkTextCountType type);
MODULE_SCOPE int TkTextIndexCmp(const TkTextIndex *index1Ptr,
const TkTextIndex *index2Ptr);
+MODULE_SCOPE int TkTextIndexCountBytes(const TkText *textPtr,
+ const TkTextIndex *index1Ptr,
+ const TkTextIndex *index2Ptr);
MODULE_SCOPE int TkTextIndexCount(const TkText *textPtr,
const TkTextIndex *index1Ptr,
const TkTextIndex *index2Ptr,
diff --git a/generic/tkTextBTree.c b/generic/tkTextBTree.c
index e34dae7..7383d21 100644
--- a/generic/tkTextBTree.c
+++ b/generic/tkTextBTree.c
@@ -1879,8 +1879,7 @@ TkBTreePreviousLine(
* number of pixels in the widget.
*
* Results:
- * The result is the index of linePtr within the tree, where 0
- * corresponds to the first line in the tree.
+ * The result is the pixel height of the top of the given line.
*
* Side effects:
* None.
@@ -1989,7 +1988,7 @@ TkBTreeLinesTo(
}
}
if (textPtr != NULL) {
- /*
+ /*
* The index to return must be relative to textPtr, not to the entire
* tree. Take care to never return a negative index when linePtr
* denotes a line before -startline, or an index larger than the
@@ -3616,20 +3615,6 @@ TkTextIsElided(
infoPtr->elidePriority = -1;
for (i = infoPtr->numTags-1; i >=0; i--) {
if (infoPtr->tagCnts[i] & 1) {
- /*
- * Who would make the selection elided?
- */
-
- if ((tagPtr == textPtr->selTagPtr)
- && !(textPtr->flags & GOT_FOCUS)
- && (textPtr->inactiveSelBorder == NULL
-#ifdef MAC_OSX_TK
- /* Don't show inactive selection in disabled widgets. */
- || textPtr->state == TK_TEXT_STATE_DISABLED
-#endif
- )) {
- continue;
- }
infoPtr->elide = infoPtr->tagPtrs[i]->elide;
/*
diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c
index 8ceb3fa..01ec22d 100644
--- a/generic/tkTextDisp.c
+++ b/generic/tkTextDisp.c
@@ -243,7 +243,8 @@ typedef struct DLine {
* top to bottom. Note: the next DLine doesn't
* always correspond to the next line of text:
* (a) can have multiple DLines for one text
- * line, and (b) can have gaps where DLine's
+ * line (wrapping), (b) can have elided newlines,
+ * and (c) can have gaps where DLine's
* have been deleted because they're out of
* date. */
int flags; /* Various flag bits: see below for values. */
@@ -543,7 +544,8 @@ static void DisplayDLine(TkText *textPtr, DLine *dlPtr,
static void DisplayLineBackground(TkText *textPtr, DLine *dlPtr,
DLine *prevPtr, Pixmap pixmap);
static void DisplayText(ClientData clientData);
-static DLine * FindDLine(DLine *dlPtr, const TkTextIndex *indexPtr);
+static DLine * FindDLine(TkText *textPtr, DLine *dlPtr,
+ const TkTextIndex *indexPtr);
static void FreeDLines(TkText *textPtr, DLine *firstPtr,
DLine *lastPtr, int action);
static void FreeStyle(TkText *textPtr, TextStyle *stylePtr);
@@ -590,6 +592,8 @@ static int TextGetScrollInfoObj(Tcl_Interp *interp,
int *intPtr);
static void AsyncUpdateLineMetrics(ClientData clientData);
static void AsyncUpdateYScrollbar(ClientData clientData);
+static int IsStartOfNotMergedLine(TkText *textPtr,
+ CONST TkTextIndex *indexPtr);
/*
* Result values returned by TextGetScrollInfoObj:
@@ -1020,7 +1024,7 @@ FreeStyle(
* whose leftmost character is given by indexPtr.
*
* Results:
- * The return value is a pointer to a DLine structure desribing the
+ * The return value is a pointer to a DLine structure describing the
* display line. All fields are filled in and correct except for y and
* nextPtr.
*
@@ -1759,7 +1763,7 @@ UpdateDisplayInfo(
*/
index = textPtr->topIndex;
- dlPtr = FindDLine(dInfoPtr->dLinePtr, &index);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &index);
if ((dlPtr != NULL) && (dlPtr != dInfoPtr->dLinePtr)) {
FreeDLines(textPtr, dInfoPtr->dLinePtr, dlPtr, DLINE_UNLINK);
}
@@ -1909,7 +1913,7 @@ UpdateDisplayInfo(
prevPtr->index.linePtr) != lineHeight)) {
/*
* The logical line height we just calculated is actually
- * differnt to the currently cached height of the text line.
+ * different to the currently cached height of the text line.
* That is fine (the text line heights are only calculated
* asynchronously), but we must update the cached height so
* that any counts made with DLine pointers are the same as
@@ -3385,7 +3389,7 @@ TkTextFindDisplayLineEnd(
{
TkTextIndex index;
- if (!end && indexPtr->byteIndex == 0) {
+ if (!end && IsStartOfNotMergedLine(textPtr, indexPtr)) {
/*
* Nothing to do.
*/
@@ -3463,7 +3467,8 @@ TkTextFindDisplayLineEnd(
*/
*xOffset = DlineXOfIndex(textPtr, dlPtr,
- indexPtr->byteIndex - dlPtr->index.byteIndex);
+ TkTextIndexCountBytes(textPtr, &dlPtr->index,
+ indexPtr));
}
if (end) {
/*
@@ -3533,6 +3538,27 @@ CalculateDisplayLineHeight(
DLine *dlPtr;
int pixelHeight;
+ if (tkTextDebug) {
+ int oldtkTextDebug = tkTextDebug;
+ /*
+ * Check that the indexPtr we are given really is at the start of a
+ * display line. The gymnastics with tkTextDebug is to prevent
+ * failure of a test suite test, that checks that lines are rendered
+ * exactly once. TkTextFindDisplayLineEnd is used here for checking
+ * indexPtr but it calls LayoutDLine/FreeDLine which makes the
+ * counting wrong. The debug mode shall therefore be switched off
+ * when calling TkTextFindDisplayLineEnd.
+ */
+
+ TkTextIndex indexPtr2 = *indexPtr;
+ tkTextDebug = 0;
+ TkTextFindDisplayLineEnd(textPtr, &indexPtr2, 0, NULL);
+ tkTextDebug = oldtkTextDebug;
+ if (TkTextIndexCmp(&indexPtr2,indexPtr) != 0) {
+ Tcl_Panic("CalculateDisplayLineHeight called with bad indexPtr");
+ }
+ }
+
/*
* Special case for artificial last line. May be better to move this
* inside LayoutDLine.
@@ -3599,26 +3625,44 @@ TkTextIndexYPixels(
{
int pixelHeight;
TkTextIndex index;
+ int alreadyStartOfLine = 1;
+
+ /*
+ * Find the index denoting the closest position being at the same time
+ * the start of a logical line above indexPtr and the start of a display
+ * line.
+ */
+
+ index = *indexPtr;
+ while (1) {
+ TkTextFindDisplayLineEnd(textPtr, &index, 0, NULL);
+ if (index.byteIndex == 0) {
+ break;
+ }
+ TkTextIndexBackBytes(textPtr, &index, 1, &index);
+ alreadyStartOfLine = 0;
+ }
- pixelHeight = TkBTreePixelsTo(textPtr, indexPtr->linePtr);
+ pixelHeight = TkBTreePixelsTo(textPtr, index.linePtr);
/*
- * Iterate through all display-lines corresponding to the single logical
- * line belonging to indexPtr, adding up the pixel height of each such
- * display line as we go along, until we go past 'indexPtr'.
+ * Shortcut to avoid layout of a superfluous display line. We know there
+ * is nothing more to add up to the height if the index we were given was
+ * already on the first display line of a logical line.
*/
- if (indexPtr->byteIndex == 0) {
- return pixelHeight;
+ if (alreadyStartOfLine) {
+ return pixelHeight;
}
- index.tree = textPtr->sharedTextPtr->tree;
- index.linePtr = indexPtr->linePtr;
- index.byteIndex = 0;
- index.textPtr = NULL;
+ /*
+ * Iterate through display lines, starting at the logical line belonging
+ * to index, adding up the pixel height of each such display line as we
+ * go along, until we go past 'indexPtr'.
+ */
while (1) {
- int bytes, height;
+ int bytes, height, compare;
/*
* Currently this call doesn't have many side-effects. However, if in
@@ -3630,9 +3674,10 @@ TkTextIndexYPixels(
height = CalculateDisplayLineHeight(textPtr, &index, &bytes, NULL);
- index.byteIndex += bytes;
+ TkTextIndexForwBytes(textPtr, &index, bytes, &index);
- if (index.byteIndex > indexPtr->byteIndex) {
+ compare = TkTextIndexCmp(&index,indexPtr);
+ if (compare > 0) {
return pixelHeight;
}
@@ -3640,7 +3685,7 @@ TkTextIndexYPixels(
pixelHeight += height;
}
- if (index.byteIndex == indexPtr->byteIndex) {
+ if (compare == 0) {
return pixelHeight;
}
}
@@ -3704,10 +3749,26 @@ TkTextUpdateOneLine(
}
/*
+ * CalculateDisplayLineHeight _must_ be called (below) with an index at
+ * the beginning of a display line. Force this to happen. This is needed
+ * when TkTextUpdateOneLine is called with a line that is merged with its
+ * previous line: the number of merged logical lines in a display line is
+ * calculated correctly only when CalculateDisplayLineHeight receives
+ * an index at the beginning of a display line. In turn this causes the
+ * merged lines to receive their correct zero pixel height in
+ * TkBTreeAdjustPixelHeight.
+ */
+
+ TkTextFindDisplayLineEnd(textPtr, indexPtr, 0, NULL);
+ linePtr = indexPtr->linePtr;
+
+ /*
* Iterate through all display-lines corresponding to the single logical
- * line 'linePtr', adding up the pixel height of each such display line as
- * we go along. The final total is, therefore, the height of the logical
- * line.
+ * line 'linePtr' (and lines merged into this line due to eol elision),
+ * adding up the pixel height of each such display line as we go along.
+ * The final total is, therefore, the total height of all display lines
+ * made up by the logical line 'linePtr' and subsequent logical lines
+ * merged into this line.
*/
displayLines = 0;
@@ -3724,7 +3785,7 @@ TkTextUpdateOneLine(
* test below this while loop.
*/
- height = CalculateDisplayLineHeight(textPtr, indexPtr, &bytes,
+ height = CalculateDisplayLineHeight(textPtr, indexPtr, &bytes,
&logicalLines);
if (height > 0) {
@@ -3738,44 +3799,31 @@ TkTextUpdateOneLine(
break;
}
- if (logicalLines == 0) {
- if (indexPtr->linePtr != linePtr) {
- /*
- * If we reached the end of the logical line, then either way
- * we don't have a partial calculation.
- */
-
- partialCalc = 0;
- break;
- }
- } else if (indexPtr->byteIndex != 0) {
- /*
- * We must still be on the same wrapped line.
- */
- } else {
- /*
- * Must check if indexPtr is really a new logical line which is
- * not merged with the previous line. The only code that would
- * really know this is LayoutDLine, which doesn't pass the
- * information on, so we have to check manually here.
- */
-
- TkTextIndex idx;
-
- TkTextIndexBackChars(textPtr, indexPtr, 1, &idx, COUNT_INDICES);
- if (!TkTextIsElided(textPtr, &idx, NULL)) {
- /*
- * We've ended a logical line.
- */
+ if (mergedLines == 0) {
+ if (indexPtr->linePtr != linePtr) {
+ /*
+ * If we reached the end of the logical line, then either way
+ * we don't have a partial calculation.
+ */
- partialCalc = 0;
- break;
- }
+ partialCalc = 0;
+ break;
+ }
+ } else {
+ if (IsStartOfNotMergedLine(textPtr, indexPtr)) {
+ /*
+ * We've ended a logical line.
+ */
+
+ partialCalc = 0;
+ break;
+ }
- /*
- * We must still be on the same wrapped line.
- */
- }
+ /*
+ * We must still be on the same wrapped line, on a new logical
+ * line merged with the logical line 'linePtr'.
+ */
+ }
if (partialCalc && displayLines > 50 && mergedLines == 0) {
/*
* Only calculate 50 display lines at a time, to avoid huge
@@ -3900,6 +3948,7 @@ DisplayText(
* warnings. */
Tcl_Interp *interp;
+
if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
/*
* The widget has been deleted. Don't do anything.
@@ -3970,15 +4019,6 @@ DisplayText(
UpdateDisplayInfo(textPtr);
dInfoPtr->dLinesInvalidated = 0;
-#ifdef MAC_OSX_TK
- /*
- * Make sure that unmapped subwindows really have been unmapped.
- * If the unmap request is pending as an idle request, the window
- * can get redrawn on top of the widget.
- */
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
-#endif
-
/*
* See if it's possible to bring some parts of the screen up-to-date by
* scrolling (copying from other parts of the screen). We have to be
@@ -4100,6 +4140,7 @@ DisplayText(
oldY, dInfoPtr->maxX-dInfoPtr->x, height, 0, y-oldY,
damageRgn)) {
TextInvalidateRegion(textPtr, damageRgn);
+
}
numCopies++;
TkDestroyRegion(damageRgn);
@@ -4548,6 +4589,8 @@ TextChanged(
TextDInfo *dInfoPtr = textPtr->dInfoPtr;
DLine *firstPtr, *lastPtr;
TkTextIndex rounded;
+ TkTextLine *linePtr;
+ int notBegin;
/*
* Schedule both a redisplay and a recomputation of display information.
@@ -4573,23 +4616,78 @@ TextChanged(
/*
* Find the DLines corresponding to index1Ptr and index2Ptr. There is one
* tricky thing here, which is that we have to relayout in units of whole
- * text lines: round index1Ptr back to the beginning of its text line, and
- * include all the display lines after index2, up to the end of its text
- * line. This is necessary because the indices stored in the display lines
- * will no longer be valid. It's also needed because any edit could change
- * the way lines wrap.
+ * text lines: This is necessary because the indices stored in the display
+ * lines will no longer be valid. It's also needed because any edit could
+ * change the way lines wrap.
+ * To relayout in units of whole text (logical) lines, round index1Ptr
+ * back to the beginning of its text line (or, if this line start is
+ * elided, to the beginning of the text line that starts the display line
+ * it is included in), and include all the display lines after index2Ptr,
+ * up to the end of its text line (or, if this line end is elided, up to
+ * the end of the first non elided text line after this line end).
*/
rounded = *index1Ptr;
rounded.byteIndex = 0;
- firstPtr = FindDLine(dInfoPtr->dLinePtr, &rounded);
+ notBegin = 0;
+ while (!IsStartOfNotMergedLine(textPtr, &rounded) && notBegin) {
+ notBegin = !TkTextIndexBackBytes(textPtr, &rounded, 1, &rounded);
+ rounded.byteIndex = 0;
+ }
+
+ /*
+ * 'rounded' now points to the start of a display line as well as the
+ * real (non elided) start of a logical line, and this index is the
+ * closest before index1Ptr.
+ */
+
+ firstPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &rounded);
+
if (firstPtr == NULL) {
+ /*
+ * index1Ptr pertains to no display line, i.e this index is after
+ * the last display line. Since index2Ptr is after index1Ptr, there
+ * is no display line to free/redisplay and we can return early.
+ */
+
return;
}
- lastPtr = FindDLine(dInfoPtr->dLinePtr, index2Ptr);
- while ((lastPtr != NULL)
- && (lastPtr->index.linePtr == index2Ptr->linePtr)) {
- lastPtr = lastPtr->nextPtr;
+
+ rounded = *index2Ptr;
+ linePtr = index2Ptr->linePtr;
+ do {
+ linePtr = TkBTreeNextLine(textPtr, linePtr);
+ if (linePtr == NULL) {
+ break;
+ }
+ rounded.linePtr = linePtr;
+ rounded.byteIndex = 0;
+ } while (!IsStartOfNotMergedLine(textPtr, &rounded));
+
+ if (linePtr == NULL) {
+ lastPtr = NULL;
+ } else {
+ /*
+ * 'rounded' now points to the start of a display line as well as the
+ * start of a logical line not merged with its previous line, and
+ * this index is the closest after index2Ptr.
+ */
+
+ lastPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &rounded);
+
+ /*
+ * At least one display line is supposed to change. This makes the
+ * redisplay OK in case the display line we expect to get here was
+ * unlinked by a previous call to TkTextChanged and the text widget
+ * did not update before reaching this point. This happens for
+ * instance when moving the cursor up one line.
+ * Note that lastPtr != NULL here, otherwise we would have returned
+ * earlier when we tested for firstPtr being NULL.
+ */
+
+ if (lastPtr == firstPtr) {
+ lastPtr = lastPtr->nextPtr;
+ }
}
/*
@@ -4769,14 +4867,13 @@ TextRedrawTag(
* the line containing the previous character.
*/
- if (curIndexPtr->byteIndex == 0) {
- dlPtr = FindDLine(dlPtr, curIndexPtr);
+ if (IsStartOfNotMergedLine(textPtr, curIndexPtr)) {
+ dlPtr = FindDLine(textPtr, dlPtr, curIndexPtr);
} else {
- TkTextIndex tmp;
+ TkTextIndex tmp = *curIndexPtr;
- tmp = *curIndexPtr;
- tmp.byteIndex -= 1;
- dlPtr = FindDLine(dlPtr, &tmp);
+ TkTextIndexBackBytes(textPtr, &tmp, 1, &tmp);
+ dlPtr = FindDLine(textPtr, dlPtr, &tmp);
}
if (dlPtr == NULL) {
break;
@@ -4792,9 +4889,9 @@ TextRedrawTag(
curIndexPtr = &search.curIndex;
endIndexPtr = curIndexPtr;
}
- endPtr = FindDLine(dlPtr, endIndexPtr);
- if ((endPtr != NULL) && (endPtr->index.linePtr == endIndexPtr->linePtr)
- && (endPtr->index.byteIndex < endIndexPtr->byteIndex)) {
+ endPtr = FindDLine(textPtr, dlPtr, endIndexPtr);
+ if ((endPtr != NULL)
+ && (TkTextIndexCmp(&endPtr->index,endIndexPtr) < 0)) {
endPtr = endPtr->nextPtr;
}
@@ -4912,7 +5009,7 @@ TkTextRelayoutWindow(
* could change the way lines wrap.
*/
- if (textPtr->topIndex.byteIndex != 0) {
+ if (!IsStartOfNotMergedLine(textPtr, &textPtr->topIndex)) {
TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
}
@@ -5025,9 +5122,9 @@ TkTextSetYView(
*/
textPtr->topIndex = *indexPtr;
- if (indexPtr->byteIndex != 0) {
- TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
- }
+ if (!IsStartOfNotMergedLine(textPtr, indexPtr)) {
+ TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
+ }
dInfoPtr->newTopPixelOffset = pickPlace;
goto scheduleUpdate;
}
@@ -5041,7 +5138,7 @@ TkTextSetYView(
if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
UpdateDisplayInfo(textPtr);
}
- dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
if (dlPtr != NULL) {
if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) {
/*
@@ -5050,19 +5147,20 @@ TkTextSetYView(
*/
dlPtr = NULL;
- } else if ((dlPtr->index.linePtr == indexPtr->linePtr)
- && (dlPtr->index.byteIndex <= indexPtr->byteIndex)) {
- if (dInfoPtr->dLinePtr == dlPtr && dInfoPtr->topPixelOffset != 0) {
- /*
- * It is on the top line, but that line is hanging off the top
- * of the screen. Change the top overlap to zero and update.
- */
-
- dInfoPtr->newTopPixelOffset = 0;
- goto scheduleUpdate;
- }
- return;
- }
+ } else {
+ if (TkTextIndexCmp(&dlPtr->index, indexPtr) <= 0) {
+ if (dInfoPtr->dLinePtr == dlPtr && dInfoPtr->topPixelOffset != 0) {
+ /*
+ * It is on the top line, but that line is hanging off the top
+ * of the screen. Change the top overlap to zero and update.
+ */
+
+ dInfoPtr->newTopPixelOffset = 0;
+ goto scheduleUpdate;
+ }
+ return;
+ }
+ }
}
/*
@@ -5073,7 +5171,9 @@ TkTextSetYView(
* If the line is not close, place it in the center of the window.
*/
- lineHeight = CalculateDisplayLineHeight(textPtr, indexPtr, NULL, NULL);
+ tmpIndex = *indexPtr;
+ TkTextFindDisplayLineEnd(textPtr, &tmpIndex, 0, NULL);
+ lineHeight = CalculateDisplayLineHeight(textPtr, &tmpIndex, NULL, NULL);
/*
* It would be better if 'bottomY' were calculated using the actual height
@@ -5114,7 +5214,7 @@ TkTextSetYView(
MeasureUp(textPtr, indexPtr, close + lineHeight
- textPtr->charHeight/2, &tmpIndex, &overlap);
- if (FindDLine(dInfoPtr->dLinePtr, &tmpIndex) != NULL) {
+ if (FindDLine(textPtr, dInfoPtr->dLinePtr, &tmpIndex) != NULL) {
bottomY = dInfoPtr->maxY - dInfoPtr->y;
}
}
@@ -5252,6 +5352,8 @@ MeasureUp(
index.linePtr = TkBTreeFindLine(srcPtr->tree, textPtr, lineNum);
index.byteIndex = 0;
+ TkTextFindDisplayLineEnd(textPtr, &index, 0, NULL);
+ lineNum = TkBTreeLinesTo(textPtr, index.linePtr);
lowestPtr = NULL;
do {
dlPtr = LayoutDLine(textPtr, &index);
@@ -5272,8 +5374,21 @@ MeasureUp(
for (dlPtr = lowestPtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) {
distance -= dlPtr->height;
if (distance <= 0) {
- *dstPtr = dlPtr->index;
- if (overlap != NULL) {
+ *dstPtr = dlPtr->index;
+
+ /*
+ * dstPtr is the start of a display line that is or is not
+ * the start of a logical line. If it is the start of a
+ * logical line, we must check whether this line is merged
+ * with the previous logical line, and if so we must adjust
+ * dstPtr to the start of the display line since a display
+ * line start needs to be returned.
+ */
+ if (!IsStartOfNotMergedLine(textPtr, dstPtr)) {
+ TkTextFindDisplayLineEnd(textPtr, dstPtr, 0, NULL);
+ }
+
+ if (overlap != NULL) {
*overlap = -distance;
}
break;
@@ -5373,16 +5488,24 @@ TkTextSeeCmd(
}
/*
- * Find the chunk that contains the desired index. dlPtr may be NULL if
- * the widget is not mapped. [Bug #641778]
+ * Find the display line containing the desired index. dlPtr may be NULL
+ * if the widget is not mapped. [Bug #641778]
*/
- dlPtr = FindDLine(dInfoPtr->dLinePtr, &index);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &index);
if (dlPtr == NULL) {
return TCL_OK;
}
- byteCount = index.byteIndex - dlPtr->index.byteIndex;
+ /*
+ * Find the chunk within the display line that contains the desired
+ * index. The chunks making the display line are skipped up to but not
+ * including the one crossing index. Skipping is done based on a
+ * byteCount offset possibly spanning several logical lines in case
+ * they are elided.
+ */
+
+ byteCount = TkTextIndexCountBytes(textPtr, &dlPtr->index, &index);
for (chunkPtr = dlPtr->chunkPtr; chunkPtr != NULL ;
chunkPtr = chunkPtr->nextPtr) {
if (byteCount < chunkPtr->numBytes) {
@@ -5398,29 +5521,30 @@ TkTextSeeCmd(
*/
if (chunkPtr != NULL) {
- chunkPtr->bboxProc(textPtr, chunkPtr, byteCount,
- dlPtr->y + dlPtr->spaceAbove,
- dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
- dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width,
- &height);
- delta = x - dInfoPtr->curXPixelOffset;
- oneThird = lineWidth/3;
- if (delta < 0) {
- if (delta < -oneThird) {
- dInfoPtr->newXPixelOffset = x - lineWidth/2;
- } else {
- dInfoPtr->newXPixelOffset += delta;
- }
- } else {
- delta -= lineWidth - width;
- if (delta <= 0) {
- return TCL_OK;
- } else if (delta > oneThird) {
- dInfoPtr->newXPixelOffset = x - lineWidth/2;
- } else {
- dInfoPtr->newXPixelOffset += delta;
- }
- }
+ chunkPtr->bboxProc(textPtr, chunkPtr, byteCount,
+ dlPtr->y + dlPtr->spaceAbove,
+ dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
+ dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width,
+ &height);
+ delta = x - dInfoPtr->curXPixelOffset;
+ oneThird = lineWidth/3;
+ if (delta < 0) {
+ if (delta < -oneThird) {
+ dInfoPtr->newXPixelOffset = x - lineWidth/2;
+ } else {
+ dInfoPtr->newXPixelOffset += delta;
+ }
+ } else {
+ delta -= lineWidth - width;
+ if (delta <= 0) {
+ return TCL_OK;
+ }
+ if (delta > oneThird) {
+ dInfoPtr->newXPixelOffset = x - lineWidth/2;
+ } else {
+ dInfoPtr->newXPixelOffset += delta;
+ }
+ }
}
dInfoPtr->flags |= DINFO_OUT_OF_DATE;
if (!(dInfoPtr->flags & REDRAW_PENDING)) {
@@ -5657,7 +5781,25 @@ YScrollByLines(
offset++;
if (offset == 0) {
textPtr->topIndex = dlPtr->index;
- break;
+
+ /*
+ * topIndex is the start of a logical line. However, if
+ * the eol of the previous logical line is elided, then
+ * topIndex may be elsewhere than the first character of
+ * a display line, which is unwanted. Adjust to the start
+ * of the display line, if needed.
+ * topIndex is the start of a display line that is or is
+ * not the start of a logical line. If it is the start of
+ * a logical line, we must check whether this line is
+ * merged with the previous logical line, and if so we
+ * must adjust topIndex to the start of the display line.
+ */
+ if (!IsStartOfNotMergedLine(textPtr, &textPtr->topIndex)) {
+ TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex,
+ 0, NULL);
+ }
+
+ break;
}
}
@@ -6144,13 +6286,10 @@ GetYPixelCount(
/*
* For the common case where this dlPtr is also the start of the logical
- * line, we can return right away. Note the implicit assumption here that
- * the start of a logical line is always the start of a display line (if
- * the 'elide won't elide first newline' bug is fixed, this will no longer
- * necessarily be true).
+ * line, we can return right away.
*/
- if (dlPtr->index.byteIndex == 0) {
+ if (IsStartOfNotMergedLine(textPtr, &dlPtr->index)) {
return count;
}
@@ -6437,11 +6576,12 @@ AsyncUpdateYScrollbar(
static DLine *
FindDLine(
+ TkText *textPtr, /* Widget record for text widget. */
register DLine *dlPtr, /* Pointer to first in list of DLines to
* search. */
const TkTextIndex *indexPtr)/* Index of desired character. */
{
- TkTextLine *linePtr;
+ DLine *dlPtrPrev;
if (dlPtr == NULL) {
return NULL;
@@ -6456,43 +6596,89 @@ FindDLine(
}
/*
- * Find the first display line that covers the desired text line.
+ * The display line containing the desired index is such that the index
+ * of the first character of this display line is at or before the
+ * desired index, and the index of the first character of the next
+ * display line is after the desired index.
*/
- linePtr = dlPtr->index.linePtr;
- while (linePtr != indexPtr->linePtr) {
- while (dlPtr->index.linePtr == linePtr) {
- dlPtr = dlPtr->nextPtr;
- if (dlPtr == NULL) {
- return NULL;
- }
- }
+ while (TkTextIndexCmp(&dlPtr->index,indexPtr) < 0) {
+ dlPtrPrev = dlPtr;
+ dlPtr = dlPtr->nextPtr;
+ if (dlPtr == NULL) {
+ TkTextIndex indexPtr2;
+ /*
+ * We're past the last display line, either because the desired
+ * index lies past the visible text, or because the desired index
+ * is on the last display line showing the last logical line.
+ */
+ indexPtr2 = dlPtrPrev->index;
+ TkTextIndexForwBytes(textPtr, &indexPtr2, dlPtrPrev->byteCount,
+ &indexPtr2);
+ if (TkTextIndexCmp(&indexPtr2,indexPtr) > 0) {
+ dlPtr = dlPtrPrev;
+ break;
+ } else {
+ return NULL;
+ }
+ }
+ if (TkTextIndexCmp(&dlPtr->index,indexPtr) > 0) {
+ dlPtr = dlPtrPrev;
+ break;
+ }
+ }
- /*
- * VMD: some concern here as to whether this logic, or the caller's
- * logic will work well with partial peer widgets.
- */
+ return dlPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * IsStartOfNotMergedLine --
+ *
+ * This function checks whether the given index is the start of a
+ * logical line that is not merged with the previous logical line
+ * (due to elision of the eol of the previous line).
+ *
+ * Results:
+ * Returns whether the given index denotes the first index of a
+* logical line not merged with its previous line.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
- linePtr = TkBTreeNextLine(NULL, linePtr);
- if (linePtr == NULL) {
- Tcl_Panic("FindDLine reached end of text");
- }
- }
- if (indexPtr->linePtr != dlPtr->index.linePtr) {
- return dlPtr;
+static int
+IsStartOfNotMergedLine(
+ TkText *textPtr, /* Widget record for text widget. */
+ CONST TkTextIndex *indexPtr) /* Index to check. */
+{
+ TkTextIndex indexPtr2;
+
+ if (indexPtr->byteIndex != 0) {
+ /*
+ * Not the start of a logical line.
+ */
+ return 0;
}
- /*
- * Now get to the right position within the text line.
- */
+ if (TkTextIndexBackBytes(textPtr, indexPtr, 1, &indexPtr2)) {
+ /*
+ * indexPtr is the first index of the text widget.
+ */
+ return 1;
+ }
- while (indexPtr->byteIndex >= (dlPtr->index.byteIndex+dlPtr->byteCount)) {
- dlPtr = dlPtr->nextPtr;
- if ((dlPtr == NULL) || (dlPtr->index.linePtr != indexPtr->linePtr)) {
- break;
- }
+ if (!TkTextIsElided(textPtr, &indexPtr2, NULL)) {
+ /*
+ * The eol of the line just before indexPtr is elided.
+ */
+ return 1;
}
- return dlPtr;
+
+ return 0;
}
/*
@@ -6663,10 +6849,15 @@ DlineIndexOfX(
* We've reached the end of the text.
*/
+ TkTextIndexBackChars(NULL, indexPtr, 1, indexPtr, COUNT_INDICES);
return;
}
if (chunkPtr->nextPtr == NULL) {
- TkTextIndexBackChars(NULL, indexPtr, 1, indexPtr, COUNT_INDICES);
+ /*
+ * We've reached the end of the display line.
+ */
+
+ TkTextIndexBackChars(NULL, indexPtr, 1, indexPtr, COUNT_INDICES);
return;
}
chunkPtr = chunkPtr->nextPtr;
@@ -6822,7 +7013,7 @@ TkTextIndexBbox(
TextDInfo *dInfoPtr = textPtr->dInfoPtr;
DLine *dlPtr;
register TkTextDispChunk *chunkPtr;
- int byteIndex;
+ int byteCount;
/*
* Make sure that all of the screen layout information is up to date.
@@ -6836,24 +7027,37 @@ TkTextIndexBbox(
* Find the display line containing the desired index.
*/
- dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
+
+ /*
+ * Two cases shall be trapped here because the logic later really
+ * needs dlPtr to be the display line containing indexPtr:
+ * 1. if no display line contains the desired index (NULL dlPtr)
+ * 2. if indexPtr is before the first display line, in which case
+ * dlPtr currently points to the first display line
+ */
+
if ((dlPtr == NULL) || (TkTextIndexCmp(&dlPtr->index, indexPtr) > 0)) {
return -1;
}
/*
- * Find the chunk within the line that contains the desired index.
+ * Find the chunk within the display line that contains the desired
+ * index. The chunks making the display line are skipped up to but not
+ * including the one crossing indexPtr. Skipping is done based on
+ * a byteCount offset possibly spanning several logical lines in case
+ * they are elided.
*/
- byteIndex = indexPtr->byteIndex - dlPtr->index.byteIndex;
+ byteCount = TkTextIndexCountBytes(textPtr, &dlPtr->index, indexPtr);
for (chunkPtr = dlPtr->chunkPtr; ; chunkPtr = chunkPtr->nextPtr) {
if (chunkPtr == NULL) {
return -1;
}
- if (byteIndex < chunkPtr->numBytes) {
+ if (byteCount < chunkPtr->numBytes) {
break;
}
- byteIndex -= chunkPtr->numBytes;
+ byteCount -= chunkPtr->numBytes;
}
/*
@@ -6863,13 +7067,13 @@ TkTextIndexBbox(
* coordinate on the screen. Translate it to reflect horizontal scrolling.
*/
- chunkPtr->bboxProc(textPtr, chunkPtr, byteIndex,
+ chunkPtr->bboxProc(textPtr, chunkPtr, byteCount,
dlPtr->y + dlPtr->spaceAbove,
dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
dlPtr->baseline - dlPtr->spaceAbove, xPtr, yPtr, widthPtr,
heightPtr);
*xPtr = *xPtr + dInfoPtr->x - dInfoPtr->curXPixelOffset;
- if ((byteIndex == chunkPtr->numBytes-1) && (chunkPtr->nextPtr == NULL)) {
+ if ((byteCount == chunkPtr->numBytes-1) && (chunkPtr->nextPtr == NULL)) {
/*
* Last character in display line. Give it all the space up to the
* line.
@@ -6967,7 +7171,16 @@ TkTextDLineInfo(
* Find the display line containing the desired index.
*/
- dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
+
+ /*
+ * Two cases shall be trapped here because the logic later really
+ * needs dlPtr to be the display line containing indexPtr:
+ * 1. if no display line contains the desired index (NULL dlPtr)
+ * 2. if indexPtr is before the first display line, in which case
+ * dlPtr currently points to the first display line
+ */
+
if ((dlPtr == NULL) || (TkTextIndexCmp(&dlPtr->index, indexPtr) > 0)) {
return -1;
}
diff --git a/generic/tkTextIndex.c b/generic/tkTextIndex.c
index 55a4907..70f74fb 100644
--- a/generic/tkTextIndex.c
+++ b/generic/tkTextIndex.c
@@ -40,6 +40,9 @@ static const char * StartEnd(TkText *textPtr, const char *string,
static int GetIndex(Tcl_Interp *interp, TkSharedText *sharedPtr,
TkText *textPtr, const char *string,
TkTextIndex *indexPtr, int *canCachePtr);
+static int IndexCountBytesOrdered(CONST TkText *textPtr,
+ CONST TkTextIndex *indexPtr1,
+ CONST TkTextIndex *indexPtr2);
/*
* The "textindex" Tcl_Obj definition:
@@ -759,11 +762,11 @@ GetIndex(
}
if (TkTextWindowIndex(textPtr, string, indexPtr) != 0) {
- return TCL_OK;
+ goto done;
}
if (TkTextImageIndex(textPtr, string, indexPtr) != 0) {
- return TCL_OK;
+ goto done;
}
/*
@@ -1616,6 +1619,90 @@ TkTextIndexForwChars(
/*
*---------------------------------------------------------------------------
*
+ * TkTextIndexCountBytes --
+ *
+ * Given a pair of indices in a text widget, this function counts how
+ * many bytes are between the two indices. The two indices do not need
+ * to be ordered.
+ *
+ * Results:
+ * The number of bytes in the given range.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+TkTextIndexCountBytes(
+ CONST TkText *textPtr,
+ CONST TkTextIndex *indexPtr1, /* Index describing one location. */
+ CONST TkTextIndex *indexPtr2) /* Index describing second location. */
+{
+ int compare = TkTextIndexCmp(indexPtr1, indexPtr2);
+
+ if (compare == 0) {
+ return 0;
+ } else if (compare > 0) {
+ return IndexCountBytesOrdered(textPtr, indexPtr2, indexPtr1);
+ } else {
+ return IndexCountBytesOrdered(textPtr, indexPtr1, indexPtr2);
+ }
+}
+
+static int
+IndexCountBytesOrdered(
+ CONST TkText *textPtr,
+ CONST TkTextIndex *indexPtr1,
+ /* Index describing location of character from
+ * which to count. */
+ CONST TkTextIndex *indexPtr2)
+ /* Index describing location of last character
+ * at which to stop the count. */
+{
+ int byteCount, offset;
+ TkTextSegment *segPtr, *segPtr1;
+ TkTextLine *linePtr;
+
+ if (indexPtr1->linePtr == indexPtr2->linePtr) {
+ return indexPtr2->byteIndex - indexPtr1->byteIndex;
+ }
+
+ /*
+ * indexPtr2 is on a line strictly after the line containing indexPtr1.
+ * Add up:
+ * bytes between indexPtr1 and end of its line
+ * bytes in lines strictly between indexPtr1 and indexPtr2
+ * bytes between start of the indexPtr2 line and indexPtr2
+ */
+
+ segPtr1 = TkTextIndexToSeg(indexPtr1, &offset);
+ byteCount = -offset;
+ for (segPtr = segPtr1; segPtr != NULL; segPtr = segPtr->nextPtr) {
+ byteCount += segPtr->size;
+ }
+
+ linePtr = indexPtr1->linePtr->nextPtr;
+ while (linePtr != indexPtr2->linePtr) {
+ for (segPtr = linePtr->segPtr; segPtr != NULL;
+ segPtr = segPtr->nextPtr) {
+ byteCount += segPtr->size;
+ }
+ linePtr = TkBTreeNextLine(textPtr, linePtr);
+ if (linePtr == NULL) {
+ Tcl_Panic("TextIndexCountBytesOrdered ran out of lines");
+ }
+ }
+
+ byteCount += indexPtr2->byteIndex;
+
+ return byteCount;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
* TkTextIndexCount --
*
* Given an ordered pair of indices in a text widget, this function
diff --git a/generic/tkUndo.c b/generic/tkUndo.c
index a642e72..8359e0a 100644
--- a/generic/tkUndo.c
+++ b/generic/tkUndo.c
@@ -392,7 +392,7 @@ TkUndoSetDepth(
prevelem = elem;
elem = elem->next;
}
- CLANG_ASSERT(prevelem);
+ CLANG_ASSERT(prevelem);
prevelem->next = NULL;
while (elem != NULL) {
prevelem = elem;
diff --git a/generic/ttk/ttkGenStubs.tcl b/generic/ttk/ttkGenStubs.tcl
index 034f405..56ba2fa 100644
--- a/generic/ttk/ttkGenStubs.tcl
+++ b/generic/ttk/ttkGenStubs.tcl
@@ -12,7 +12,7 @@
#
# SOURCE: tcl/tools/genStubs.tcl, revision 1.44
#
-# CHANGES:
+# CHANGES:
# + Second argument to "declare" is used as a status guard
# instead of a platform guard.
# + Allow trailing semicolon in function declarations
@@ -678,7 +678,7 @@ proc genStubs::addGuard {status text} {
set upName [string toupper $libraryName]
switch -- $status {
- current {
+ current {
# No change
}
deprecated {
@@ -691,7 +691,7 @@ proc genStubs::addGuard {status text} {
puts stderr "Unrecognized status code $status"
}
}
- return $text
+ return $text
}
proc genStubs::ifdeffed {macro text} {
diff --git a/generic/ttk/ttkLabel.c b/generic/ttk/ttkLabel.c
index d51388b..1037840 100644
--- a/generic/ttk/ttkLabel.c
+++ b/generic/ttk/ttkLabel.c
@@ -293,6 +293,7 @@ static void ImageCleanup(ImageElement *image)
TtkFreeImageSpec(image->imageSpec);
}
+#ifndef MAC_OSX_TK
/*
* StippleOver --
* Draw a stipple over the image area, to make it look "grayed-out"
@@ -317,6 +318,7 @@ static void StippleOver(
Tk_FreeBitmapFromObj(tkwin, image->stippleObj);
}
}
+#endif
static void ImageDraw(
ImageElement *image, Tk_Window tkwin,Drawable d,Ttk_Box b,Ttk_State state)
diff --git a/library/button.tcl b/library/button.tcl
index 815b137..b2bafb2 100644
--- a/library/button.tcl
+++ b/library/button.tcl
@@ -17,6 +17,7 @@
#-------------------------------------------------------------------------
if {[tk windowingsystem] eq "aqua"} {
+
bind Radiobutton <Enter> {
tk::ButtonEnter %W
}
@@ -143,7 +144,7 @@ bind Radiobutton <Leave> {
if {"win32" eq [tk windowingsystem]} {
#########################
-# Windows implementation
+# Windows implementation
#########################
# ::tk::ButtonEnter --
diff --git a/library/choosedir.tcl b/library/choosedir.tcl
index c0ab326..68dd9b0 100644
--- a/library/choosedir.tcl
+++ b/library/choosedir.tcl
@@ -122,7 +122,7 @@ proc ::tk::dialog::file::chooseDir:: {args} {
# Return value to user
#
-
+
return $Priv(selectFilePath)
}
@@ -164,7 +164,7 @@ proc ::tk::dialog::file::chooseDir::Config {dataName argList} {
if {$data(-title) eq ""} {
set data(-title) "[mc "Choose Directory"]"
}
-
+
# Stub out the -multiple value for the dialog; it doesn't make sense for
# choose directory dialogs, but we have to have something there because we
# share so much code with the file dialogs.
diff --git a/library/clrpick.tcl b/library/clrpick.tcl
index 3772a30..600be16 100644
--- a/library/clrpick.tcl
+++ b/library/clrpick.tcl
@@ -12,7 +12,7 @@
#
# (1): Find out how many free colors are left in the colormap and
# don't allocate too many colors.
-# (2): Implement HSV color selection.
+# (2): Implement HSV color selection.
#
# Make sure namespaces exist
@@ -54,11 +54,11 @@ proc ::tk::dialog::color:: {args} {
set data(BARS_WIDTH) 160
# PLGN_WIDTH is the number of pixels wide of the triangular selection
- # polygon. This also results in the definition of the padding on the
+ # polygon. This also results in the definition of the padding on the
# left and right sides which is half of PLGN_WIDTH. Make this number even.
set data(PLGN_HEIGHT) 10
- # PLGN_HEIGHT is the height of the selection polygon and the height of the
+ # PLGN_HEIGHT is the height of the selection polygon and the height of the
# selection rectangle at the bottom of the color bar. No restrictions.
set data(PLGN_WIDTH) 10
@@ -328,7 +328,7 @@ proc ::tk::dialog::color::BuildDialog {w} {
# Sets the current selection of the dialog box
#
proc ::tk::dialog::color::SetRGBValue {w color} {
- upvar ::tk::dialog::color::[winfo name $w] data
+ upvar ::tk::dialog::color::[winfo name $w] data
set data(red,intensity) [lindex $color 0]
set data(green,intensity) [lindex $color 1]
@@ -368,7 +368,7 @@ proc ::tk::dialog::color::RgbToX {w color} {
}
# ::tk::dialog::color::DrawColorScale --
-#
+#
# Draw color scale is called whenever the size of one of the color
# scale canvases is changed.
#
@@ -507,7 +507,7 @@ proc ::tk::dialog::color::RedrawColorBars {w colorChanged} {
upvar ::tk::dialog::color::[winfo name $w] data
switch $colorChanged {
- red {
+ red {
DrawColorScale $w green
DrawColorScale $w blue
}
@@ -537,7 +537,7 @@ proc ::tk::dialog::color::RedrawColorBars {w colorChanged} {
# Handles a mousedown button event over the selector polygon.
# Adds the bindings for moving the mouse while the button is
# pressed. Sets the binding for the button-release event.
-#
+#
# Params: sel is the selector canvas window, color is the color of the strip.
#
proc ::tk::dialog::color::StartMove {w sel color x delta {dontMove 0}} {
@@ -549,7 +549,7 @@ proc ::tk::dialog::color::StartMove {w sel color x delta {dontMove 0}} {
}
# ::tk::dialog::color::MoveSelector --
-#
+#
# Moves the polygon selector so that its middle point has the same
# x value as the specified x. If x is outside the bounds [0,255],
# the selector is set to the closest endpoint.
@@ -583,7 +583,7 @@ proc ::tk::dialog::color::MoveSelector {w sel color x delta} {
# x is the x-coord of the mouse.
#
proc ::tk::dialog::color::ReleaseMouse {w sel color x delta} {
- upvar ::tk::dialog::color::[winfo name $w] data
+ upvar ::tk::dialog::color::[winfo name $w] data
set x [MoveSelector $w $sel $color $x $delta]
@@ -602,7 +602,7 @@ proc ::tk::dialog::color::ResizeColorBars {w} {
upvar ::tk::dialog::color::[winfo name $w] data
if {
- ($data(BARS_WIDTH) < $data(NUM_COLORBARS)) ||
+ ($data(BARS_WIDTH) < $data(NUM_COLORBARS)) ||
(($data(BARS_WIDTH) % $data(NUM_COLORBARS)) != 0)
} then {
set data(BARS_WIDTH) $data(NUM_COLORBARS)
@@ -660,7 +660,7 @@ proc ::tk::dialog::color::HandleRGBEntry {w} {
SetRGBValue $w "$data(red,intensity) \
$data(green,intensity) $data(blue,intensity)"
-}
+}
# mouse cursor enters a color bar
#
diff --git a/library/comdlg.tcl b/library/comdlg.tcl
index f89754c..18df8a6 100644
--- a/library/comdlg.tcl
+++ b/library/comdlg.tcl
@@ -180,7 +180,7 @@ proc ::tk::FocusGroup_Destroy {t w} {
if {$t eq $w} {
unset Priv(fg,$t)
- unset Priv(focus,$t)
+ unset Priv(focus,$t)
foreach name [array names FocusIn $t,*] {
unset FocusIn($name)
@@ -277,7 +277,7 @@ proc ::tk::FDGetFileTypes {string} {
continue
}
- # Validate each macType. This is to agree with the
+ # Validate each macType. This is to agree with the
# behaviour of TkGetFileFilters(). This list may be
# empty.
foreach macType [lindex $t 2] {
@@ -286,7 +286,7 @@ proc ::tk::FDGetFileTypes {string} {
"bad Macintosh file type \"$macType\""
}
}
-
+
set name "$label \("
set sep ""
set doAppend 1
diff --git a/library/console.tcl b/library/console.tcl
index e93a39d..566140f 100644
--- a/library/console.tcl
+++ b/library/console.tcl
@@ -311,7 +311,7 @@ proc ::tk::ConsoleHistory {cmd} {
# ::tk::ConsolePrompt --
# This procedure draws the prompt. If tcl_prompt1 or tcl_prompt2
-# exists in the main interpreter it will be called to generate the
+# exists in the main interpreter it will be called to generate the
# prompt. Otherwise, a hard coded default prompt is printed.
#
# Arguments:
@@ -781,7 +781,7 @@ proc ::tk::console::TagProc w {
# c2 - second char of pair
#
# Calls: ::tk::console::Blink
-
+
proc ::tk::console::MatchPair {w c1 c2 {lim 1.0}} {
if {!$::tk::console::magicKeys} {
return
@@ -836,7 +836,7 @@ proc ::tk::console::MatchPair {w c1 c2 {lim 1.0}} {
# w - console text widget
#
# Calls: ::tk::console::Blink
-
+
proc ::tk::console::MatchQuote {w {lim 1.0}} {
if {!$::tk::console::magicKeys} {
return
@@ -971,7 +971,7 @@ proc ::tk::console::Expand {w {type ""}} {
#
# Returns: list containing longest unique match followed by all the
# possible further matches
-
+
proc ::tk::console::ExpandPathname str {
set pwd [EvalAttached pwd]
if {[catch {EvalAttached [list cd [file dirname $str]]} err opt]} {
diff --git a/library/dialog.tcl b/library/dialog.tcl
index 6a9babb..22c4dd3 100644
--- a/library/dialog.tcl
+++ b/library/dialog.tcl
@@ -149,7 +149,7 @@ proc ::tk_dialog {w title text bitmap default args} {
# so we know how big it wants to be, then center the window in the
# display (Motif style) and de-iconify it.
- ::tk::PlaceWindow $w
+ ::tk::PlaceWindow $w
tkwait visibility $w
# 7. Set a grab and claim the focus too.
diff --git a/library/entry.tcl b/library/entry.tcl
index f28547e..c8422dc 100644
--- a/library/entry.tcl
+++ b/library/entry.tcl
@@ -69,8 +69,8 @@ bind Entry <<PasteSelection>> {
}
bind Entry <<TraverseIn>> {
- %W selection range 0 end
- %W icursor end
+ %W selection range 0 end
+ %W icursor end
}
# Standard Motif bindings:
diff --git a/library/fontchooser.tcl b/library/fontchooser.tcl
index 8b3f87e..8f91ade 100644
--- a/library/fontchooser.tcl
+++ b/library/fontchooser.tcl
@@ -105,7 +105,7 @@ proc ::tk::fontchooser::Configure {args} {
"bad option \"$option\": must be\
-command, -font, -parent, -title or -visible"
}
-
+
set cache [dict create -parent $S(-parent) -title $S(-title) \
-font $S(-font) -command $S(-command)]
set r [tclParseConfigSpec [namespace which -variable S] $specs "" $args]
diff --git a/library/mkpsenc.tcl b/library/mkpsenc.tcl
index 50224eb..b3fd13d 100644
--- a/library/mkpsenc.tcl
+++ b/library/mkpsenc.tcl
@@ -1163,11 +1163,11 @@ namespace eval ::tk {
0 exch 0 exch
{
dup type /stringtype eq
- { stringwidth } {
+ { stringwidth } {
currentfont /Encoding get exch 1 exch put (\001)
- stringwidth
+ stringwidth
}
- ifelse
+ ifelse
exch 3 1 roll add 3 1 roll add exch
} forall
}
diff --git a/library/msgbox.tcl b/library/msgbox.tcl
index 10e91f1..939928d 100644
--- a/library/msgbox.tcl
+++ b/library/msgbox.tcl
@@ -137,7 +137,7 @@ proc ::tk::MessageBox {args} {
#
# The default value of the title is space (" ") not the empty string
- # because for some window managers, a
+ # because for some window managers, a
# wm title .foo ""
# causes the window title to be "foo" instead of the empty string.
#
@@ -175,7 +175,7 @@ proc ::tk::MessageBox {args} {
}
switch -- $data(-type) {
- abortretryignore {
+ abortretryignore {
set names [list abort retry ignore]
set labels [list &Abort &Retry &Ignore]
set cancel abort
@@ -218,7 +218,7 @@ proc ::tk::MessageBox {args} {
lappend buttons [list $name -text [mc $lab]]
}
- # If no default button was specified, the default default is the
+ # If no default button was specified, the default default is the
# first button (Bug: 2218).
if {$data(-default) eq ""} {
diff --git a/library/palette.tcl b/library/palette.tcl
index 924dd61..9cecf5b 100644
--- a/library/palette.tcl
+++ b/library/palette.tcl
@@ -100,7 +100,7 @@ proc ::tk_setPalette {args} {
set new(troughColor) $darkerBg
}
- # let's make one of each of the widgets so we know what the
+ # let's make one of each of the widgets so we know what the
# defaults are currently for this platform.
toplevel .___tk_set_palette
wm withdraw .___tk_set_palette
@@ -113,12 +113,12 @@ proc ::tk_setPalette {args} {
}
# Walk the widget hierarchy, recoloring all existing windows.
- # The option database must be set according to what we do here,
- # but it breaks things if we set things in the database while
+ # The option database must be set according to what we do here,
+ # but it breaks things if we set things in the database while
# we are changing colors...so, ::tk::RecolorTree now returns the
# option database changes that need to be made, and they
# need to be evalled here to take effect.
- # We have to walk the whole widget tree instead of just
+ # We have to walk the whole widget tree instead of just
# relying on the widgets we've created above to do the work
# because different extensions may provide other kinds
# of widgets that we don't currently know about, so we'll
@@ -144,7 +144,7 @@ proc ::tk_setPalette {args} {
# ::tk::RecolorTree --
# This procedure changes the colors in a window and all of its
# descendants, according to information provided by the colors
-# argument. This looks at the defaults provided by the option
+# argument. This looks at the defaults provided by the option
# database, if it exists, and if not, then it looks at the default
# value of the widget itself.
#
diff --git a/library/scrlbar.tcl b/library/scrlbar.tcl
index 1f8c7d2..e17442f 100644
--- a/library/scrlbar.tcl
+++ b/library/scrlbar.tcl
@@ -15,7 +15,7 @@
#-------------------------------------------------------------------------
# Standard Motif bindings:
-if {[tk windowingsystem] eq "x11"} {
+if {[tk windowingsystem] eq "x11" || [tk windowingsystem] eq "aqua"} {
bind Scrollbar <Enter> {
if {$tk_strictMotif} {
diff --git a/library/spinbox.tcl b/library/spinbox.tcl
index 641584d..4d94420 100644
--- a/library/spinbox.tcl
+++ b/library/spinbox.tcl
@@ -74,8 +74,8 @@ bind Spinbox <<PasteSelection>> {
}
bind Spinbox <<TraverseIn>> {
- %W selection range 0 end
- %W icursor end
+ %W selection range 0 end
+ %W icursor end
}
# Standard Motif bindings:
diff --git a/library/tearoff.tcl b/library/tearoff.tcl
index 6da2a0f..b500023 100644
--- a/library/tearoff.tcl
+++ b/library/tearoff.tcl
@@ -150,7 +150,7 @@ proc ::tk::MenuDup {src dst type} {
set tags [bindtags $src]
set srcLen [string length $src]
-
+
# Copy tags to x, replacing each substring of src with dst.
while {[set index [string first $src $tags]] != -1} {
diff --git a/library/tk.tcl b/library/tk.tcl
index b7d85c4..da619e6 100644
--- a/library/tk.tcl
+++ b/library/tk.tcl
@@ -13,7 +13,7 @@
# Insist on running with compatible version of Tcl
package require Tcl 8.6
# Verify that we have Tk binary and script components from the same release
-package require -exact Tk 8.6.3
+package require -exact Tk 8.6.4
# Create a ::tk namespace
namespace eval ::tk {
@@ -302,7 +302,7 @@ tk::ScreenChanged [winfo screen .]
proc ::tk::EventMotifBindings {n1 dummy dummy} {
upvar $n1 name
-
+
if {$name} {
set op delete
} else {
@@ -328,7 +328,7 @@ proc ::tk::EventMotifBindings {n1 dummy dummy} {
}
#----------------------------------------------------------------------
-# Define common dialogs on platforms where they are not implemented
+# Define common dialogs on platforms where they are not implemented
# using compiled code.
#----------------------------------------------------------------------
@@ -543,7 +543,7 @@ proc ::tk::CancelRepeat {} {
# ::tk::TabToWindow --
# This procedure moves the focus to the given widget.
-# It sends a <<TraverseOut>> virtual event to the previous focus window,
+# It sends a <<TraverseOut>> virtual event to the previous focus window,
# if any, before changing the focus, and a <<TraverseIn>> event
# to the new focus window afterwards.
#
@@ -571,7 +571,7 @@ proc ::tk::UnderlineAmpersand {text} {
return [list [string map {\ufeff {}} $s] $idx]
}
-# ::tk::SetAmpText --
+# ::tk::SetAmpText --
# Given widget path and text with "magic ampersands", sets -text and
# -underline options for the widget
#
diff --git a/library/unsupported.tcl b/library/unsupported.tcl
index 2c68e78..b5f404a 100644
--- a/library/unsupported.tcl
+++ b/library/unsupported.tcl
@@ -16,7 +16,7 @@ namespace eval ::tk::unsupported {
# Map from the old global names of Tk private commands to their
# new namespace-encapsulated names.
- variable PrivateCommands
+ variable PrivateCommands
array set PrivateCommands {
tkButtonAutoInvoke ::tk::ButtonAutoInvoke
tkButtonDown ::tk::ButtonDown
diff --git a/library/xmfbox.tcl b/library/xmfbox.tcl
index 0578361..aa66f7f 100644
--- a/library/xmfbox.tcl
+++ b/library/xmfbox.tcl
@@ -27,7 +27,7 @@ namespace eval ::tk::dialog::file {}
# When -multiple is set to 0, this returns the absolute pathname
# of the selected file. (NOTE: This is not the same as a single
# element list.)
-#
+#
# When -multiple is set to > 0, this returns a Tcl list of absolute
# pathnames. The argument for -multiple is ignored, but for consistency
# with Windows it defines the maximum amount of memory to allocate for
@@ -505,7 +505,7 @@ proc ::tk::MotifFDialog_InterpFilter {w} {
if {[file pathtype $text] eq "relative"} {
set relative 1
} elseif {$badTilde} {
- set relative 1
+ set relative 1
}
if {$relative} {
@@ -552,7 +552,7 @@ proc ::tk::MotifFDialog_Update {w} {
$data(sEnt) delete 0 end
$data(sEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
$data(selectFile)]
-
+
MotifFDialog_LoadFiles $w
}
@@ -626,7 +626,7 @@ proc ::tk::MotifFDialog_LoadFiles {w} {
# w The pathname of the dialog box.
#
# Results:
-# None.
+# None.
proc ::tk::MotifFDialog_BrowseDList {w} {
upvar ::tk::dialog::file::[winfo name $w] data
@@ -672,7 +672,7 @@ proc ::tk::MotifFDialog_BrowseDList {w} {
# w The pathname of the dialog box.
#
# Results:
-# None.
+# None.
proc ::tk::MotifFDialog_ActivateDList {w} {
upvar ::tk::dialog::file::[winfo name $w] data
@@ -720,7 +720,7 @@ proc ::tk::MotifFDialog_ActivateDList {w} {
# w The pathname of the dialog box.
#
# Results:
-# None.
+# None.
proc ::tk::MotifFDialog_BrowseFList {w} {
upvar ::tk::dialog::file::[winfo name $w] data
@@ -740,9 +740,9 @@ proc ::tk::MotifFDialog_BrowseFList {w} {
$data(fEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
$data(filter)]
$data(fEnt) xview end
-
- # if it's a multiple selection box, just put in the filenames
- # otherwise put in the full path as usual
+
+ # if it's a multiple selection box, just put in the filenames
+ # otherwise put in the full path as usual
$data(sEnt) delete 0 end
if {$data(-multiple) != 0} {
$data(sEnt) insert 0 $data(selectFile)
@@ -762,7 +762,7 @@ proc ::tk::MotifFDialog_BrowseFList {w} {
# w The pathname of the dialog box.
#
# Results:
-# None.
+# None.
proc ::tk::MotifFDialog_ActivateFList {w} {
upvar ::tk::dialog::file::[winfo name $w] data
@@ -788,7 +788,7 @@ proc ::tk::MotifFDialog_ActivateFList {w} {
# w The pathname of the dialog box.
#
# Results:
-# None.
+# None.
proc ::tk::MotifFDialog_ActivateFEnt {w} {
upvar ::tk::dialog::file::[winfo name $w] data
@@ -803,7 +803,7 @@ proc ::tk::MotifFDialog_ActivateFEnt {w} {
# ::tk::MotifFDialog_ActivateSEnt --
#
# This procedure is called when the user presses Return inside
-# the "selection" entry. It sets the ::tk::Priv(selectFilePath)
+# the "selection" entry. It sets the ::tk::Priv(selectFilePath)
# variable so that the vwait loop in tk::MotifFDialog will be
# terminated.
#
@@ -811,7 +811,7 @@ proc ::tk::MotifFDialog_ActivateFEnt {w} {
# w The pathname of the dialog box.
#
# Results:
-# None.
+# None.
proc ::tk::MotifFDialog_ActivateSEnt {w} {
variable ::tk::Priv
@@ -930,7 +930,7 @@ proc ::tk::ListBoxKeyAccel_Unset {w} {
# key The key which the user just pressed.
#
# Results:
-# None.
+# None.
proc ::tk::ListBoxKeyAccel_Key {w key} {
variable ::tk::Priv
diff --git a/macosx/GNUmakefile b/macosx/GNUmakefile
index 333961c..02240ed 100644
--- a/macosx/GNUmakefile
+++ b/macosx/GNUmakefile
@@ -134,7 +134,7 @@ endif
INSTALL_TARGETS = install-binaries install-libraries
ifeq (${EMBEDDED_BUILD},)
-INSTALL_TARGETS += install-private-headers install-demos
+INSTALL_TARGETS += install-private-headers install-headers install-demos
endif
ifeq (${INSTALL_BUILD}_${EMBEDDED_BUILD}_${BUILD_STYLE},1__Deployment)
INSTALL_TARGETS += html-tk
diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c
index d4aae8d..5c5aa9e 100644
--- a/macosx/tkMacOSXButton.c
+++ b/macosx/tkMacOSXButton.c
@@ -5,12 +5,15 @@
* button widgets.
*
* Copyright (c) 1996-1997 by Sun Microsystems, Inc.
- * Copyright 2001-2009, Apple Inc.
- * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
- * Copyright 2014 Marc Culler.
+ * Copyright 2001, Apple Computer, Inc.
+ * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2007 Revar Desmera.
+ * Copyright 2015 Kevin Walzer/WordTech Communications LLC.
+ * Copyright 2015 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
*/
#include "tkMacOSXPrivate.h"
@@ -18,118 +21,82 @@
#include "tkMacOSXFont.h"
#include "tkMacOSXDebug.h"
-/*
-#ifdef TK_MAC_DEBUG
-#define TK_MAC_DEBUG_BUTTON
-#endif
-*/
-static NSRect TkMacOSXGetButtonFrame(TkButton *butPtr);
+#define FIRST_DRAW 2
+#define ACTIVE 4
+
/*
- * A subclass of NSButton with sanity checking:
- * NSButtons created by Tk will have their tag set to a pointer to the TkButton
- * which manages the NSButton. This allows a TkNSButton to be aware of the
- * state of its Tk parent. This subclass overrides the drawRect method
- * so that it will not draw itself unless the NSButton frame matches
- * the frame which was installed by DisplayButton, and the TkButton is
- * mapped. Also, it will not draw anything if the widget is completely
- * outside of its container.
+ * Default insets for controls
*/
-@interface TkNSButton: NSButton
-
-@end
-
-@implementation TkNSButton
-
- - (void)drawRect:(NSRect)dirtyRect
- {
- NSInteger tag = [self tag];
- if ( tag != -1) {
- TkButton *butPtr = (TkButton *)tag;
- MacDrawable* macWin = (MacDrawable *)butPtr;
- NSRect Tkframe = TkMacOSXGetButtonFrame(butPtr);
- Tk_Window tkwin = butPtr->tkwin;
- /* Do not draw if the widget is misplaced or unmapped. */
- if ( NSIsEmptyRect(Tkframe) ||
- ! macWin->winPtr->flags & TK_MAPPED ||
- ! NSEqualRects(Tkframe, [self frame])
- ) {
- return;
- }
- /* Do not draw if the widget is completely outside of its parent, or within 20 pixels of the lower border; this prevents buttons from being drawn on peer widgets as scrolling occurs. */
- if (tkwin) {
- int parent_height = Tk_Height(Tk_Parent(tkwin));
- int widget_height = Tk_Height(tkwin);
- int y = Tk_Y(tkwin);
- if ( y > parent_height - 20 || y + widget_height < 0 ) {
- return;
- }
+#define DEF_INSET_LEFT 2
+#define DEF_INSET_RIGHT 2
+#define DEF_INSET_TOP 2
+#define DEF_INSET_BOTTOM 4
- /* Do not draw if the widget is completely outside of its parent, or within 50 pixels of the right border; this prevents buttons from being drawn on peer widgets as scrolling occurs. */
- int parent_width = Tk_Width(Tk_Parent(tkwin));
- int widget_width = Tk_Width(tkwin);
- int x = Tk_X(tkwin);
- if (x > parent_width - 50 || x < 0) {
- return;
- }
- }
- [super drawRect:dirtyRect];
- }
- }
+/*
+ * Some defines used to control what type of control is drawn.
+ */
-@end
+#define DRAW_LABEL 0 /* Labels are treated genericly. */
+#define DRAW_CONTROL 1 /* Draw using the Native control. */
+#define DRAW_CUSTOM 2 /* Make our own button drawing. */
+#define DRAW_BEVEL 3
+/*
+ * The delay in milliseconds between pulsing default button redraws.
+ */
+#define PULSE_TIMER_MSECS 62 /* Largest value that didn't look stuttery */
-typedef struct MacButton {
- TkButton info;
- TkNSButton *button;
- NSImage *image, *selectImage, *tristateImage;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- int fix;
-#endif
-} MacButton;
+/*
+ * Declaration of Mac specific button structure.
+ */
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-int tkMacOSXUseCompatibilityMetrics = 1;
+typedef struct {
+ int drawType;
+ Tk_3DBorder border;
+ int relief;
+ int offset; /* 0 means this is a normal widget. 1 means
+ * it is an image button, so we offset the
+ * image to make the button appear to move
+ * up and down as the relief changes. */
+ GC gc;
+ int hasImageOrBitmap;
+} DrawParams;
+
+typedef struct {
+ TkButton info; /* Generic button info */
+ int id;
+ int usingControl;
+ int useTkText;
+ int flags; /* Initialisation status */
+ ThemeButtonKind btnkind;
+ HIThemeButtonDrawInfo drawinfo;
+ HIThemeButtonDrawInfo lastdrawinfo;
+ DrawParams drawParams;
+ Tcl_TimerToken defaultPulseHandler;
+} MacButton;
/*
- * Use the following heuristic conversion constants to make NSButton-based
- * widget metrics match up with the old Carbon control buttons (for the
- * default Lucida Grande 13 font).
+ * Forward declarations for procedures defined later in this file:
*/
-#define NATIVE_BUTTON_INSET 2
-#define NATIVE_BUTTON_EXTRA_H 2
-typedef struct {
- int trimW, trimH, inset, shrinkH, offsetX, offsetY;
-} BoundsFix;
-
-#define fixForTypeStyle(type, style) ( \
- type == NSSwitchButton ? 0 : \
- type == NSRadioButton ? 1 : \
- style == NSRoundedBezelStyle ? 2 : \
- style == NSRegularSquareBezelStyle ? 3 : \
- style == NSShadowlessSquareBezelStyle ? 4 : \
- INT_MIN)
-
-static const BoundsFix boundsFixes[] = {
- [fixForTypeStyle(NSSwitchButton,0)] = { 2, 2, -1, 0, 2, 1 },
- [fixForTypeStyle(NSRadioButton,0)] = { 0, 2, -1, 0, 1, 1 },
- [fixForTypeStyle(0,NSRoundedBezelStyle)] = { 28, 16, -6, 0, 0, 3 },
- [fixForTypeStyle(0,NSRegularSquareBezelStyle)] = { 28, 15, -2, -1 },
- [fixForTypeStyle(0,NSShadowlessSquareBezelStyle)] = { 2, 2 },
-};
-
-#endif
+static void ButtonBackgroundDrawCB (const HIRect *btnbounds, MacButton *ptr,
+ SInt16 depth, Boolean isColorDev);
+static void ButtonContentDrawCB (const HIRect *bounds, ThemeButtonKind kind,
+ const HIThemeButtonDrawInfo *info, MacButton *ptr, SInt16 depth,
+ Boolean isColorDev);
+static void ButtonEventProc(ClientData clientData, XEvent *eventPtr);
+static void TkMacOSXComputeButtonParams (TkButton * butPtr, ThemeButtonKind* btnkind,
+ HIThemeButtonDrawInfo* drawinfo);
+static int TkMacOSXComputeButtonDrawParams (TkButton * butPtr, DrawParams * dpPtr);
+static void TkMacOSXDrawButton (MacButton *butPtr, GC gc, Pixmap pixmap);
+static void DrawButtonImageAndText(TkButton* butPtr);
+static void PulseDefaultButtonProc(ClientData clientData);
-static void DisplayNativeButton(TkButton *butPtr);
-static void ComputeNativeButtonGeometry(TkButton *butPtr);
-static void DisplayUnixButton(TkButton *butPtr);
-static void ComputeUnixButtonGeometry(TkButton *butPtr);
/*
* The class procedure table for the button widgets.
@@ -138,68 +105,67 @@ static void ComputeUnixButtonGeometry(TkButton *butPtr);
const Tk_ClassProcs tkpButtonProcs = {
sizeof(Tk_ClassProcs), /* size */
TkButtonWorldChanged, /* worldChangedProc */
- NULL, /* createProc */
- NULL /* modalProc */
};
-
+static int bCount;
+
/*
*----------------------------------------------------------------------
*
- * TkpCreateButton --
+ * TkpButtonSetDefaults --
*
- * Allocate a new TkButton structure.
+ * This procedure is invoked before option tables are created for
+ * buttons. It modifies some of the default values to match the current
+ * values defined for this platform.
*
* Results:
- * Returns a newly allocated TkButton structure.
+ * Some of the default values in *specPtr are modified.
*
* Side effects:
- * Registers an event handler for the widget.
+ * Updates some of.
*
*----------------------------------------------------------------------
*/
-TkButton *
-TkpCreateButton(
- Tk_Window tkwin)
+void
+TkpButtonSetDefaults()
{
- MacButton *macButtonPtr = ckalloc(sizeof(MacButton));
-
- macButtonPtr->button = nil;
- macButtonPtr->image = nil;
- macButtonPtr->selectImage = nil;
- macButtonPtr->tristateImage = nil;
-
- return (TkButton *) macButtonPtr;
+/*No-op.*/
}
+
/*
*----------------------------------------------------------------------
*
- * TkpDestroyButton --
+ * TkpCreateButton --
*
- * Free data structures associated with the button control.
+ * Allocate a new TkButton structure.
*
* Results:
- * None.
+ * Returns a newly allocated TkButton structure.
*
* Side effects:
- * Restores the default control state.
+ * Registers an event handler for the widget.
*
*----------------------------------------------------------------------
*/
-void
-TkpDestroyButton(
- TkButton *butPtr)
+TkButton *
+TkpCreateButton(
+ Tk_Window tkwin)
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
- [macButtonPtr->button setTag:(NSInteger)-1];
-
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->button);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->image);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->selectImage);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->tristateImage);
+ MacButton *macButtonPtr = (MacButton *) ckalloc(sizeof(MacButton));
+
+ Tk_CreateEventHandler(tkwin, ActivateMask,
+ ButtonEventProc, (ClientData) macButtonPtr);
+ macButtonPtr->id = bCount++;
+ macButtonPtr->flags = FIRST_DRAW;
+ macButtonPtr->btnkind = kThemePushButton;
+ macButtonPtr->defaultPulseHandler = NULL;
+ bzero(&macButtonPtr->drawinfo, sizeof(macButtonPtr->drawinfo));
+ bzero(&macButtonPtr->lastdrawinfo, sizeof(macButtonPtr->lastdrawinfo));
+
+ return (TkButton *)macButtonPtr;
}
/*
@@ -224,1090 +190,1021 @@ void
TkpDisplayButton(
ClientData clientData) /* Information about widget. */
{
+ MacButton *macButtonPtr = (MacButton *) clientData;
TkButton *butPtr = (TkButton *) clientData;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ DrawParams* dpPtr = &macButtonPtr->drawParams;
+ int needhighlight = 0;
butPtr->flags &= ~REDRAW_PENDING;
- if (!butPtr->tkwin || !Tk_IsMapped(butPtr->tkwin)) {
+ if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
return;
}
+ pixmap = (Pixmap) Tk_WindowId(tkwin);
+ TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin));
- switch (butPtr->type) {
- case TYPE_LABEL:
- DisplayUnixButton(butPtr);
- break;
- case TYPE_BUTTON:
- case TYPE_CHECK_BUTTON:
- case TYPE_RADIO_BUTTON:
- DisplayNativeButton(butPtr);
- break;
+ if (TkMacOSXComputeButtonDrawParams(butPtr, dpPtr) ) {
+ macButtonPtr->useTkText = 0;
+ } else {
+ macButtonPtr->useTkText = 1;
+ }
+
+
+ /*
+ * Set up clipping region. Make sure the we are using the port
+ * for this button, or we will set the wrong window's clip.
+ */
+
+ if (macButtonPtr->useTkText) {
+ if (butPtr->type == TYPE_BUTTON) {
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+ } else {
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+ }
+
+ /* Display image or bitmap or text for labels or custom controls. */
+ DrawButtonImageAndText(butPtr);
+ needhighlight = 1;
+ } else {
+ /* Draw the native portion of the buttons. */
+ TkMacOSXDrawButton(macButtonPtr, dpPtr->gc, pixmap);
+
+ /* Draw highlight border, if needed. */
+ if (butPtr->highlightWidth < 3) {
+ needhighlight = 1;
+ }
+ }
+
+ /* Draw highlight border, if needed. */
+ if (needhighlight) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ Tk_Draw3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin),
+ butPtr->highlightWidth, TK_RELIEF_SOLID);
+ }
}
}
/*
*----------------------------------------------------------------------
*
- * TkpShiftButton --
+ * TkpComputeButtonGeometry --
*
- * Moves the frame of an NSButton (or TkNSButton) and in case the tag is
- * set, also adjusts the xOff and yOff of the controlling TkButton's
- * MacDrawable. This is used to avoid jitter when scrolling.
+ * After changes in a button's text or bitmap, this procedure
+ * recomputes the button's geometry and passes this information
+ * along to the geometry manager for the window.
*
* Results:
- * None
+ * None.
*
* Side effects:
- * Moves the NSbutton after adjusting the associated MacDrawable.
+ * The button's window may change size.
*
*----------------------------------------------------------------------
*/
+
void
-TkpShiftButton(
- NSButton *button,
- NSPoint delta )
- {
- NSPoint origin = [button frame].origin;
- NSInteger tag = [button tag];
- if ( tag != -1) {
- TkButton* butPtr = (TkButton *)tag;
- TkWindow *winPtr = (TkWindow *) (butPtr->tkwin);
- if (winPtr) {
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
- macWin->xOff += delta.x;
- macWin->yOff += delta.y;
- }
+TkpComputeButtonGeometry(
+ TkButton *butPtr) /* Button whose geometry may have changed. */
+{
+ int width = 0, height = 0, charWidth = 1, haveImage = 0, haveText = 0;
+ int txtWidth = 0, txtHeight = 0;
+ MacButton *mbPtr = (MacButton*)butPtr;
+ Tk_FontMetrics fm;
+ DrawParams drawParams;
+
+ /*
+ * First figure out the size of the contents of the button.
+ */
+
+ TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
+
+ /*
+ * If the indicator is on, get its size.
+ */
+
+ if ( butPtr->indicatorOn ) {
+ switch (butPtr->type) {
+ case TYPE_RADIO_BUTTON:
+ GetThemeMetric(kThemeMetricRadioButtonWidth, &butPtr->indicatorDiameter);
+ break;
+ case TYPE_CHECK_BUTTON:
+ GetThemeMetric(kThemeMetricCheckBoxWidth, &butPtr->indicatorDiameter);
+ break;
+ default:
+ break;
+ }
+ /* Allow 2px extra space next to the indicator. */
+ butPtr->indicatorSpace = butPtr->indicatorDiameter + 2;
+ } else {
+ butPtr->indicatorSpace = 0;
+ butPtr->indicatorDiameter = 0;
+ }
+
+ if (butPtr->image != NULL) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
+ }
+
+ if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
+ Tk_FreeTextLayout(butPtr->textLayout);
+ butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
+ Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength,
+ butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
+
+ txtWidth = butPtr->textWidth;
+ txtHeight = butPtr->textHeight;
+ charWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
+ Tk_GetFontMetrics(butPtr->tkfont, &fm);
+ haveText = (txtWidth != 0 && txtHeight != 0);
+ }
+
+ if (haveImage && haveText) { /* Image and Text */
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM:
+ /*
+ * Image is above or below text.
+ */
+
+ height += txtHeight + butPtr->padY;
+ width = (width > txtWidth ? width : txtWidth);
+ break;
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT:
+ /*
+ * Image is left or right of text.
+ */
+
+ width += txtWidth + butPtr->padX;
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ case COMPOUND_CENTER:
+ /*
+ * Image and text are superimposed.
+ */
+
+ width = (width > txtWidth ? width : txtWidth);
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ default:
+ break;
+ }
+ width += butPtr->indicatorSpace;
+
+ } else if (haveImage) { /* Image only */
+ width = butPtr->width > 0 ? butPtr->width : width + butPtr->indicatorSpace;
+ height = butPtr->height > 0 ? butPtr->height : height;
+
+ } else { /* Text only */
+ width = txtWidth + butPtr->indicatorSpace;
+ height = txtHeight;
+ if (butPtr->width > 0) {
+ width = butPtr->width * charWidth;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height * fm.linespace;
}
- origin.x += delta.x;
- origin.y -= delta.y;
- [button setFrameOrigin:origin];
}
-
+ /* Add padding */
+ width += 2 * butPtr->padX;
+ height += 2 * butPtr->padY;
+
+ /*
+ * Now figure out the size of the border decorations for the button.
+ */
+
+ if (butPtr->highlightWidth < 0) {
+ butPtr->highlightWidth = 0;
+ }
+
+ butPtr->inset = 0;
+ butPtr->inset += butPtr->highlightWidth;
+
+ if (TkMacOSXComputeButtonDrawParams(butPtr,&drawParams)) {
+ HIRect tmpRect;
+ HIRect contBounds;
+ int paddingx = 0;
+ int paddingy = 0;
+
+ tmpRect = CGRectMake(0, 0, width, height);
+
+ HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds);
+ /* If the content region has a minimum height, match it. */
+ if (height < contBounds.size.height) {
+ height = contBounds.size.height;
+ }
+
+ /* If the content region has a minimum width, match it. */
+ if (width < contBounds.size.width) {
+ width = contBounds.size.width;
+ }
+
+ /* Pad to fill difference between content bounds and button bounds. */
+ paddingx = contBounds.origin.x;
+ paddingy = contBounds.origin.y;
+
+ if (height < paddingx - 4) {
+ /* can't have buttons much shorter than button side diameter. */
+ height = paddingx - 4;
+ }
+
+ } else {
+ height += butPtr->borderWidth*2;
+ width += butPtr->borderWidth*2;
+ }
+
+ width += butPtr->inset*2;
+ height += butPtr->inset*2;
+
+ Tk_GeometryRequest(butPtr->tkwin, width, height);
+ Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
+}
+
/*
*----------------------------------------------------------------------
*
- * TkpComputeButtonGeometry --
+ * DrawButtonImageAndText --
*
- * After changes in a button's text or bitmap, this procedure
- * recomputes the button's geometry and passes this information
- * along to the geometry manager for the window.
+ * Draws the image and text associated with a button or label.
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * The button's window may change size.
+ * The image and text are drawn.
*
*----------------------------------------------------------------------
*/
-
-void
-TkpComputeButtonGeometry(
- register TkButton *butPtr) /* Button whose geometry may have changed. */
+static void
+DrawButtonImageAndText(
+ TkButton* butPtr)
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
- switch (butPtr->type) {
- case TYPE_LABEL:
- if (macButtonPtr->button && [macButtonPtr->button superview]) {
- [macButtonPtr->button removeFromSuperviewWithoutNeedingDisplay];
+ MacButton *mbPtr = (MacButton*)butPtr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ int haveImage = 0;
+ int haveText = 0;
+ int imageWidth = 0;
+ int imageHeight = 0;
+ int imageXOffset = 0;
+ int imageYOffset = 0;
+ int textXOffset = 0;
+ int textYOffset = 0;
+ int width = 0;
+ int height = 0;
+ int fullWidth = 0;
+ int fullHeight = 0;
+ int pressed = 0;
+
+
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
+ }
+
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+ if (butPtr->image != None) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
+ }
+
+ imageWidth = width;
+ imageHeight = height;
+
+ if (mbPtr->drawinfo.state == kThemeStatePressed) {
+ /* Offset bitmaps by a bit when the button is pressed. */
+ pressed = 1;
+ }
+
+ haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
+ if (haveImage && haveText) { /* Image and Text */
+ int x;
+ int y;
+ textXOffset = 0;
+ textYOffset = 0;
+ fullWidth = 0;
+ fullHeight = 0;
+
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM: {
+ /* Image is above or below text */
+ if (butPtr->compound == COMPOUND_TOP) {
+ textYOffset = height + butPtr->padY;
+ } else {
+ imageYOffset = butPtr->textHeight + butPtr->padY;
+ }
+ fullHeight = height + butPtr->textHeight + butPtr->padY;
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ break;
}
- ComputeUnixButtonGeometry(butPtr);
- break;
- case TYPE_BUTTON:
- case TYPE_CHECK_BUTTON:
- case TYPE_RADIO_BUTTON:
- if (!macButtonPtr->button) {
- TkNSButton *button = [[TkNSButton alloc] initWithFrame:NSZeroRect];
- [button setTag:(NSInteger)butPtr];
- macButtonPtr->button = TkMacOSXMakeUncollectable(button);
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT: {
+ /*
+ * Image is left or right of text
+ */
+
+ if (butPtr->compound == COMPOUND_LEFT) {
+ textXOffset = width + butPtr->padX;
+ } else {
+ imageXOffset = butPtr->textWidth + butPtr->padX;
+ }
+ fullWidth = butPtr->textWidth + butPtr->padX + width;
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
}
- ComputeNativeButtonGeometry(butPtr);
- break;
+ case COMPOUND_CENTER: {
+ /*
+ * Image and text are superimposed
+ */
+
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
+ }
+ default:
+ break;
+ }
+
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ fullWidth + butPtr->indicatorSpace, fullHeight, &x, &y);
+ x += butPtr->indicatorSpace;
+
+ if (dpPtr->relief == TK_RELIEF_SUNKEN) {
+ x += dpPtr->offset;
+ y += dpPtr->offset;
+ } else if (dpPtr->relief == TK_RELIEF_RAISED) {
+ x -= dpPtr->offset;
+ y -= dpPtr->offset;
+ }
+ if (pressed) {
+ x += dpPtr->offset;
+ y += dpPtr->offset;
+ }
+ imageXOffset += x;
+ imageYOffset += y;
+ textYOffset -= 1;
+
+ if (butPtr->image != NULL) {
+ if ((butPtr->selectImage != NULL) &&
+ (butPtr->flags & SELECTED)) {
+ Tk_RedrawImage(butPtr->selectImage, 0, 0,
+ width, height, pixmap, imageXOffset, imageYOffset);
+ } else if ((butPtr->tristateImage != NULL) &&
+ (butPtr->flags & TRISTATED)) {
+ Tk_RedrawImage(butPtr->tristateImage, 0, 0,
+ width, height, pixmap, imageXOffset, imageYOffset);
+ } else {
+ Tk_RedrawImage(butPtr->image, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ }
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc,
+ imageXOffset, imageYOffset);
+ XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width, (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+
+ Tk_DrawTextLayout(butPtr->display, pixmap,
+ dpPtr->gc, butPtr->textLayout,
+ x + textXOffset, y + textYOffset, 0, -1);
+ Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout,
+ x + textXOffset, y + textYOffset,
+ butPtr->underline);
+ } else if (haveImage) { /* Image only */
+ int x = 0;
+ int y;
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ width + butPtr->indicatorSpace,
+ height, &x, &y);
+ x += butPtr->indicatorSpace;
+ if (pressed) {
+ x += dpPtr->offset;
+ y += dpPtr->offset;
+ }
+ imageXOffset += x;
+ imageYOffset += y;
+
+ if (butPtr->image != NULL) {
+
+ if ((butPtr->selectImage != NULL) &&
+ (butPtr->flags & SELECTED)) {
+ Tk_RedrawImage(butPtr->selectImage, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ } else if ((butPtr->tristateImage != NULL) &&
+ (butPtr->flags & TRISTATED)) {
+ Tk_RedrawImage(butPtr->tristateImage, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ } else {
+ Tk_RedrawImage(butPtr->image, 0, 0, width, height,
+ pixmap, imageXOffset, imageYOffset);
+ }
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc, x, y);
+ XCopyPlane(butPtr->display, butPtr->bitmap,
+ pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width,
+ (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+ } else { /* Text only */
+ int x, y;
+ TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
+ butPtr->textWidth + butPtr->indicatorSpace,
+ butPtr->textHeight, &x, &y);
+ x += butPtr->indicatorSpace;
+ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout,
+ x, y, 0, -1);
}
-}
-
+
+ /*
+ * If the button is disabled with a stipple rather than a special
+ * foreground color, generate the stippled effect. If the widget
+ * is selected and we use a different background color when selected,
+ * must temporarily modify the GC so the stippling is the right color.
+ */
+
+ if (mbPtr->useTkText) {
+ if ((butPtr->state == STATE_DISABLED)
+ && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) {
+ if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
+ && (butPtr->selectBorder != NULL)) {
+ XSetForeground(butPtr->display, butPtr->stippleGC,
+ Tk_3DBorderColor(butPtr->selectBorder)->pixel);
+ }
+ /*
+ * Stipple the whole button if no disabledFg was specified,
+ * otherwise restrict stippling only to displayed image
+ */
+ if (butPtr->disabledFg == NULL) {
+ XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
+ 0, 0, (unsigned) Tk_Width(tkwin),
+ (unsigned) Tk_Height(tkwin));
+ } else {
+ XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
+ imageXOffset, imageYOffset,
+ (unsigned) imageWidth, (unsigned) imageHeight);
+ }
+ if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
+ && (butPtr->selectBorder != NULL)
+ ) {
+ XSetForeground(butPtr->display, butPtr->stippleGC,
+ Tk_3DBorderColor(butPtr->normalBorder)->pixel);
+ }
+ }
+
+ /*
+ * Draw the border and traversal highlight last. This way, if the
+ * button's contents overflow they'll be covered up by the border.
+ */
+
+ if (dpPtr->relief != TK_RELIEF_FLAT) {
+ int inset = butPtr->highlightWidth;
+ Tk_Draw3DRectangle(tkwin, pixmap, dpPtr->border, inset, inset,
+ Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset,
+ butPtr->borderWidth, dpPtr->relief);
+ }
+ }
+
+ }
+
+
+
+
/*
*----------------------------------------------------------------------
*
- * TkpButtonSetDefaults --
+ * TkpDestroyButton --
*
- * This procedure is invoked before option tables are created for
- * buttons. It modifies some of the default values to match the current
- * values defined for this platform.
+ * Free data structures associated with the button control.
*
* Results:
- * Some of the default values in *specPtr are modified.
+ * None.
*
* Side effects:
- * Updates some of.
+ * Restores the default control state.
*
*----------------------------------------------------------------------
*/
void
-TkpButtonSetDefaults()
+TkpDestroyButton(
+ TkButton *butPtr)
{
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (!tkMacOSXUseCompatibilityMetrics) {
- strcpy(tkDefButtonHighlightWidth, DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM);
- strcpy(tkDefLabelHighlightWidth, DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM);
- strcpy(tkDefButtonPadx, DEF_BUTTON_PADX_NOCM);
- strcpy(tkDefLabelPadx, DEF_BUTTON_PADX_NOCM);
- strcpy(tkDefButtonPady, DEF_BUTTON_PADY_NOCM);
- strcpy(tkDefLabelPady, DEF_BUTTON_PADY_NOCM);
+ MacButton *mbPtr = (MacButton *) butPtr; /* Mac button. */
+ if (mbPtr->defaultPulseHandler) {
+ Tcl_DeleteTimerHandler(mbPtr->defaultPulseHandler);
}
-#endif
}
-
-#pragma mark -
-#pragma mark Native Buttons:
-
/*
- *----------------------------------------------------------------------
+ *--------------------------------------------------------------
*
- * TkMacOSXGetButtonFrame --
+ * TkMacOSXDrawButton --
*
- * Computes a frame for an NSButton that will correspond to where
- * Tk thinks the button is located.
+ * This function draws the tk button using Mac controls
+ * In addition, this code may apply custom colors passed
+ * in the TkButton.
*
* Results:
- * Returns an NSRect describing a frame for an NSButton.
+ * None.
*
* Side effects:
- * None
+ * The control is created, or reinitialised as needed
*
- *----------------------------------------------------------------------
+ *--------------------------------------------------------------
*/
-NSRect TkMacOSXGetButtonFrame(
- TkButton *butPtr)
+
+static void
+TkMacOSXDrawButton(
+ MacButton *mbPtr, /* Mac button. */
+ GC gc, /* The GC we are drawing into - needed for
+ * the bevel button */
+ Pixmap pixmap) /* The pixmap we are drawing into - needed
+ * for the bevel button */
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
- Tk_Window tkwin = butPtr->tkwin;
- TkWindow *winPtr = (TkWindow *) tkwin;
- if (tkwin) {
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
- NSView *view = TkMacOSXDrawableView(macWin);
- CGFloat viewHeight = [view bounds].size.height;
- NSRect frame = NSMakeRect(macWin->xOff, macWin->yOff,
- Tk_Width(tkwin), Tk_Height(tkwin));
-
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- BoundsFix boundsFix = boundsFixes[macButtonPtr->fix];
- frame = NSOffsetRect(frame, boundsFix.offsetX, boundsFix.offsetY);
- frame.size.height -= boundsFix.shrinkH + NATIVE_BUTTON_EXTRA_H;
- frame = NSInsetRect(frame, boundsFix.inset + NATIVE_BUTTON_INSET,
- boundsFix.inset + NATIVE_BUTTON_INSET);
+ TkButton * butPtr = ( TkButton *)mbPtr;
+ TkWindow * winPtr;
+ HIRect cntrRect;
+ TkMacOSXDrawingContext dc;
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ int useNewerHITools = 1;
+
+ winPtr = (TkWindow *)butPtr->tkwin;
+
+ TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
+
+ cntrRect = CGRectMake(winPtr->privatePtr->xOff,
+ winPtr->privatePtr->yOff,
+ Tk_Width(butPtr->tkwin),
+ Tk_Height(butPtr->tkwin));
+
+ cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset);
+
+ if (useNewerHITools == 1) {
+ HIRect contHIRec;
+ static HIThemeButtonDrawInfo hiinfo;
+
+ ButtonBackgroundDrawCB(&cntrRect, mbPtr, 32, true);
+
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
}
-#endif
- frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
- return frame;
+
+ 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;
+ hiinfo.value = mbPtr->drawinfo.value;
+ hiinfo.adornment = mbPtr->drawinfo.adornment;
+ hiinfo.animation.time.current = CFAbsoluteTimeGetCurrent();
+ if (hiinfo.animation.time.start == 0) {
+ hiinfo.animation.time.start = hiinfo.animation.time.current;
+ }
+
+ HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec);
+ TkMacOSXRestoreDrawingContext(&dc);
+ ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, (MacButton *)mbPtr, 32, true);
+
} else {
- return NSZeroRect;
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
+ }
+
+ TkMacOSXRestoreDrawingContext(&dc);
}
+ mbPtr->lastdrawinfo = mbPtr->drawinfo;
}
/*
- *----------------------------------------------------------------------
+ *--------------------------------------------------------------
*
- * DisplayNativeButton --
+ * ButtonBackgroundDrawCB --
*
- * This procedure is invoked to display a button widget. It is
- * normally invoked as an idle handler.
+ * This function draws the background that
+ * lies under checkboxes and radiobuttons.
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * Commands are output to X to display the button in its
- * current mode. The REDRAW_PENDING flag is cleared.
+ * The background gets updated to the current color.
*
- *----------------------------------------------------------------------
+ *--------------------------------------------------------------
*/
-
static void
-DisplayNativeButton(
- TkButton *butPtr)
+ButtonBackgroundDrawCB (
+ const HIRect * btnbounds,
+ MacButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
- TkNSButton *button = macButtonPtr->button;
- Tk_Window tkwin = butPtr->tkwin;
- TkWindow *winPtr = (TkWindow *) tkwin;
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
- TkMacOSXDrawingContext dc;
- NSView *view = TkMacOSXDrawableView(macWin);
- CGFloat viewHeight = [view bounds].size.height;
- CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
- .ty = viewHeight};
- NSRect frame;
- int enabled;
- NSCellStateValue state;
-
- if (!view ||
- !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
- return;
- }
- CGContextConcatCTM(dc.context, t);
-
- /*
- * We cannot change the background color of the button itself, only the
- * color of the background of its container.
- * This will be the color that peeks around the rounded corners of the
- * button. We make this the highlightbackground rather than the background,
- * because if you color the background of a frame containing a
- * button, you usually also color the highlightbackground as well,
- * or you will get a thin grey ring around the button.
- */
+ MacButton* mbPtr = (MacButton*)ptr;
+ TkButton* butPtr = (TkButton*)mbPtr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ int usehlborder = 0;
- Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, butPtr->type == TYPE_BUTTON ?
- butPtr->highlightBorder : butPtr->normalBorder, 0, 0,
- Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
- if ([button superview] != view) {
- [view addSubview:button];
- }
- if (macButtonPtr->tristateImage) {
- NSImage *selectImage = macButtonPtr->selectImage ?
- macButtonPtr->selectImage : macButtonPtr->image;
- [button setImage:(butPtr->flags & TRISTATED ?
- selectImage : macButtonPtr->image)];
- [button setAlternateImage:(butPtr->flags & TRISTATED ?
- macButtonPtr->tristateImage : selectImage)];
- }
- if (butPtr->flags & SELECTED) {
- state = NSOnState;
- } else if (butPtr->flags & TRISTATED) {
- state = NSMixedState;
- } else {
- state = NSOffState;
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- [button setState:state];
- enabled = !(butPtr->state == STATE_DISABLED);
- [button setEnabled:enabled];
- if (enabled) {
- //[button highlight:(butPtr->state == STATE_ACTIVE)];
- //[cell setHighlighted:(butPtr->state == STATE_ACTIVE)];
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+ if (butPtr->type != TYPE_LABEL) {
+ switch (mbPtr->btnkind) {
+ case kThemeSmallBevelButton:
+ case kThemeBevelButton:
+ case kThemeRoundedBevelButton:
+ case kThemePushButton:
+ usehlborder = 1;
+ break;
+ }
}
- if (butPtr->type == TYPE_BUTTON && butPtr->defaultState == STATE_ACTIVE) {
- //[[view window] setDefaultButtonCell:cell];
- [button setKeyEquivalent:@"\r"];
+ if (usehlborder) {
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
} else {
- [button setKeyEquivalent:@""];
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
}
- frame = TkMacOSXGetButtonFrame(butPtr);
- [button setFrame:frame];
- [button displayRectIgnoringOpacity:[button bounds]];
- TkMacOSXRestoreDrawingContext(&dc);
-#ifdef TK_MAC_DEBUG_BUTTON
- TKLog(@"button %s frame %@ width %d height %d",
- ((TkWindow *)butPtr->tkwin)->pathName, NSStringFromRect(frame),
- Tk_Width(tkwin), Tk_Height(tkwin));
-#endif
}
/*
- *----------------------------------------------------------------------
+ *--------------------------------------------------------------
*
- * ComputeNativeButtonGeometry --
+ * ButtonContentDrawCB --
*
- * After changes in a button's text or bitmap, this procedure
- * recomputes the button's geometry and passes this information
- * along to the geometry manager for the window.
+ * This function draws the label and image for the button.
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * The button's window may change size.
+ * The content of the button gets updated.
*
- *----------------------------------------------------------------------
+ *--------------------------------------------------------------
*/
-
static void
-ComputeNativeButtonGeometry(
- TkButton *butPtr) /* Button whose geometry may have changed. */
+ButtonContentDrawCB (
+ const HIRect * btnbounds,
+ ThemeButtonKind kind,
+ const HIThemeButtonDrawInfo *drawinfo,
+ MacButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
{
- MacButton *macButtonPtr = (MacButton *) butPtr;
- TkNSButton *button = macButtonPtr->button;
- NSButtonCell *cell = [button cell];
- NSButtonType type = -1;
- NSBezelStyle style = 0;
- NSInteger highlightsBy = 0, showsStateBy = 0;
- NSFont *font;
- NSRect bounds = NSZeroRect, titleRect = NSZeroRect;
- int haveImage = (butPtr->image || butPtr->bitmap != None), haveText = 0;
- int haveCompound = (butPtr->compound != COMPOUND_NONE);
- int width, height, border = 0;
-
- butPtr->indicatorSpace = 0;
- butPtr->inset = 0;
- if (butPtr->highlightWidth < 0) {
- butPtr->highlightWidth = 0;
- }
- switch (butPtr->type) {
- case TYPE_BUTTON:
- type = NSMomentaryPushInButton;
- if (!haveImage) {
- style = NSRoundedBezelStyle;
- butPtr->inset = butPtr->defaultState != STATE_DISABLED ?
- butPtr->highlightWidth : 0;
- [button setImage:nil];
- [button setImagePosition:NSNoImage];
- } else {
- style = NSShadowlessSquareBezelStyle;
- highlightsBy = butPtr->selectImage || butPtr->bitmap ?
- NSContentsCellMask : 0;
- border = butPtr->borderWidth;
- }
- break;
- case TYPE_RADIO_BUTTON:
- case TYPE_CHECK_BUTTON:
- if (!haveImage /*|| butPtr->indicatorOn*/) { // TODO: indicatorOn
- type = butPtr->type == TYPE_RADIO_BUTTON ?
- NSRadioButton : NSSwitchButton;
- butPtr->inset = /*butPtr->indicatorOn ? 0 :*/ butPtr->borderWidth;
- } else {
- type = NSPushOnPushOffButton;
- style = NSShadowlessSquareBezelStyle;
- highlightsBy = butPtr->selectImage || butPtr->bitmap ?
- NSContentsCellMask : 0;
- showsStateBy = butPtr->selectImage || butPtr->tristateImage ?
- NSContentsCellMask : 0;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- border = butPtr->borderWidth > 1 ? butPtr->borderWidth - 1 : 1;
- } else
-#endif
- {
- border = butPtr->borderWidth;
- }
- }
- break;
- }
- [button setButtonType:type];
- if (style) {
- [button setBezelStyle:style];
- }
- if (highlightsBy) {
- [cell setHighlightsBy:highlightsBy|[cell highlightsBy]];
- }
- if (showsStateBy) {
- [cell setShowsStateBy:showsStateBy|[cell showsStateBy]];
- }
-#if 0
- if (style == NSShadowlessSquareBezelStyle) {
- NSControlSize controlSize = NSRegularControlSize;
-
- if (butPtr->borderWidth <= 2) {
- controlSize = NSMiniControlSize;
- } else if (butPtr->borderWidth == 3) {
- controlSize = NSSmallControlSize;
- }
- [cell setControlSize:controlSize];
- }
-#endif
- [button setAllowsMixedState:YES];
-
- if (!haveImage || haveCompound) {
- int len;
- char *text = Tcl_GetStringFromObj(butPtr->textPtr, &len);
-
- if (len) {
- NSString *title = [[NSString alloc] initWithBytes:text length:len
- encoding:NSUTF8StringEncoding];
- [button setTitle:title];
- [title release];
- haveText = 1;
- }
- }
- haveCompound = (haveCompound && haveImage && haveText);
- if (haveText) {
- NSTextAlignment alignment = NSNaturalTextAlignment;
-
- switch (butPtr->justify) {
- case TK_JUSTIFY_LEFT:
- alignment = NSLeftTextAlignment;
- break;
- case TK_JUSTIFY_RIGHT:
- alignment = NSRightTextAlignment;
- break;
- case TK_JUSTIFY_CENTER:
- alignment = NSCenterTextAlignment;
- break;
- }
- [button setAlignment:alignment];
- } else {
- [button setTitle:@""];
- }
- font = TkMacOSXNSFontForFont(butPtr->tkfont);
- if (font) {
- [button setFont:font];
- }
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->image);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->selectImage);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->tristateImage);
- if (haveImage) {
- int width, height;
- NSImage *image, *selectImage = nil, *tristateImage = nil;
- NSCellImagePosition pos = NSImageOnly;
-
- if (butPtr->image) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- image = TkMacOSXGetNSImageWithTkImage(butPtr->display,
- butPtr->image, width, height);
- if (butPtr->selectImage) {
- selectImage = TkMacOSXGetNSImageWithTkImage(butPtr->display,
- butPtr->selectImage, width, height);
- }
- if (butPtr->tristateImage) {
- tristateImage = TkMacOSXGetNSImageWithTkImage(butPtr->display,
- butPtr->tristateImage, width, height);
- }
- } else {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- image = TkMacOSXGetNSImageWithBitmap(butPtr->display,
- butPtr->bitmap, butPtr->normalTextGC, width, height);
- selectImage = TkMacOSXGetNSImageWithBitmap(butPtr->display,
- butPtr->bitmap, butPtr->activeTextGC, width, height);
- }
- [button setImage:image];
- if (selectImage) {
- [button setAlternateImage:selectImage];
- }
- if (tristateImage) {
- macButtonPtr->image = TkMacOSXMakeUncollectableAndRetain(image);
- if (selectImage) {
- macButtonPtr->selectImage =
- TkMacOSXMakeUncollectableAndRetain(selectImage);
- }
- macButtonPtr->tristateImage =
- TkMacOSXMakeUncollectableAndRetain(tristateImage);
- }
- if (haveCompound) {
- switch ((enum compound) butPtr->compound) {
- case COMPOUND_TOP:
- pos = NSImageAbove;
- break;
- case COMPOUND_BOTTOM:
- pos = NSImageBelow;
- break;
- case COMPOUND_LEFT:
- pos = NSImageLeft;
- break;
- case COMPOUND_RIGHT:
- pos = NSImageRight;
- break;
- case COMPOUND_CENTER:
- pos = NSImageOverlaps;
- break;
- case COMPOUND_NONE:
- pos = NSImageOnly;
- break;
- }
- }
- [button setImagePosition:pos];
- }
+ TkButton *butPtr = (TkButton *)ptr;
+ Tk_Window tkwin = butPtr->tkwin;
- // if font is too tall, we can't use the fixed-height rounded bezel
- if (!haveImage && haveText && style == NSRoundedBezelStyle) {
- Tk_FontMetrics fm;
- Tk_GetFontMetrics(butPtr->tkfont, &fm);
- if (fm.linespace > 18) {
- [button setBezelStyle:(style = NSShadowlessSquareBezelStyle)];
- }
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- bounds.size = [cell cellSize];
- if (haveText) {
- titleRect = [cell titleRectForBounds:bounds];
- if (butPtr->wrapLength > 0 &&
- titleRect.size.width > butPtr->wrapLength) {
- if (style == NSRoundedBezelStyle) {
- [button setBezelStyle:(style = NSRegularSquareBezelStyle)];
- bounds.size = [cell cellSize];
- titleRect = [cell titleRectForBounds:bounds];
- }
- bounds.size.width -= titleRect.size.width - butPtr->wrapLength;
- bounds.size.height = 40000.0;
- [cell setWraps:YES];
- bounds.size = [cell cellSizeForBounds:bounds];
-#ifdef TK_MAC_DEBUG_BUTTON
- titleRect = [cell titleRectForBounds:bounds];
-#endif
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- bounds.size.height += 3;
- }
-#endif
- }
- }
- width = lround(bounds.size.width);
- height = lround(bounds.size.height);
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- macButtonPtr->fix = fixForTypeStyle(type, style);
- width -= boundsFixes[macButtonPtr->fix].trimW;
- height -= boundsFixes[macButtonPtr->fix].trimH;
- }
-#endif
+ /*Overlay Tk elements over button native region: drawing elements within button boundaries/native region causes unpredictable metrics.*/
+ DrawButtonImageAndText( butPtr);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ButtonEventProc --
+ *
+ * This procedure is invoked by the Tk dispatcher for various
+ * events on buttons.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * When it gets exposed, it is redisplayed.
+ *
+ *--------------------------------------------------------------
+ */
- if (haveImage || haveCompound) {
- if (butPtr->width > 0) {
- width = butPtr->width;
- }
- if (butPtr->height > 0) {
- height = butPtr->height;
+static void
+ButtonEventProc(
+ ClientData clientData, /* Information about window. */
+ XEvent *eventPtr) /* Information about event. */
+{
+ TkButton *buttonPtr = (TkButton *) clientData;
+ MacButton *mbPtr = (MacButton *) clientData;
+
+ if (eventPtr->type == ActivateNotify
+ || eventPtr->type == DeactivateNotify) {
+ if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) {
+ return;
}
- } else {
- if (butPtr->width > 0) {
- int avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
- width = butPtr->width * avgWidth;
+ if (eventPtr->type == ActivateNotify) {
+ mbPtr->flags |= ACTIVE;
+ } else {
+ mbPtr->flags &= ~ACTIVE;
}
- if (butPtr->height > 0) {
- Tk_FontMetrics fm;
-
- Tk_GetFontMetrics(butPtr->tkfont, &fm);
- height = butPtr->height * fm.linespace;
+ if ((buttonPtr->flags & REDRAW_PENDING) == 0) {
+ Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) buttonPtr);
+ buttonPtr->flags |= REDRAW_PENDING;
}
}
- if (!haveImage || haveCompound) {
- width += 2*butPtr->padX;
- height += 2*butPtr->padY;
- }
- if (haveImage) {
- width += 2*border;
- height += 2*border;
- }
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- width += 2*NATIVE_BUTTON_INSET;
- height += 2*NATIVE_BUTTON_INSET + NATIVE_BUTTON_EXTRA_H;
- }
-#endif
- Tk_GeometryRequest(butPtr->tkwin, width, height);
- Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
-#ifdef TK_MAC_DEBUG_BUTTON
- TKLog(@"button %s bounds %@ titleRect %@ width %d height %d inset %d borderWidth %d",
- ((TkWindow *)butPtr->tkwin)->pathName, NSStringFromRect(bounds),
- NSStringFromRect(titleRect), width, height, butPtr->inset,
- butPtr->borderWidth);
-#endif
}
-
-#pragma mark -
-#pragma mark Unix Buttons:
-
/*
*----------------------------------------------------------------------
*
- * DisplayUnixButton --
+ * TkMacOSXComputeButtonParams --
*
- * This procedure is invoked to display a button widget. It is
- * normally invoked as an idle handler.
+ * This procedure computes the various parameters used
+ * when creating a Carbon Appearance control.
+ * These are determined by the various tk button parameters
*
* Results:
* None.
*
* Side effects:
- * Commands are output to X to display the button in its
- * current mode. The REDRAW_PENDING flag is cleared.
+ * Sets the btnkind and drawinfo parameters
*
*----------------------------------------------------------------------
*/
-void
-DisplayUnixButton(
- TkButton *butPtr)
+static void
+TkMacOSXComputeButtonParams(
+ TkButton * butPtr,
+ ThemeButtonKind* btnkind,
+ HIThemeButtonDrawInfo *drawinfo)
{
- GC gc;
- Tk_3DBorder border;
- Pixmap pixmap;
- int x = 0; /* Initialization only needed to stop compiler
- * warning. */
- int y, relief;
- Tk_Window tkwin = butPtr->tkwin;
- int width = 0, height = 0, fullWidth, fullHeight;
- int textXOffset, textYOffset;
- int haveImage = 0, haveText = 0;
- int imageWidth, imageHeight;
- int imageXOffset = 0, imageYOffset = 0;
- /* image information that will be used to
- * restrict disabled pixmap as well */
-
- border = butPtr->normalBorder;
- if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
- gc = butPtr->disabledGC;
- } else if ((butPtr->state == STATE_ACTIVE)
- && !Tk_StrictMotif(butPtr->tkwin)) {
- gc = butPtr->activeTextGC;
- border = butPtr->activeBorder;
+ MacButton *mbPtr = (MacButton *)butPtr;
+
+ if (butPtr->borderWidth <= 2) {
+ *btnkind = kThemeSmallBevelButton;
+ } else if (butPtr->borderWidth == 3) {
+ *btnkind = kThemeBevelButton;
+ } else if (butPtr->borderWidth == 4) {
+ *btnkind = kThemeRoundedBevelButton;
} else {
- gc = butPtr->normalTextGC;
+ *btnkind = kThemePushButton;
}
- if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE)
- && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) {
- border = butPtr->selectBorder;
- }
-
- relief = butPtr->relief;
-
- pixmap = (Pixmap) Tk_WindowId(tkwin);
- Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
- Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
-
- /*
- * Display image or bitmap or text for button.
- */
-
- if (butPtr->image != NULL) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- haveImage = 1;
- } else if (butPtr->bitmap != None) {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- haveImage = 1;
- }
- imageWidth = width;
- imageHeight = height;
-
- haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
-
- if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
- textXOffset = 0;
- textYOffset = 0;
- fullWidth = 0;
- fullHeight = 0;
-
- switch ((enum compound) butPtr->compound) {
- case COMPOUND_TOP:
- case COMPOUND_BOTTOM:
- /*
- * Image is above or below text.
- */
-
- if (butPtr->compound == COMPOUND_TOP) {
- textYOffset = height + butPtr->padY;
- } else {
- imageYOffset = butPtr->textHeight + butPtr->padY;
- }
- fullHeight = height + butPtr->textHeight + butPtr->padY;
- fullWidth = (width > butPtr->textWidth ? width :
- butPtr->textWidth);
- textXOffset = (fullWidth - butPtr->textWidth)/2;
- imageXOffset = (fullWidth - width)/2;
- break;
- case COMPOUND_LEFT:
- case COMPOUND_RIGHT:
- /*
- * Image is left or right of text.
- */
-
- if (butPtr->compound == COMPOUND_LEFT) {
- textXOffset = width + butPtr->padX;
- } else {
- imageXOffset = butPtr->textWidth + butPtr->padX;
- }
- fullWidth = butPtr->textWidth + butPtr->padX + width;
- fullHeight = (height > butPtr->textHeight ? height :
- butPtr->textHeight);
- textYOffset = (fullHeight - butPtr->textHeight)/2;
- imageYOffset = (fullHeight - height)/2;
- break;
- case COMPOUND_CENTER:
- /*
- * Image and text are superimposed.
- */
-
- fullWidth = (width > butPtr->textWidth ? width :
- butPtr->textWidth);
- fullHeight = (height > butPtr->textHeight ? height :
- butPtr->textHeight);
- textXOffset = (fullWidth - butPtr->textWidth)/2;
- imageXOffset = (fullWidth - width)/2;
- textYOffset = (fullHeight - butPtr->textHeight)/2;
- imageYOffset = (fullHeight - height)/2;
- break;
- case COMPOUND_NONE:
- break;
- }
-
- TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
- fullWidth, fullHeight, &x, &y);
-
- imageXOffset += x;
- imageYOffset += y;
-
- if (butPtr->image != NULL) {
- /*
- * Do boundary clipping, so that Tk_RedrawImage is passed valid
- * coordinates. [Bug 979239]
- */
-
- if (imageXOffset < 0) {
- imageXOffset = 0;
- }
- if (imageYOffset < 0) {
- imageYOffset = 0;
- }
- if (width > Tk_Width(tkwin)) {
- width = Tk_Width(tkwin);
- }
- if (height > Tk_Height(tkwin)) {
- height = Tk_Height(tkwin);
- }
- if ((width + imageXOffset) > Tk_Width(tkwin)) {
- imageXOffset = Tk_Width(tkwin) - width;
- }
- if ((height + imageYOffset) > Tk_Height(tkwin)) {
- imageYOffset = Tk_Height(tkwin) - height;
- }
-
- if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) {
- Tk_RedrawImage(butPtr->selectImage, 0, 0,
- width, height, pixmap, imageXOffset, imageYOffset);
- } else if ((butPtr->tristateImage != NULL) && (butPtr->flags & TRISTATED)) {
- Tk_RedrawImage(butPtr->tristateImage, 0, 0,
- width, height, pixmap, imageXOffset, imageYOffset);
- } else {
- Tk_RedrawImage(butPtr->image, 0, 0, width,
- height, pixmap, imageXOffset, imageYOffset);
- }
- } else {
- XSetClipOrigin(butPtr->display, gc, imageXOffset, imageYOffset);
- XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc,
- 0, 0, (unsigned int) width, (unsigned int) height,
- imageXOffset, imageYOffset, 1);
- XSetClipOrigin(butPtr->display, gc, 0, 0);
- }
-
- Tk_DrawTextLayout(butPtr->display, pixmap, gc,
- butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1);
- Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
- butPtr->textLayout, x + textXOffset, y + textYOffset,
- butPtr->underline);
- y += fullHeight/2;
- } else {
- if (haveImage) {
- TkComputeAnchor(butPtr->anchor, tkwin, 0, 0,
- width, height, &x, &y);
- imageXOffset += x;
- imageYOffset += y;
- if (butPtr->image != NULL) {
- /*
- * Do boundary clipping, so that Tk_RedrawImage is passed
- * valid coordinates. [Bug 979239]
- */
-
- if (imageXOffset < 0) {
- imageXOffset = 0;
- }
- if (imageYOffset < 0) {
- imageYOffset = 0;
- }
- if (width > Tk_Width(tkwin)) {
- width = Tk_Width(tkwin);
- }
- if (height > Tk_Height(tkwin)) {
- height = Tk_Height(tkwin);
- }
- if ((width + imageXOffset) > Tk_Width(tkwin)) {
- imageXOffset = Tk_Width(tkwin) - width;
- }
- if ((height + imageYOffset) > Tk_Height(tkwin)) {
- imageYOffset = Tk_Height(tkwin) - height;
- }
- if ((butPtr->selectImage != NULL) &&
- (butPtr->flags & SELECTED)) {
- Tk_RedrawImage(butPtr->selectImage, 0, 0, width,
- height, pixmap, imageXOffset, imageYOffset);
- } else if ((butPtr->tristateImage != NULL) &&
- (butPtr->flags & TRISTATED)) {
- Tk_RedrawImage(butPtr->tristateImage, 0, 0, width,
- height, pixmap, imageXOffset, imageYOffset);
+ if ((butPtr->image == None) && (butPtr->bitmap == None)) {
+ switch (butPtr->type) {
+ case TYPE_BUTTON:
+ *btnkind = kThemePushButton;
+ break;
+ case TYPE_RADIO_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallRadioButton;
} else {
- Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap,
- imageXOffset, imageYOffset);
+ *btnkind = kThemeRadioButton;
}
- } else {
- XSetClipOrigin(butPtr->display, gc, x, y);
- XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0,
- (unsigned int) width, (unsigned int) height, x, y, 1);
- XSetClipOrigin(butPtr->display, gc, 0, 0);
- }
- y += height/2;
- } else {
- TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
- butPtr->textWidth, butPtr->textHeight, &x, &y);
-
- Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout,
- x, y, 0, -1);
- Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
- butPtr->textLayout, x, y, butPtr->underline);
- y += butPtr->textHeight/2;
+ break;
+ case TYPE_CHECK_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallCheckBox;
+ } else {
+ *btnkind = kThemeCheckBox;
+ }
+ break;
}
}
- /*
- * If the button is disabled with a stipple rather than a special
- * foreground color, generate the stippled effect. If the widget is
- * selected and we use a different background color when selected, must
- * temporarily modify the GC so the stippling is the right color.
- */
-
- if ((butPtr->state == STATE_DISABLED)
- && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) {
- if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
- && (butPtr->selectBorder != NULL)) {
- XSetForeground(butPtr->display, butPtr->stippleGC,
- Tk_3DBorderColor(butPtr->selectBorder)->pixel);
- }
-
- /*
- * Stipple the whole button if no disabledFg was specified, otherwise
- * restrict stippling only to displayed image
- */
-
- if (butPtr->disabledFg == NULL) {
- XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC, 0, 0,
- (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin));
- } else {
- XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC,
- imageXOffset, imageYOffset,
- (unsigned) imageWidth, (unsigned) imageHeight);
- }
- if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
- && (butPtr->selectBorder != NULL)) {
- XSetForeground(butPtr->display, butPtr->stippleGC,
- Tk_3DBorderColor(butPtr->normalBorder)->pixel);
- }
+ if (butPtr->indicatorOn) {
+ switch (butPtr->type) {
+ case TYPE_RADIO_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallRadioButton;
+ } else {
+ *btnkind = kThemeRadioButton;
+ }
+ break;
+ case TYPE_CHECK_BUTTON:
+ if (butPtr->borderWidth <= 1) {
+ *btnkind = kThemeSmallCheckBox;
+ } else {
+ *btnkind = kThemeCheckBox;
+ }
+ break;
+ }
+ } else {
+ if (butPtr->type == TYPE_RADIO_BUTTON ||
+ butPtr->type == TYPE_CHECK_BUTTON
+ ) {
+ if (*btnkind == kThemePushButton) {
+ *btnkind = kThemeBevelButton;
+ }
+ }
}
- /*
- * Draw the border and traversal highlight last. This way, if the button's
- * contents overflow they'll be covered up by the border. This code is
- * complicated by the possible combinations of focus highlight and default
- * rings. We draw the focus and highlight rings using the highlight border
- * and highlight foreground color.
- */
-
- if (relief != TK_RELIEF_FLAT) {
- int inset = butPtr->highlightWidth;
-
- if (butPtr->defaultState == DEFAULT_ACTIVE) {
- /*
- * Draw the default ring with 2 pixels of space between the
- * default ring and the button and the default ring and the focus
- * ring. Note that we need to explicitly draw the space in the
- * highlightBorder color to ensure that we overwrite any overflow
- * text and/or a different button background color.
- */
-
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
- inset, Tk_Width(tkwin) - 2*inset,
- Tk_Height(tkwin) - 2*inset, 2, TK_RELIEF_FLAT);
- inset += 2;
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
- inset, Tk_Width(tkwin) - 2*inset,
- Tk_Height(tkwin) - 2*inset, 1, TK_RELIEF_SUNKEN);
- inset++;
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, inset,
- inset, Tk_Width(tkwin) - 2*inset,
- Tk_Height(tkwin) - 2*inset, 2, TK_RELIEF_FLAT);
-
- inset += 2;
- } else if (butPtr->defaultState == DEFAULT_NORMAL) {
- /*
- * Leave room for the default ring and write over any text or
- * background color.
- */
-
- Tk_Draw3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0,
- 0, Tk_Width(tkwin), Tk_Height(tkwin), 5, TK_RELIEF_FLAT);
- inset += 5;
- }
-
- /*
- * Draw the button border.
- */
-
- Tk_Draw3DRectangle(tkwin, pixmap, border, inset, inset,
- Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset,
- butPtr->borderWidth, relief);
+ if (butPtr->flags & SELECTED) {
+ drawinfo->value = kThemeButtonOn;
+ } else if (butPtr->flags & TRISTATED) {
+ drawinfo->value = kThemeButtonMixed;
+ } else {
+ drawinfo->value = kThemeButtonOff;
}
- if (butPtr->highlightWidth > 0) {
- GC gc;
- if (butPtr->flags & GOT_FOCUS) {
- gc = Tk_GCForColor(butPtr->highlightColorPtr, pixmap);
- } else {
- gc = Tk_GCForColor(Tk_3DBorderColor(butPtr->highlightBorder),
- pixmap);
+ if ((mbPtr->flags & FIRST_DRAW) != 0) {
+ mbPtr->flags &= ~FIRST_DRAW;
+ if (Tk_MacOSXIsAppInFront()) {
+ mbPtr->flags |= ACTIVE;
}
+ }
- /*
- * Make sure the focus ring shrink-wraps the actual button, not the
- * padding space left for a default ring.
- */
+ drawinfo->state = kThemeStateInactive;
+ if ((mbPtr->flags & ACTIVE) == 0) {
+ if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailableInactive;
+ } else {
+ drawinfo->state = kThemeStateInactive;
+ }
+ } else if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailable;
+ } else if (butPtr->state == STATE_ACTIVE) {
+ drawinfo->state = kThemeStatePressed;
+ } else {
+ drawinfo->state = kThemeStateActive;
+ }
- if (butPtr->defaultState == DEFAULT_NORMAL) {
- TkDrawInsetFocusHighlight(tkwin, gc, butPtr->highlightWidth,
- pixmap, 5);
- } else {
- Tk_DrawFocusHighlight(tkwin, gc, butPtr->highlightWidth, pixmap);
- }
+ drawinfo->adornment = kThemeAdornmentNone;
+ if (butPtr->defaultState == DEFAULT_ACTIVE) {
+ drawinfo->adornment |= kThemeAdornmentDefault;
+ if (!mbPtr->defaultPulseHandler) {
+ mbPtr->defaultPulseHandler = Tcl_CreateTimerHandler(
+ PULSE_TIMER_MSECS, PulseDefaultButtonProc,
+ (ClientData) butPtr);
+ }
+ } else if (mbPtr->defaultPulseHandler) {
+ Tcl_DeleteTimerHandler(mbPtr->defaultPulseHandler);
+ }
+ if (butPtr->highlightWidth >= 3) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ drawinfo->adornment |= kThemeAdornmentFocus;
+ }
}
}
/*
*----------------------------------------------------------------------
*
- * ComputeUnixButtonGeometry --
+ * TkMacOSXComputeButtonDrawParams --
*
- * After changes in a button's text or bitmap, this procedure
- * recomputes the button's geometry and passes this information
- * along to the geometry manager for the window.
+ * This procedure computes the various parameters used
+ * when drawing a button
+ * These are determined by the various tk button parameters
*
* Results:
- * None.
+ * 1 if control will be used, 0 otherwise.
*
* Side effects:
- * The button's window may change size.
+ * Sets the button draw parameters
*
*----------------------------------------------------------------------
*/
-void
-ComputeUnixButtonGeometry(
- register TkButton *butPtr) /* Button whose geometry may have changed. */
+static int
+TkMacOSXComputeButtonDrawParams(
+ TkButton *butPtr,
+ DrawParams *dpPtr)
{
- int width, height, avgWidth, txtWidth, txtHeight;
- int haveImage = 0, haveText = 0;
- Tk_FontMetrics fm;
-
- butPtr->inset = butPtr->highlightWidth + butPtr->borderWidth;
-
- /*
- * Leave room for the default ring if needed.
- */
-
- if (butPtr->defaultState != DEFAULT_DISABLED) {
- butPtr->inset += 5;
+ MacButton *mbPtr = (MacButton *)butPtr;
+
+ dpPtr->hasImageOrBitmap = ((butPtr->image != NULL)
+ || (butPtr->bitmap != None));
+
+ if (butPtr->type != TYPE_LABEL) {
+ dpPtr->offset = 0;
+ if (dpPtr->hasImageOrBitmap) {
+ switch (mbPtr->btnkind) {
+ case kThemeSmallBevelButton:
+ case kThemeBevelButton:
+ case kThemeRoundedBevelButton:
+ case kThemePushButton:
+ dpPtr->offset = 1;
+ break;
+ }
+ }
}
- butPtr->indicatorSpace = 0;
- width = 0;
- height = 0;
- txtWidth = 0;
- txtHeight = 0;
- avgWidth = 0;
- if (butPtr->image != NULL) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- haveImage = 1;
- } else if (butPtr->bitmap != None) {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- haveImage = 1;
+ dpPtr->border = butPtr->normalBorder;
+ if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
+ dpPtr->gc = butPtr->disabledGC;
+ } else if (butPtr->type == TYPE_BUTTON && butPtr->state == STATE_ACTIVE) {
+ dpPtr->gc = butPtr->activeTextGC;
+ dpPtr->border = butPtr->activeBorder;
+ } else {
+ dpPtr->gc = butPtr->normalTextGC;
}
- if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
- Tk_FreeTextLayout(butPtr->textLayout);
-
- butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
- Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength,
- butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
-
- txtWidth = butPtr->textWidth;
- txtHeight = butPtr->textHeight;
- avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
- Tk_GetFontMetrics(butPtr->tkfont, &fm);
- haveText = (txtWidth != 0 && txtHeight != 0);
+ if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE)
+ && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) {
+ dpPtr->border = butPtr->selectBorder;
}
/*
- * If the button is compound (i.e., it shows both an image and text), the
- * new geometry is a combination of the image and text geometry. We only
- * honor the compound bit if the button has both text and an image,
- * because otherwise it is not really a compound button.
+ * Override the relief specified for the button if this is a
+ * checkbutton or radiobutton and there's no indicator.
*/
- if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
- switch ((enum compound) butPtr->compound) {
- case COMPOUND_TOP:
- case COMPOUND_BOTTOM:
- /*
- * Image is above or below text.
- */
+ dpPtr->relief = butPtr->relief;
- height += txtHeight + butPtr->padY;
- width = (width > txtWidth ? width : txtWidth);
- break;
- case COMPOUND_LEFT:
- case COMPOUND_RIGHT:
- /*
- * Image is left or right of text.
- */
-
- width += txtWidth + butPtr->padX;
- height = (height > txtHeight ? height : txtHeight);
- break;
- case COMPOUND_CENTER:
- /*
- * Image and text are superimposed.
- */
-
- width = (width > txtWidth ? width : txtWidth);
- height = (height > txtHeight ? height : txtHeight);
- break;
- case COMPOUND_NONE:
- break;
- }
- if (butPtr->width > 0) {
- width = butPtr->width;
- }
- if (butPtr->height > 0) {
- height = butPtr->height;
+ if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) {
+ if (!dpPtr->hasImageOrBitmap) {
+ dpPtr->relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN
+ : TK_RELIEF_RAISED;
}
+ }
- width += 2*butPtr->padX;
- height += 2*butPtr->padY;
- } else {
- if (haveImage) {
- if (butPtr->width > 0) {
- width = butPtr->width;
- }
- if (butPtr->height > 0) {
- height = butPtr->height;
- }
- } else {
- width = txtWidth;
- height = txtHeight;
+ /*
+ * Determine the draw type
+ */
- if (butPtr->width > 0) {
- width = butPtr->width * avgWidth;
- }
- if (butPtr->height > 0) {
- height = butPtr->height * fm.linespace;
- }
+ if (butPtr->type == TYPE_LABEL) {
+ dpPtr->drawType = DRAW_LABEL;
+ } else if (butPtr->type == TYPE_BUTTON) {
+ if (!dpPtr->hasImageOrBitmap) {
+ dpPtr->drawType = DRAW_CONTROL;
+ } else {
+ dpPtr->drawType = DRAW_BEVEL;
}
+ } else if (butPtr->indicatorOn) {
+ dpPtr->drawType = DRAW_CONTROL;
+ } else if (dpPtr->hasImageOrBitmap) {
+ dpPtr->drawType = DRAW_BEVEL;
+ } else {
+ dpPtr->drawType = DRAW_CUSTOM;
}
- if (!haveImage) {
- width += 2*butPtr->padX;
- height += 2*butPtr->padY;
+ if ((dpPtr->drawType == DRAW_CONTROL) || (dpPtr->drawType == DRAW_BEVEL)) {
+ return 1;
+ } else {
+ return 0;
}
- Tk_GeometryRequest(butPtr->tkwin, (int) (width
- + 2*butPtr->inset), (int) (height + 2*butPtr->inset));
- Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
}
-
/*
- * Local Variables:
- * mode: objc
- * c-basic-offset: 4
- * fill-column: 79
- * coding: utf-8
- * End:
+ *--------------------------------------------------------------
+ *
+ * PulseDefaultButtonProc --
+ *
+ * This function redraws the button on a timer, to pulse
+ * default buttons.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Sets a timer to run itself again.
+ *
+ *--------------------------------------------------------------
*/
+static void
+PulseDefaultButtonProc(ClientData clientData)
+{
+ MacButton *mbPtr = (MacButton *)clientData;
+ TkpDisplayButton(clientData);
+ mbPtr->defaultPulseHandler = Tcl_CreateTimerHandler(
+ PULSE_TIMER_MSECS, PulseDefaultButtonProc, clientData);
+}
+
diff --git a/macosx/tkMacOSXDefault.h b/macosx/tkMacOSXDefault.h
index 8565cdb..e95560f 100644
--- a/macosx/tkMacOSXDefault.h
+++ b/macosx/tkMacOSXDefault.h
@@ -16,9 +16,9 @@
#ifndef _TKMACDEFAULT
#define _TKMACDEFAULT
-#ifndef TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-#define TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS 1
-#endif
+//#ifndef TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+//#define TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS 1
+//#endif
/*
* The definitions below provide symbolic names for the default colors.
@@ -72,12 +72,12 @@
#define DEF_BUTTON_HIGHLIGHT_BG_MONO DEF_BUTTON_BG_MONO
#define DEF_BUTTON_HIGHLIGHT "systemButtonFrame"
#define DEF_LABEL_HIGHLIGHT_WIDTH "0"
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-#define DEF_BUTTON_HIGHLIGHT_WIDTH "4"
-#define DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM "1"
-#else
+//#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+//#define DEF_BUTTON_HIGHLIGHT_WIDTH "4"
+//#define DEF_BUTTON_HIGHLIGHT_WIDTH_NOCM "1"
+//#else
#define DEF_BUTTON_HIGHLIGHT_WIDTH "1"
-#endif
+//#endif
#define DEF_BUTTON_IMAGE ((char *) NULL)
#define DEF_BUTTON_INDICATOR "1"
#define DEF_BUTTON_JUSTIFY "center"
@@ -85,19 +85,19 @@
#define DEF_BUTTON_ON_VALUE "1"
#define DEF_BUTTON_TRISTATE_VALUE ""
#define DEF_BUTTON_OVER_RELIEF ""
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-#define DEF_BUTTON_PADX "12"
-#define DEF_BUTTON_PADX_NOCM "1"
-#else
+//#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+//#define DEF_BUTTON_PADX "12"
+//#define DEF_BUTTON_PADX_NOCM "1"
+//#else
#define DEF_BUTTON_PADX "1"
-#endif
+//#endif
#define DEF_LABCHKRAD_PADX "1"
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-#define DEF_BUTTON_PADY "3"
-#define DEF_BUTTON_PADY_NOCM "1"
-#else
+//#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+//#define DEF_BUTTON_PADY "3"
+//#define DEF_BUTTON_PADY_NOCM "1"
+//#else
#define DEF_BUTTON_PADY "1"
-#endif
+//#endif
#define DEF_LABCHKRAD_PADY "1"
#define DEF_BUTTON_RELIEF "flat"
#define DEF_LABCHKRAD_RELIEF "flat"
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c
index 0f8e051..328f905 100644
--- a/macosx/tkMacOSXDraw.c
+++ b/macosx/tkMacOSXDraw.c
@@ -101,13 +101,6 @@ TkMacOSXInitCGDrawing(
(char *) &useThemedFrame, TCL_LINK_BOOLEAN) != TCL_OK) {
Tcl_ResetResult(interp);
}
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (Tcl_LinkVar(interp, "::tk::mac::useCompatibilityMetrics",
- (char *) &tkMacOSXUseCompatibilityMetrics, TCL_LINK_BOOLEAN)
- != TCL_OK) {
- Tcl_ResetResult(interp);
- }
-#endif
}
return TCL_OK;
}
@@ -155,7 +148,8 @@ BitmapRepFromDrawableRect(
cg_image = CGBitmapContextCreateImage( (CGContextRef) cg_context);
sub_cg_image = CGImageCreateWithImageInRect(cg_image, image_rect);
if ( sub_cg_image ) {
- bitmap_rep = [[NSBitmapImageRep alloc] autorelease];
+ /*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/
+ bitmap_rep = [NSBitmapImageRep alloc];
[bitmap_rep initWithCGImage:sub_cg_image];
}
if ( cg_image ) {
@@ -169,7 +163,8 @@ BitmapRepFromDrawableRect(
width,height);
if ( [view lockFocusIfCanDraw] ) {
- bitmap_rep = [[NSBitmapImageRep alloc] autorelease];
+ /*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/
+ bitmap_rep = [NSBitmapImageRep alloc];
bitmap_rep = [bitmap_rep initWithFocusedViewRect:view_rect];
[view unlockFocus];
} else {
@@ -1480,19 +1475,19 @@ TkScrollWindow(
TkRegion damageRgn) /* Region to accumulate damage in. */
{
Drawable drawable = Tk_WindowId(tkwin);
- MacDrawable *macDraw = (MacDrawable *) drawable;
+ MacDrawable *macDraw = (MacDrawable *) drawable;
NSView *view = TkMacOSXDrawableView(macDraw);
CGRect srcRect, dstRect;
HIShapeRef dmgRgn = NULL, extraRgn;
NSRect bounds, visRect, scrollSrc, scrollDst;
- NSPoint delta = NSMakePoint(dx, dy);
int result;
-
+
+
if ( view ) {
/* Get the scroll area in NSView coordinates (origin at bottom left). */
bounds = [view bounds];
scrollSrc = NSMakeRect(
- macDraw->xOff + x,
+ macDraw->xOff + x,
bounds.size.height - height - (macDraw->yOff + y),
width, height);
scrollDst = NSOffsetRect(scrollSrc, dx, -dy);
@@ -1500,45 +1495,26 @@ TkScrollWindow(
visRect = [view visibleRect];
scrollSrc = NSIntersectionRect(scrollSrc, visRect);
scrollDst = NSIntersectionRect(scrollDst, visRect);
-
+
if ( !NSIsEmptyRect(scrollSrc) && !NSIsEmptyRect(scrollDst) ) {
-
+
/*
* Mark the difference between source and destination as damaged.
* This region is described in the Tk coordinate system.
*/
-
+
srcRect = CGRectMake(x, y, width, height);
dstRect = CGRectOffset(srcRect, dx, dy);
dmgRgn = HIShapeCreateMutableWithRect(&srcRect);
extraRgn = HIShapeCreateWithRect(&dstRect);
ChkErr(HIShapeDifference, dmgRgn, extraRgn, (HIMutableShapeRef) dmgRgn);
CFRelease(extraRgn);
-
+
/* Scroll the rectangle. */
[view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)];
-
- /*
- * Adjust the positions of the button subwindows that meet the scroll
- * area.
- */
-
- for (NSView *subview in [view subviews] ) {
- if ( [subview isKindOfClass:[NSButton class]] == YES ) {
- NSRect subframe = [subview frame];
- if ( NSIntersectsRect(scrollSrc, subframe) ||
- NSIntersectsRect(scrollDst, subframe) ) {
- TkpShiftButton((NSButton *)subview, delta );
- }
- }
- }
-
- /* Redisplay the scrolled area. */
- [view displayRect:scrollDst];
-
}
}
-
+
if ( dmgRgn == NULL ) {
dmgRgn = HIShapeCreateEmpty();
}
@@ -1657,13 +1633,13 @@ TkMacOSXSetupDrawingContext(
CGContextSetTextDrawingMode(dc.context, kCGTextFill);
CGContextConcatCTM(dc.context, t);
if (dc.clipRgn) {
-#ifdef TK_MAC_DEBUG_DRAWING
+ #ifdef TK_MAC_DEBUG_DRAWING
CGContextSaveGState(dc.context);
ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context);
CGContextSetRGBFillColor(dc.context, 1.0, 0.0, 0.0, 0.1);
CGContextEOFillPath(dc.context);
CGContextRestoreGState(dc.context);
-#endif /* TK_MAC_DEBUG_DRAWING */
+ #endif /* TK_MAC_DEBUG_DRAWING */
CGRect r;
if (!HIShapeIsRectangular(dc.clipRgn) || !CGRectContainsRect(
*HIShapeGetBounds(dc.clipRgn, &r),
@@ -1880,9 +1856,9 @@ TkpClipDrawableToRect(
macDraw->drawRgn = NULL;
}
if (width >= 0 && height >= 0) {
- CGRect drawRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff,
+ CGRect clipRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff,
width, height);
- HIShapeRef drawRgn = HIShapeCreateWithRect(&drawRect);
+ HIShapeRef drawRgn = HIShapeCreateWithRect(&clipRect);
if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) {
TkMacOSXUpdateClipRgn(macDraw->winPtr);
@@ -1895,9 +1871,9 @@ TkpClipDrawableToRect(
macDraw->drawRgn = drawRgn;
}
if (view && view != [NSView focusView] && [view lockFocusIfCanDraw]) {
- drawRect.origin.y = [view bounds].size.height -
- (drawRect.origin.y + drawRect.size.height);
- NSRectClip(NSRectFromCGRect(drawRect));
+ clipRect.origin.y = [view bounds].size.height -
+ (clipRect.origin.y + clipRect.size.height);
+ NSRectClip(NSRectFromCGRect(clipRect));
macDraw->flags |= TK_FOCUSED_VIEW;
}
} else {
diff --git a/macosx/tkMacOSXEmbed.c b/macosx/tkMacOSXEmbed.c
index 1d66b82..99f7584 100644
--- a/macosx/tkMacOSXEmbed.c
+++ b/macosx/tkMacOSXEmbed.c
@@ -174,6 +174,50 @@ TkpMakeWindow(
/*
*----------------------------------------------------------------------
*
+ * TkpScanWindowId --
+ *
+ * Given a string, produce the corresponding Window Id.
+ *
+ * Results:
+ * The return value is normally TCL_OK; in this case *idPtr will be set
+ * to the Window value equivalent to string. If string is improperly
+ * formed then TCL_ERROR is returned and an error message will be left in
+ * the interp's result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkpScanWindowId(
+ Tcl_Interp *interp,
+ CONST char * string,
+ Window *idPtr)
+{
+ int code;
+ Tcl_Obj obj;
+
+ obj.refCount = 1;
+ obj.bytes = (char *) string; /* DANGER?! */
+ obj.length = strlen(string);
+ obj.typePtr = NULL;
+
+ code = Tcl_GetLongFromObj(interp, &obj, (long *)idPtr);
+
+ if (obj.refCount > 1) {
+ Tcl_Panic("invalid sharing of Tcl_Obj on C stack");
+ }
+ if (obj.typePtr && obj.typePtr->freeIntRepProc) {
+ obj.typePtr->freeIntRepProc(&obj);
+ }
+ return code;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TkpUseWindow --
*
* This procedure causes a Tk window to use a given X window as its
@@ -215,7 +259,7 @@ TkpUseWindow(
}
/*
- * Decode the container pointer, and look for it among the list of
+ * Decode the container window ID, and look for it among the list of
* available containers.
*
* N.B. For now, we are limiting the containers to be in the same Tk
@@ -223,7 +267,7 @@ TkpUseWindow(
* containers.
*/
- if (Tcl_GetInt(interp, string, (int*) &parent) != TCL_OK) {
+ if (TkpScanWindowId(interp, string, (Window *)&parent) != TCL_OK) {
return TCL_ERROR;
}
diff --git a/macosx/tkMacOSXHLEvents.c b/macosx/tkMacOSXHLEvents.c
index 8d51c33..daf860f 100644
--- a/macosx/tkMacOSXHLEvents.c
+++ b/macosx/tkMacOSXHLEvents.c
@@ -217,7 +217,6 @@ OappHandler(
AppleEvent *reply,
SRefCon handlerRefcon)
{
- Tcl_CmdInfo dummy;
Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
if (interp &&
@@ -289,7 +288,6 @@ PrefsHandler(
AppleEvent *reply,
SRefCon handlerRefcon)
{
- Tcl_CmdInfo dummy;
Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon;
if (interp &&
@@ -422,7 +420,6 @@ PrintHandler(
long count, index;
AEKeyword keyword;
Tcl_DString command, pathName;
- Tcl_CmdInfo dummy;
int code;
/*
@@ -543,8 +540,12 @@ ScriptHandler(
theErr = FSRefToDString(&file, &scriptName);
if (theErr == noErr) {
- tclErr = Tcl_FSEvalFileEx(interp, Tcl_DStringValue(&scriptName), NULL);
+ Tcl_Obj *pathName =
+ Tcl_NewStringObj(Tcl_DStringValue(&scriptName), -1);
Tcl_DStringFree(&scriptName);
+
+ tclErr = Tcl_FSEvalFile(interp, pathName);
+ Tcl_DecrRefCount(pathName);
} else {
sprintf(errString, "AEDoScriptHandler: file not found");
AEPutParamPtr(reply, keyErrorString, typeChar, errString,
diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c
index aaeb348..6a881d3 100644
--- a/macosx/tkMacOSXInit.c
+++ b/macosx/tkMacOSXInit.c
@@ -53,10 +53,6 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
- (void) _setupWindowNotifications;
@end
-@interface TKApplication(TKScrlbr)
-- (void) _setupScrollBarNotifications;
-@end
-
@interface TKApplication(TKMenus)
- (void) _setupMenus;
@end
@@ -91,11 +87,9 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
- (void) _setupEventLoop
{
- _running = 1;
- if (!_appFlags._hasBeenRun) {
- _appFlags._hasBeenRun = YES;
- [self finishLaunching];
- }
+
+ /*Remove private API flags here.*/
+ [self finishLaunching];
[self setWindowsNeedUpdate:YES];
}
@@ -110,7 +104,6 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
selector:@selector(_postedNotification:) name:nil object:nil];
#endif
[self _setupWindowNotifications];
- [self _setupScrollBarNotifications];
[self _setupApplicationNotifications];
}
@@ -245,7 +238,7 @@ TkpInit(
Tcl_Panic("Mac OS X 10.%d or later required !",
(MAC_OS_X_VERSION_MIN_REQUIRED/10)-100);
}
-
+
#ifdef TK_FRAMEWORK
/*
diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c
index 0cfb663..c9ad9f1 100644
--- a/macosx/tkMacOSXKeyEvent.c
+++ b/macosx/tkMacOSXKeyEvent.c
@@ -272,8 +272,9 @@ static unsigned isFunctionKey(unsigned int code);
NSString *str = [aString respondsToSelector: @selector (string)] ?
[aString string] : aString;
if (NS_KEYLOG)
- NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
- selRange.length, selRange.location);
+ NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu", str,
+ (unsigned long) [str length], (unsigned long) selRange.length,
+ (unsigned long) selRange.location);
if (privateWorkingText != nil)
[self deleteWorkingText];
@@ -293,7 +294,8 @@ static unsigned isFunctionKey(unsigned int code);
if (privateWorkingText == nil)
return;
if (NS_KEYLOG)
- NSLog(@"deleteWorkingText len = %d\n", [privateWorkingText length]);
+ NSLog(@"deleteWorkingText len = %lu\n",
+ (unsigned long)[privateWorkingText length]);
[privateWorkingText release];
privateWorkingText = nil;
processingCompose = NO;
diff --git a/macosx/tkMacOSXKeyboard.c b/macosx/tkMacOSXKeyboard.c
index 54f99d3..7ac087d 100644
--- a/macosx/tkMacOSXKeyboard.c
+++ b/macosx/tkMacOSXKeyboard.c
@@ -734,7 +734,8 @@ TkpGetKeySym(
*/
if (eventPtr->xany.send_event == -1) {
- int modifier = eventPtr->xkey.keycode;
+
+ int modifier = eventPtr->xkey.keycode & NSDeviceIndependentModifierFlagsMask;
if (modifier == NSCommandKeyMask) {
return XK_Meta_L;
diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c
index a8e9f2f..85e1d6c 100644
--- a/macosx/tkMacOSXMenu.c
+++ b/macosx/tkMacOSXMenu.c
@@ -757,7 +757,7 @@ TkpPostMenu(
* to be posted. */
int y) /* The global y-coordinate */
{
-
+
/* Get the object that holds this Tk Window.*/
Tk_Window root;
@@ -765,7 +765,7 @@ TkpPostMenu(
if (root == NULL) {
return TCL_ERROR;
}
-
+
Drawable d = Tk_WindowId(root);
NSView *rootview = TkMacOSXGetRootControl(d);
NSWindow *win = [rootview window];
diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c
index df42763..a85e572 100644
--- a/macosx/tkMacOSXMenubutton.c
+++ b/macosx/tkMacOSXMenubutton.c
@@ -5,66 +5,70 @@
* menubutton widget.
*
* Copyright (c) 1996 by Sun Microsystems, Inc.
- * Copyright 2001-2009, Apple Inc.
- * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2001, Apple Computer, Inc.
+ * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright 2007 Revar Desmera.
+ * Copyright 2015 Kevin Walzer/WordTech Communications LLC.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
*/
#include "tkMacOSXPrivate.h"
+#include "tkMenu.h"
#include "tkMenubutton.h"
#include "tkMacOSXFont.h"
#include "tkMacOSXDebug.h"
-/*
-#ifdef TK_MAC_DEBUG
-#define TK_MAC_DEBUG_MENUBUTTON
-#endif
-*/
+#define FIRST_DRAW 2
+#define ACTIVE 4
-typedef struct MacMenuButton {
- TkMenuButton info;
- NSPopUpButton *button;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- int fix;
-#endif
-} MacMenuButton;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
+typedef struct {
+ Tk_3DBorder border;
+ int relief;
+ GC gc;
+ int hasImageOrBitmap;
+} DrawParams;
+
/*
- * Use the following heuristic conversion constants to make NSButton-based
- * widget metrics match up with the old Carbon control buttons (for the
- * default Lucida Grande 13 font).
- * TODO: provide a scriptable way to turn this off and use the raw NSButton
- * metrics (will also need dynamic adjustment of the default padding,
- * c.f. tkMacOSXDefault.h).
+ * Declaration of Mac specific button structure.
*/
-typedef struct {
- int trimW, trimH, inset, shrinkW, offsetX, offsetY;
-} BoundsFix;
-
-#define fixForStyle(style) ( \
- style == NSRoundedBezelStyle ? 1 : \
- style == NSRegularSquareBezelStyle ? 2 : \
- style == NSShadowlessSquareBezelStyle ? 3 : \
- INT_MIN)
-
-static const BoundsFix boundsFixes[] = {
- [fixForStyle(NSRoundedBezelStyle)] = { 14, 10, -2, -1},
- [fixForStyle(NSRegularSquareBezelStyle)] = { 6, 13, -2, 1, 1},
- [fixForStyle(NSShadowlessSquareBezelStyle)] = { 15, 0, 2 },
-};
-
-#endif
+typedef struct MacMenuButton {
+ TkMenuButton info; /* Generic button info. */
+ int flags;
+ ThemeButtonKind btnkind;
+ HIThemeButtonDrawInfo drawinfo;
+ HIThemeButtonDrawInfo lastdrawinfo;
+ DrawParams drawParams;
+} MacMenuButton;
/*
* Forward declarations for procedures defined later in this file:
*/
static void MenuButtonEventProc(ClientData clientData, XEvent *eventPtr);
+static void MenuButtonBackgroundDrawCB ( MacMenuButton *ptr, SInt16 depth, Boolean isColorDev);
+static void MenuButtonContentDrawCB ( ThemeButtonKind kind, const HIThemeButtonDrawInfo * info, MacMenuButton *ptr, SInt16 depth, Boolean isColorDev);
+static void MenuButtonEventProc ( ClientData clientData, XEvent *eventPtr);
+static void TkMacOSXComputeMenuButtonParams (TkMenuButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo* drawinfo);
+static int TkMacOSXComputeMenuButtonDrawParams (TkMenuButton * butPtr, DrawParams * dpPtr);
+static void TkMacOSXDrawMenuButton (MacMenuButton *butPtr,
+ GC gc, Pixmap pixmap);
+static void DrawMenuButtonImageAndText(TkMenuButton* butPtr);
+
+/*
+ * The structure below defines menubutton class behavior by means of
+ * procedures that can be invoked from generic window code.
+ */
+
+Tk_ClassProcs tkpMenubuttonClass = {
+ sizeof(Tk_ClassProcs), /* size */
+ TkMenuButtonWorldChanged, /* worldChangedProc */
+};
/*
@@ -87,113 +91,94 @@ TkMenuButton *
TkpCreateMenuButton(
Tk_Window tkwin)
{
- MacMenuButton *macButtonPtr = ckalloc(sizeof(MacMenuButton));
+ MacMenuButton *mbPtr = (MacMenuButton *) ckalloc(sizeof(MacMenuButton));
- macButtonPtr->button = nil;
Tk_CreateEventHandler(tkwin, ActivateMask,
- MenuButtonEventProc, (ClientData) macButtonPtr);
- return (TkMenuButton *) macButtonPtr;
+ MenuButtonEventProc, (ClientData) mbPtr);
+ mbPtr->flags = FIRST_DRAW;
+ mbPtr->btnkind = kThemePopupButton;
+ bzero(&mbPtr->drawinfo, sizeof(mbPtr->drawinfo));
+ bzero(&mbPtr->lastdrawinfo, sizeof(mbPtr->lastdrawinfo));
+
+ return (TkMenuButton *) mbPtr;
}
/*
*----------------------------------------------------------------------
*
- * TkpDestroyMenuButton --
+ * TkpDisplayMenuButton --
*
- * Free data structures associated with the menubutton control.
+ * This procedure is invoked to display a menubutton widget.
*
* Results:
* None.
*
* Side effects:
- * Restores the default control state.
+ * Commands are output to X to display the menubutton in its
+ * current mode.
*
*----------------------------------------------------------------------
*/
void
-TkpDestroyMenuButton(
- TkMenuButton *mbPtr)
+TkpDisplayMenuButton(
+ ClientData clientData) /* Information about widget. */
{
- MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr;
- [macButtonPtr->button setTag:(NSInteger)-1];
+ MacMenuButton *mbPtr = (MacMenuButton *)clientData;
+ TkMenuButton *butPtr = (TkMenuButton *) clientData;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ DrawParams* dpPtr = &mbPtr->drawParams;
+
+ butPtr->flags &= ~REDRAW_PENDING;
+ if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
+ return;
+ }
+
+ pixmap = (Pixmap) Tk_WindowId(tkwin);
+
+ TkMacOSXComputeMenuButtonDrawParams(butPtr, dpPtr);
- TkMacOSXMakeCollectableAndRelease(macButtonPtr->button);
+ /*
+ * set up clipping region. Make sure the we are using the port
+ * for this button, or we will set the wrong window's clip.
+ */
+
+ TkMacOSXSetUpClippingRgn(pixmap);
+
+ /* Draw the native portion of the buttons. */
+ TkMacOSXDrawMenuButton(mbPtr, dpPtr->gc, pixmap);
+
+ /* Draw highlight border, if needed. */
+ if (butPtr->highlightWidth < 3) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ Tk_Draw3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin),
+ butPtr->highlightWidth, TK_RELIEF_SOLID);
+ }
+ }
}
/*
*----------------------------------------------------------------------
*
- * TkpDisplayMenuButton --
+ * TkpDestroyMenuButton --
*
- * This function is invoked to display a menubutton widget.
+ * Free data structures associated with the menubutton control.
*
* Results:
* None.
*
* Side effects:
- * Commands are output to X to display the menubutton in its current
- * mode.
+ * Restores the default control state.
*
*----------------------------------------------------------------------
*/
void
-TkpDisplayMenuButton(
- ClientData clientData) /* Information about widget. */
+TkpDestroyMenuButton(
+ TkMenuButton *mbPtr)
{
- TkMenuButton *mbPtr = (TkMenuButton *) clientData;
- MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr;
- NSPopUpButton *button = macButtonPtr->button;
- Tk_Window tkwin = mbPtr->tkwin;
- TkWindow *winPtr = (TkWindow *) tkwin;
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
- TkMacOSXDrawingContext dc;
- NSView *view = TkMacOSXDrawableView(macWin);
- CGFloat viewHeight = [view bounds].size.height;
- CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
- .ty = viewHeight};
- NSRect frame;
- int enabled;
-
- mbPtr->flags &= ~REDRAW_PENDING;
- if (!tkwin || !Tk_IsMapped(tkwin) || !view ||
- !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
- return;
- }
- CGContextConcatCTM(dc.context, t);
- Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, mbPtr->normalBorder, 0, 0,
- Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
- if ([button superview] != view) {
- [view addSubview:button];
- }
- enabled = !(mbPtr->state == STATE_DISABLED);
- [button setEnabled:enabled];
- if (enabled) {
- [[button cell] setHighlighted:(mbPtr->state == STATE_ACTIVE)];
- }
- frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin),
- Tk_Height(tkwin));
- frame = NSInsetRect(frame, mbPtr->inset, mbPtr->inset);
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- BoundsFix boundsFix = boundsFixes[macButtonPtr->fix];
- frame = NSOffsetRect(frame, boundsFix.offsetX, boundsFix.offsetY);
- frame.size.width -= boundsFix.shrinkW;
- frame = NSInsetRect(frame, boundsFix.inset, boundsFix.inset);
- }
-#endif
- frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
- if (!NSEqualRects(frame, [button frame])) {
- [button setFrame:frame];
- }
- [button displayRectIgnoringOpacity:[button bounds]];
- TkMacOSXRestoreDrawingContext(&dc);
-#ifdef TK_MAC_DEBUG_MENUBUTTON
- TKLog(@"menubutton %s frame %@ width %d height %d",
- ((TkWindow *)mbPtr->tkwin)->pathName, NSStringFromRect(frame),
- Tk_Width(tkwin), Tk_Height(tkwin));
-#endif
}
/*
@@ -201,7 +186,7 @@ TkpDisplayMenuButton(
*
* TkpComputeMenuButtonGeometry --
*
- * After changes in a menu button's text or bitmap, this function
+ * After changes in a menu button's text or bitmap, this procedure
* recomputes the menu button's geometry and passes this information
* along to the geometry manager for the window.
*
@@ -215,205 +200,504 @@ TkpDisplayMenuButton(
*/
void
-TkpComputeMenuButtonGeometry(
- TkMenuButton *mbPtr) /* Widget record for menu button. */
+TkpComputeMenuButtonGeometry(butPtr)
+ register TkMenuButton *butPtr; /* Widget record for menu button. */
{
- MacMenuButton *macButtonPtr = (MacMenuButton *) mbPtr;
- NSPopUpButton *button = macButtonPtr->button;
- NSPopUpButtonCell *cell;
- NSMenuItem *menuItem;
- NSBezelStyle style = NSRoundedBezelStyle;
- NSFont *font;
- NSRect bounds = NSZeroRect, titleRect = NSZeroRect;
- int haveImage = (mbPtr->image || mbPtr->bitmap != None), haveText = 0;
- int haveCompound = (mbPtr->compound != COMPOUND_NONE);
- int width, height;
-
- if (!button) {
- button = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:YES];
- macButtonPtr->button = TkMacOSXMakeUncollectable(button);
- cell = [button cell];
- [cell setUsesItemFromMenu:NO];
- menuItem = [[[NSMenuItem alloc] initWithTitle:@""
- action:NULL keyEquivalent:@""] autorelease];
- [cell setMenuItem:menuItem];
- } else {
- cell = [button cell];
- menuItem = [cell menuItem];
+ int width, height, avgWidth, haveImage = 0, haveText = 0;
+ MacMenuButton *mbPtr = (MacMenuButton*)butPtr;
+ int txtWidth, txtHeight;
+ Tk_FontMetrics fm;
+ DrawParams drawParams;
+ int paddingx = 0;
+ int paddingy = 0;
+
+ /*
+ * First figure out the size of the contents of the button.
+ */
+
+ width = 0;
+ height = 0;
+ txtWidth = 0;
+ txtHeight = 0;
+ avgWidth = 0;
+
+ TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
+
+ if (butPtr->image != NULL) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
}
- if (haveImage) {
- style = NSShadowlessSquareBezelStyle;
- } else if (!mbPtr->indicatorOn) {
- style = NSRegularSquareBezelStyle;
+
+ if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) {
+ Tk_FreeTextLayout(butPtr->textLayout);
+ butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
+ butPtr->text, -1, butPtr->wrapLength,
+ butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
+
+ txtWidth = butPtr->textWidth;
+ txtHeight = butPtr->textHeight;
+ avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
+ Tk_GetFontMetrics(butPtr->tkfont, &fm);
+ haveText = (txtWidth != 0 && txtHeight != 0);
}
- [button setBezelStyle:style];
- [cell setArrowPosition:(mbPtr->indicatorOn ? NSPopUpArrowAtBottom :
- NSPopUpNoArrow)];
-#if 0
- NSControlSize controlSize = NSRegularControlSize;
-
- if (mbPtr->borderWidth <= 2) {
- controlSize = NSMiniControlSize;
- } else if (mbPtr->borderWidth == 3) {
- controlSize = NSSmallControlSize;
+
+ /*
+ * If the button is compound (ie, it shows both an image and text),
+ * the new geometry is a combination of the image and text geometry.
+ * We only honor the compound bit if the button has both text and an
+ * image, because otherwise it is not really a compound button.
+ */
+
+ if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM: {
+ /*
+ * Image is above or below text
+ */
+
+ height += txtHeight + butPtr->padY;
+ width = (width > txtWidth ? width : txtWidth);
+ break;
+ }
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT: {
+ /*
+ * Image is left or right of text
+ */
+
+ width += txtWidth + butPtr->padX;
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ }
+ case COMPOUND_CENTER: {
+ /*
+ * Image and text are superimposed
+ */
+
+ width = (width > txtWidth ? width : txtWidth);
+ height = (height > txtHeight ? height : txtHeight);
+ break;
+ }
+ case COMPOUND_NONE: {break;}
+ }
+
+ if (butPtr->width > 0) {
+ width = butPtr->width;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height;
+ }
+
+ } else {
+ if (haveImage) {
+ if (butPtr->width > 0) {
+ width = butPtr->width;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height;
+ }
+ } else {
+ width = txtWidth;
+ height = txtHeight;
+ if (butPtr->width > 0) {
+ width = butPtr->width * avgWidth;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height * fm.linespace;
+ }
+ }
}
- [cell setControlSize:controlSize];
-#endif
-
- if (mbPtr->text && *(mbPtr->text) && (!haveImage || haveCompound)) {
- NSString *title = [[NSString alloc] initWithUTF8String:mbPtr->text];
- [button setTitle:title];
- [title release];
- haveText = 1;
+ width += 2 * butPtr->padX - 2;
+ height += 2 * butPtr->padY - 2;
+
+ /*Add padding for button arrows.*/
+ width += 22;
+
+ /*
+ * Now figure out the size of the border decorations for the button.
+ */
+
+ if (butPtr->highlightWidth < 0) {
+ butPtr->highlightWidth = 0;
}
- haveCompound = (haveCompound && haveImage && haveText);
- if (haveText) {
- NSTextAlignment alignment = NSNaturalTextAlignment;
-
- switch (mbPtr->justify) {
- case TK_JUSTIFY_LEFT:
- alignment = NSLeftTextAlignment;
- break;
- case TK_JUSTIFY_RIGHT:
- alignment = NSRightTextAlignment;
- break;
- case TK_JUSTIFY_CENTER:
- alignment = NSCenterTextAlignment;
- break;
- }
- [button setAlignment:alignment];
- } else {
- [button setTitle:@""];
+ butPtr->inset = 0;
+ butPtr->inset += butPtr->highlightWidth;
+
+ TkMacOSXComputeMenuButtonDrawParams(butPtr,&drawParams);
+
+ HIRect tmpRect;
+ HIRect contBounds;
+
+ tmpRect = CGRectMake(0, 0, width, height);
+
+ HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds);
+
+
+
+ /* If the content region has a minimum height, match it. */
+ if (height < contBounds.size.height) {
+ height = contBounds.size.height;
+ }
+
+ /* If the content region has a minimum width, match it. */
+ if (width < contBounds.size.width) {
+ width = contBounds.size.width;
+ }
+
+ /* Pad to fill difference between content bounds and button bounds. */
+ paddingx = tmpRect.origin.x - contBounds.origin.x;
+ paddingy = tmpRect.origin.y - contBounds.origin.y;
+
+ if (paddingx > 0) {
+ width += paddingx;
}
- font = TkMacOSXNSFontForFont(mbPtr->tkfont);
- if (font) {
- [button setFont:font];
+ if (paddingy > 0) {
+ height += paddingy;
}
- if (haveImage) {
- int width, height;
- NSImage *image;
- NSCellImagePosition pos = NSImageOnly;
-
- if (mbPtr->image) {
- Tk_SizeOfImage(mbPtr->image, &width, &height);
- image = TkMacOSXGetNSImageWithTkImage(mbPtr->display,
- mbPtr->image, width, height);
- } else {
- Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
- image = TkMacOSXGetNSImageWithBitmap(mbPtr->display,
- mbPtr->bitmap, mbPtr->normalTextGC, width, height);
- }
- if (haveCompound) {
- switch ((enum compound) mbPtr->compound) {
- case COMPOUND_TOP:
- pos = NSImageAbove;
- break;
- case COMPOUND_BOTTOM:
- pos = NSImageBelow;
- break;
- case COMPOUND_LEFT:
- pos = NSImageLeft;
- break;
- case COMPOUND_RIGHT:
- pos = NSImageRight;
- break;
- case COMPOUND_CENTER:
- pos = NSImageOverlaps;
- break;
- case COMPOUND_NONE:
- pos = NSImageOnly;
- break;
- }
- }
- [button setImagePosition:pos];
- [menuItem setImage:image];
- bounds.size = cell ? [cell cellSize] : NSZeroSize;
- if (bounds.size.height < height + 8) { /* workaround AppKit sizing bug */
- bounds.size.height = height + 8;
- }
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (!mbPtr->indicatorOn && tkMacOSXUseCompatibilityMetrics) {
- bounds.size.width -= 16;
- }
-#endif
- } else {
- bounds.size = cell ? [cell cellSize] : NSZeroSize;
+
+ width += butPtr->inset*2;
+ height += butPtr->inset*2;
+
+
+ Tk_GeometryRequest(butPtr->tkwin, width, height);
+ Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawMenuButtonImageAndText --
+ *
+ * Draws the image and text associated witha button or label.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The image and text are drawn.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+DrawMenuButtonImageAndText(
+ TkMenuButton* butPtr)
+{
+ MacMenuButton *mbPtr = (MacMenuButton*)butPtr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ int haveImage = 0;
+ int haveText = 0;
+ int imageWidth = 0;
+ int imageHeight = 0;
+ int imageXOffset = 0;
+ int imageYOffset = 0;
+ int textXOffset = 0;
+ int textYOffset = 0;
+ int width = 0;
+ int height = 0;
+ int fullWidth = 0;
+ int fullHeight = 0;
+ int pressed;
+
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- if (haveText) {
- titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect;
- if (mbPtr->wrapLength > 0 &&
- titleRect.size.width > mbPtr->wrapLength) {
- if (style == NSRoundedBezelStyle) {
- [button setBezelStyle:(style = NSRegularSquareBezelStyle)];
- bounds.size = cell ? [cell cellSize] : NSZeroSize;
- titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect;
- }
- bounds.size.width -= titleRect.size.width - mbPtr->wrapLength;
- bounds.size.height = 40000.0;
- [cell setWraps:YES];
- bounds.size = cell ? [cell cellSizeForBounds:bounds] : NSZeroSize;
-#ifdef TK_MAC_DEBUG_MENUBUTTON
- titleRect = cell ? [cell titleRectForBounds:bounds] : NSZeroRect;
-#endif
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- bounds.size.height += 3;
- }
-#endif
- }
+
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+
+ if (butPtr->image != None) {
+ Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
}
- width = lround(bounds.size.width);
- height = lround(bounds.size.height);
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
- if (tkMacOSXUseCompatibilityMetrics) {
- macButtonPtr->fix = fixForStyle(style);
- width -= boundsFixes[macButtonPtr->fix].trimW;
- height -= boundsFixes[macButtonPtr->fix].trimH;
+
+ imageWidth = width;
+ imageHeight = height;
+
+ if (mbPtr->drawinfo.state == kThemeStatePressed) {
+ /* Offset bitmaps by a bit when the button is pressed. */
+ pressed = 1;
}
-#endif
- if (haveImage || haveCompound) {
- if (mbPtr->width > 0) {
- width = mbPtr->width;
- }
- if (mbPtr->height > 0) {
- height = mbPtr->height;
+ haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
+ if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
+ int x = 0;
+ int y = 0;
+ textXOffset = 0;
+ textYOffset = 0;
+ fullWidth = 0;
+ fullHeight = 0;
+
+ switch ((enum compound) butPtr->compound) {
+ case COMPOUND_TOP:
+ case COMPOUND_BOTTOM: {
+ /* Image is above or below text */
+ if (butPtr->compound == COMPOUND_TOP) {
+ textYOffset = height + butPtr->padY;
+ } else {
+ imageYOffset = butPtr->textHeight + butPtr->padY;
+ }
+ fullHeight = height + butPtr->textHeight + butPtr->padY;
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ break;
+ }
+ case COMPOUND_LEFT:
+ case COMPOUND_RIGHT: {
+ /*
+ * Image is left or right of text
+ */
+
+ if (butPtr->compound == COMPOUND_LEFT) {
+ textXOffset = width + butPtr->padX - 2;
+ } else {
+ imageXOffset = butPtr->textWidth + butPtr->padX;
+ }
+ fullWidth = butPtr->textWidth + butPtr->padX + width;
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
+ }
+ case COMPOUND_CENTER: {
+ /*
+ * Image and text are superimposed
+ */
+
+ fullWidth = (width > butPtr->textWidth ? width :
+ butPtr->textWidth);
+ fullHeight = (height > butPtr->textHeight ? height :
+ butPtr->textHeight);
+ textXOffset = (fullWidth - butPtr->textWidth)/2;
+ imageXOffset = (fullWidth - width)/2;
+ textYOffset = (fullHeight - butPtr->textHeight)/2;
+ imageYOffset = (fullHeight - height)/2;
+ break;
+ }
+ case COMPOUND_NONE: {break;}
}
+
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ fullWidth, fullHeight, &x, &y);
+ imageXOffset += x;
+ imageYOffset += y;
+ textYOffset -= 1;
+
+ if (butPtr->image != NULL) {
+ Tk_RedrawImage(butPtr->image, 0, 0, width,
+ height, pixmap, imageXOffset, imageYOffset);
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc,
+ imageXOffset, imageYOffset);
+ XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width, (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+
+ Tk_DrawTextLayout(butPtr->display, pixmap,
+ dpPtr->gc, butPtr->textLayout,
+ x + textXOffset, y + textYOffset, 0, -1);
+ Tk_UnderlineTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout,
+ x + textXOffset, y + textYOffset,
+ butPtr->underline);
} else {
- if (mbPtr->width > 0) {
- int avgWidth = Tk_TextWidth(mbPtr->tkfont, "0", 1);
- width = mbPtr->width * avgWidth;
+ if (haveImage) {
+ int x = 0;
+ int y;
+ TkComputeAnchor(butPtr->anchor, tkwin,
+ butPtr->padX + butPtr->borderWidth,
+ butPtr->padY + butPtr->borderWidth,
+ width, height, &x, &y);
+ imageXOffset += x;
+ imageYOffset += y;
+
+ if (butPtr->image != NULL) {
+ Tk_RedrawImage(butPtr->image, 0, 0, width, height,
+ pixmap, imageXOffset, imageYOffset);
+ } else {
+ XSetClipOrigin(butPtr->display, dpPtr->gc, x, y);
+ XCopyPlane(butPtr->display, butPtr->bitmap,
+ pixmap, dpPtr->gc,
+ 0, 0, (unsigned int) width,
+ (unsigned int) height,
+ imageXOffset, imageYOffset, 1);
+ XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0);
+ }
+ } else {
+ /*Move x back by eight pixels to give the menubutton arrows room.*/
+ int x = 0;
+ int y;
+ textXOffset = 8;
+ TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
+ butPtr->textWidth, butPtr->textHeight, &x, &y);
+ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc,
+ butPtr->textLayout, x - textXOffset, y, 0, -1);
+ y += butPtr->textHeight/2;
+ }
+ }
+}
+
+
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TkMacOSXDrawMenuButton --
+ *
+ * This function draws the tk menubutton using Mac controls
+ * In addition, this code may apply custom colors passed
+ * in the TkMenubutton.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+TkMacOSXDrawMenuButton(
+ MacMenuButton *mbPtr, /* Mac menubutton. */
+ GC gc, /* The GC we are drawing into - needed for
+ * the bevel button */
+ Pixmap pixmap) /* The pixmap we are drawing into - needed
+ * for the bevel button */
+
+{
+ TkMenuButton * butPtr = ( TkMenuButton *)mbPtr;
+ TkWindow * winPtr;
+ HIRect cntrRect;
+ TkMacOSXDrawingContext dc;
+ DrawParams* dpPtr = &mbPtr->drawParams;
+ int useNewerHITools = 1;
+
+ winPtr = (TkWindow *)butPtr->tkwin;
+
+ TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo);
+
+ cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin),Tk_Height(butPtr->tkwin));
+
+ cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset);
+
+
+ if (useNewerHITools == 1) {
+ HIRect contHIRec;
+ static HIThemeButtonDrawInfo hiinfo;
+
+ MenuButtonBackgroundDrawCB((MacMenuButton*) mbPtr, 32, true);
+
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
}
- if (mbPtr->height > 0) {
- Tk_FontMetrics fm;
- Tk_GetFontMetrics(mbPtr->tkfont, &fm);
- height = mbPtr->height * fm.linespace;
+
+ hiinfo.version = 0;
+ hiinfo.state = mbPtr->drawinfo.state;
+ hiinfo.kind = mbPtr->btnkind;
+ hiinfo.value = mbPtr->drawinfo.value;
+ hiinfo.adornment = mbPtr->drawinfo.adornment;
+ hiinfo.animation.time.current = CFAbsoluteTimeGetCurrent();
+ if (hiinfo.animation.time.start == 0) {
+ hiinfo.animation.time.start = hiinfo.animation.time.current;
+ }
+
+ HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec);
+
+ TkMacOSXRestoreDrawingContext(&dc);
+
+ MenuButtonContentDrawCB( mbPtr->btnkind, &mbPtr->drawinfo, (MacMenuButton *)mbPtr, 32, true);
+ } else {
+ if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) {
+ return;
}
+
+
+ TkMacOSXRestoreDrawingContext(&dc);
}
- if (!haveImage || haveCompound) {
- width += 2*mbPtr->padX;
- height += 2*mbPtr->padY;
- }
- if (mbPtr->highlightWidth < 0) {
- mbPtr->highlightWidth = 0;
+ mbPtr->lastdrawinfo = mbPtr->drawinfo;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * MenuButtonBackgroundDrawCB --
+ *
+ * This function draws the background that
+ * lies under checkboxes and radiobuttons.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The background gets updated to the current color.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+MenuButtonBackgroundDrawCB (
+ MacMenuButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
+{
+ TkMenuButton* butPtr = (TkMenuButton*)ptr;
+ Tk_Window tkwin = butPtr->tkwin;
+ Pixmap pixmap;
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- if (haveImage) {
- mbPtr->inset = mbPtr->highlightWidth;
- width += 2*mbPtr->borderWidth;
- height += 2*mbPtr->borderWidth;
- } else {
- mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth;
+ pixmap = (Pixmap)Tk_WindowId(tkwin);
+
+ Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
+ Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * MenuButtonContentDrawCB --
+ *
+ * This function draws the label and image for the button.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The content of the button gets updated.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+MenuButtonContentDrawCB (
+ ThemeButtonKind kind,
+ const HIThemeButtonDrawInfo *drawinfo,
+ MacMenuButton *ptr,
+ SInt16 depth,
+ Boolean isColorDev)
+{
+ TkMenuButton *butPtr = (TkMenuButton *)ptr;
+ Tk_Window tkwin = butPtr->tkwin;
+
+ if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
+ return;
}
- Tk_GeometryRequest(mbPtr->tkwin, width + 2 * mbPtr->inset,
- height + 2 * mbPtr->inset);
- Tk_SetInternalBorder(mbPtr->tkwin, mbPtr->inset);
-#ifdef TK_MAC_DEBUG_MENUBUTTON
- TKLog(@"menubutton %s bounds %@ titleRect %@ width %d height %d inset %d borderWidth %d",
- ((TkWindow *)mbPtr->tkwin)->pathName, NSStringFromRect(bounds),
- NSStringFromRect(titleRect), width, height, mbPtr->inset,
- mbPtr->borderWidth);
-#endif
+
+ DrawMenuButtonImageAndText( butPtr);
}
/*
@@ -428,7 +712,7 @@ TkpComputeMenuButtonGeometry(
* None.
*
* Side effects:
- * When activation state changes, it is redisplayed.
+ * When it gets exposed, it is redisplayed.
*
*--------------------------------------------------------------
*/
@@ -438,27 +722,124 @@ MenuButtonEventProc(
ClientData clientData, /* Information about window. */
XEvent *eventPtr) /* Information about event. */
{
- TkMenuButton *mbPtr = (TkMenuButton *) clientData;
+ TkMenuButton *buttonPtr = (TkMenuButton *) clientData;
+ MacMenuButton *mbPtr = (MacMenuButton *) clientData;
- if (!mbPtr->tkwin || !Tk_IsMapped(mbPtr->tkwin)) {
- return;
+ if (eventPtr->type == ActivateNotify
+ || eventPtr->type == DeactivateNotify) {
+ if ((buttonPtr->tkwin == NULL) || (!Tk_IsMapped(buttonPtr->tkwin))) {
+ return;
+ }
+ if (eventPtr->type == ActivateNotify) {
+ mbPtr->flags |= ACTIVE;
+ } else {
+ mbPtr->flags &= ~ACTIVE;
+ }
+ if ((buttonPtr->flags & REDRAW_PENDING) == 0) {
+ Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) buttonPtr);
+ buttonPtr->flags |= REDRAW_PENDING;
+ }
}
- switch (eventPtr->type) {
- case ActivateNotify:
- case DeactivateNotify:
- if (!(mbPtr->flags & REDRAW_PENDING)) {
- Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr);
- mbPtr->flags |= REDRAW_PENDING;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXComputeMenuButtonParams --
+ *
+ * This procedure computes the various parameters used
+ * when creating a Carbon Appearance control.
+ * These are determined by the various tk button parameters
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Sets the btnkind and drawinfo parameters
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+TkMacOSXComputeMenuButtonParams(TkMenuButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo *drawinfo)
+{
+ MacMenuButton *mbPtr = (MacMenuButton *)butPtr;
+
+ if (butPtr->image || butPtr->bitmap) {
+ /* TODO: allow for Small and Mini menubuttons. */
+ *btnkind = kThemePopupButton;
+ } else {
+ if (!butPtr->text || !*butPtr->text) {
+ *btnkind = kThemeArrowButton;
+ } else {
+ *btnkind = kThemePopupButton;
+ }
+ }
+
+ drawinfo->value = kThemeButtonOff;
+
+ if ((mbPtr->flags & FIRST_DRAW) != 0) {
+ mbPtr->flags &= ~FIRST_DRAW;
+ if (Tk_MacOSXIsAppInFront()) {
+ mbPtr->flags |= ACTIVE;
}
- break;
}
+
+ drawinfo->state = kThemeStateInactive;
+ if ((mbPtr->flags & ACTIVE) == 0) {
+ if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailableInactive;
+ } else {
+ drawinfo->state = kThemeStateInactive;
+ }
+ } else if (butPtr->state == STATE_DISABLED) {
+ drawinfo->state = kThemeStateUnavailable;
+ } else {
+ drawinfo->state = kThemeStateActive;
+ }
+
+ drawinfo->adornment = kThemeAdornmentNone;
+ if (butPtr->highlightWidth >= 3) {
+ if ((butPtr->flags & GOT_FOCUS)) {
+ drawinfo->adornment |= kThemeAdornmentFocus;
+ }
+ }
+ drawinfo->adornment |= kThemeAdornmentArrowDoubleArrow;
}
/*
- * Local Variables:
- * mode: objc
- * c-basic-offset: 4
- * fill-column: 79
- * coding: utf-8
- * End:
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXComputeMenuButtonDrawParams --
+ *
+ * This procedure computes the various parameters used
+ * when drawing a button
+ * These are determined by the various tk button parameters
+ *
+ * Results:
+ * 1 if control will be used, 0 otherwise.
+ *
+ * Side effects:
+ * Sets the button draw parameters
+ *
+ *----------------------------------------------------------------------
*/
+
+static int
+TkMacOSXComputeMenuButtonDrawParams(TkMenuButton * butPtr, DrawParams * dpPtr)
+{
+ dpPtr->hasImageOrBitmap = ((butPtr->image != NULL)
+ || (butPtr->bitmap != None));
+ dpPtr->border = butPtr->normalBorder;
+ if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
+ dpPtr->gc = butPtr->disabledGC;
+ } else if (butPtr->state == STATE_ACTIVE) {
+ dpPtr->gc = butPtr->activeTextGC;
+ dpPtr->border = butPtr->activeBorder;
+ } else {
+ dpPtr->gc = butPtr->normalTextGC;
+ }
+
+ return 1;
+}
+
diff --git a/macosx/tkMacOSXPort.h b/macosx/tkMacOSXPort.h
index 1576ec7..0c3b347 100644
--- a/macosx/tkMacOSXPort.h
+++ b/macosx/tkMacOSXPort.h
@@ -141,18 +141,10 @@
/*
* This macro stores a representation of the window handle in a string.
- * This should perhaps use the real size of an XID.
*/
#define TkpPrintWindowId(buf,w) \
- sprintf((buf), "0x%x", (unsigned int) (w))
-
-/*
- * TkpScanWindowId is just an alias for Tcl_GetInt on Unix.
- */
-
-#define TkpScanWindowId(i,s,wp) \
- Tcl_GetInt((i),(s),(int *) (wp))
+ sprintf((buf), "0x%lx", (unsigned long) (w))
/*
* Turn off Tk double-buffering as Aqua windows are already double-buffered.
diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h
index adc7106..3664850 100644
--- a/macosx/tkMacOSXPrivate.h
+++ b/macosx/tkMacOSXPrivate.h
@@ -180,9 +180,6 @@ MODULE_SCOPE CGFloat tkMacOSXZeroScreenHeight;
MODULE_SCOPE CGFloat tkMacOSXZeroScreenTop;
MODULE_SCOPE int tkMacOSXGCEnabled;
MODULE_SCOPE long tkMacOSXMacOSXVersion;
-#if TK_MAC_BUTTON_USE_COMPATIBILITY_METRICS
-MODULE_SCOPE int tkMacOSXUseCompatibilityMetrics;
-#endif
/*
* Prototypes for TkMacOSXRegion.c.
diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c
index ebb99f3..7370ff5 100644
--- a/macosx/tkMacOSXScrlbr.c
+++ b/macosx/tkMacOSXScrlbr.c
@@ -7,79 +7,24 @@
* Copyright (c) 1996 by Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
- *
+ * Copyright (c) 2015 Kevin Walzer/WordTech Commununications LLC.
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#include "tkMacOSXPrivate.h"
+#include "tkInt.h"
#include "tkScrollbar.h"
+#include "tkMacOSXPrivate.h"
-/*
-#ifdef TK_MAC_DEBUG
-#define TK_MAC_DEBUG_SCROLLBAR
-#endif
-*/
-
-NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr);
-
-/*
- * A subclass of NSScroller with sanity checking:
- *
- * NSScrollers created by Tk will have their tag set to a pointer to the
- * TkScrollbar which manages the NSScroller. This allows an NSScroller to be
- * aware of the state of its Tk parent. This subclass overrides the drawRect
- * method so that it will not draw itself if the widget is completely outside
- * of its container.
- */
-
-@interface TkNSScroller: NSScroller
--(void) drawRect:(NSRect)dirtyRect;
-
-@end
-
-@implementation TkNSScroller
-
- - (void)drawRect:(NSRect)dirtyRect
- {
- NSInteger tag = [self tag];
- if ( tag != -1) {
- TkScrollbar *scrollPtr = (TkScrollbar *)tag;
- MacDrawable* macWin = (MacDrawable *)scrollPtr;
- Tk_Window tkwin = scrollPtr->tkwin;
- NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr);
- /* Do not draw if the widget is misplaced or unmapped. */
- if ( NSIsEmptyRect(Tkframe) ||
- ! macWin->winPtr->flags & TK_MAPPED ||
- ! NSEqualRects(Tkframe, [self frame])
- ) {
- return;
- }
-
- /*
- * Do not draw if the widget is completely outside of its parent.
- */
- if (tkwin) {
- int parent_height = Tk_Height(Tk_Parent(tkwin));
- int widget_height = Tk_Height(tkwin);
- int y = Tk_Y(tkwin);
- if ( y > parent_height || y + widget_height < 0 ) {
- return;
- }
-
- int parent_width = Tk_Width(Tk_Parent(tkwin));
- int widget_width = Tk_Width(tkwin);
- int x = Tk_X(tkwin);
- if (x > parent_width || x + widget_width < 0) {
- return;
- }
- }
- }
- [super drawRect:dirtyRect];
- }
-@end
+#define MIN_SCROLLBAR_VALUE 0
+/*Borrowed from ttkMacOSXTheme.c to provide appropriate scaling of scrollbar values.*/
+#ifdef __LP64__
+#define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum))
+#else
+#define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum))
+#endif /* __LP64__ */
/*
@@ -87,33 +32,15 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr);
*/
typedef struct MacScrollbar {
- TkScrollbar info;
- TkNSScroller *scroller;
- int variant;
+ TkScrollbar information; /* Generic scrollbar info. */
+ GC troughGC; /* For drawing trough. */
+ GC copyGC; /* Used for copying from pixmap onto screen. */
} MacScrollbar;
-typedef struct ScrollbarMetrics {
- SInt32 width, minThumbHeight;
- int minHeight, topArrowHeight, bottomArrowHeight;
- NSControlSize controlSize;
-} ScrollbarMetrics;
-
-static ScrollbarMetrics metrics[2] = {
- {15, 54, 26, 14, 14, NSRegularControlSize}, /* kThemeScrollBarMedium */
- {11, 40, 20, 10, 10, NSSmallControlSize}, /* kThemeScrollBarSmall */
-};
-
-/*
- * Declarations for functions defined in this file.
- */
-
-static void UpdateScrollbarMetrics(void);
-static void ScrollbarEventProc(ClientData clientData,
- XEvent *eventPtr);
-
-
/*
- * The class procedure table for the scrollbar widget.
+ * The class procedure table for the scrollbar widget. All fields except size
+ * are left initialized to NULL, which should happen automatically since the
+ * variable is declared at this scope.
*/
const Tk_ClassProcs tkpScrollbarProcs = {
@@ -122,151 +49,38 @@ const Tk_ClassProcs tkpScrollbarProcs = {
NULL, /* createProc */
NULL /* modalProc */
};
-
-#pragma mark TKApplication(TKScrlbr)
-
-#define NSAppleAquaScrollBarVariantChanged @"AppleAquaScrollBarVariantChanged"
-
-@implementation TKApplication(TKScrlbr)
-- (void) tkScroller: (TkNSScroller *) scroller
-{
- NSScrollerPart hitPart = [scroller hitPart];
- TkScrollbar *scrollPtr = (TkScrollbar *)[scroller tag];
- Tcl_DString cmdString;
- Tcl_Interp *interp;
- int result;
-
- if (!scrollPtr || !scrollPtr->command || !scrollPtr->commandSize ||
- hitPart == NSScrollerNoPart) {
- return;
- }
- Tcl_DStringInit(&cmdString);
- Tcl_DStringAppend(&cmdString, scrollPtr->command,
- scrollPtr->commandSize);
- switch (hitPart) {
- case NSScrollerKnob:
- case NSScrollerKnobSlot: {
- char valueString[TCL_DOUBLE_SPACE];
-
- Tcl_PrintDouble(NULL, [scroller doubleValue] *
- (1.0 - [scroller knobProportion]), valueString);
- Tcl_DStringAppendElement(&cmdString, "moveto");
- Tcl_DStringAppendElement(&cmdString, valueString);
- break;
- }
- case NSScrollerDecrementLine:
- case NSScrollerIncrementLine:
- Tcl_DStringAppendElement(&cmdString, "scroll");
- Tcl_DStringAppendElement(&cmdString,
- (hitPart == NSScrollerDecrementLine) ? "-1" : "1");
- Tcl_DStringAppendElement(&cmdString, "unit");
- break;
- case NSScrollerDecrementPage:
- case NSScrollerIncrementPage:
- Tcl_DStringAppendElement(&cmdString, "scroll");
- Tcl_DStringAppendElement(&cmdString,
- (hitPart == NSScrollerDecrementPage) ? "-1" : "1");
- Tcl_DStringAppendElement(&cmdString, "page");
- break;
- }
- interp = scrollPtr->interp;
- Tcl_Preserve(interp);
- Tcl_Preserve(scrollPtr);
- result = Tcl_EvalEx(interp, Tcl_DStringValue(&cmdString),
- Tcl_DStringLength(&cmdString), TCL_EVAL_GLOBAL);
- if (result != TCL_OK && result != TCL_CONTINUE && result != TCL_BREAK) {
- Tcl_AddErrorInfo(interp, "\n (scrollbar command)");
- Tcl_BackgroundException(interp, result);
- }
- Tcl_Release(scrollPtr);
- Tcl_Release(interp);
- Tcl_DStringFree(&cmdString);
-#ifdef TK_MAC_DEBUG_SCROLLBAR
- TKLog(@"scroller %s value %f knobProportion %f",
- ((TkWindow *)scrollPtr->tkwin)->pathName, [scroller doubleValue],
- [scroller knobProportion]);
-#endif
-}
-- (void) scrollBarVariantChanged: (NSNotification *) notification
-{
-#ifdef TK_MAC_DEBUG_NOTIFICATIONS
- TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
-#endif
- UpdateScrollbarMetrics();
-}
+/*Information on scrollbar layout, metrics, and draw info.*/
+typedef struct ScrollbarMetrics {
+ SInt32 width, minThumbHeight;
+ int minHeight, topArrowHeight, bottomArrowHeight;
+ NSControlSize controlSize;
+} ScrollbarMetrics;
-- (void) _setupScrollBarNotifications
-{
- NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+static ScrollbarMetrics metrics[2] = {
+ {15, 54, 26, 14, 14, NSRegularControlSize}, /* kThemeScrollBarMedium */
+ {11, 40, 20, 10, 10, NSSmallControlSize}, /* kThemeScrollBarSmall */
+};
-#define observe(n, s) [nc addObserver:self selector:@selector(s) name:(n) object:nil]
- observe(NSAppleAquaScrollBarVariantChanged, scrollBarVariantChanged:);
-#undef observe
+HIThemeTrackDrawInfo info = {
+ .version = 0,
+ .min = 0.0,
+ .max = 100.0,
+ .attributes = kThemeTrackShowThumb,
+ .kind = kThemeScrollBarMedium,
+};
- UpdateScrollbarMetrics();
-}
-@end
-#pragma mark -
-
/*
- *----------------------------------------------------------------------
- *
- * UpdateScrollbarMetrics --
- *
- * This function retrieves the current system metrics for a scrollbar.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Updates the geometry cache info for all scrollbars.
- *
- *----------------------------------------------------------------------
+ * Forward declarations for procedures defined later in this file:
*/
-static void
-UpdateScrollbarMetrics(void)
-{
- const short height = 100, width = 50;
- HIThemeTrackDrawInfo info = {
- .version = 0,
- .bounds = {{0, 0}, {width, height}},
- .min = 0,
- .max = 1,
- .value = 0,
- .attributes = kThemeTrackShowThumb,
- .enableState = kThemeTrackActive,
- .trackInfo.scrollbar = {.viewsize = 1, .pressState = 0},
- };
- CGRect bounds;
-
- ChkErr(GetThemeMetric, kThemeMetricScrollBarWidth, &metrics[0].width);
- ChkErr(GetThemeMetric, kThemeMetricScrollBarMinThumbHeight,
- &metrics[0].minThumbHeight);
- info.kind = kThemeScrollBarMedium;
- ChkErr(HIThemeGetTrackDragRect, &info, &bounds);
- metrics[0].topArrowHeight = bounds.origin.y;
- metrics[0].bottomArrowHeight = height - (bounds.origin.y +
- bounds.size.height);
- metrics[0].minHeight = metrics[0].minThumbHeight +
- metrics[0].topArrowHeight + metrics[0].bottomArrowHeight;
- ChkErr(GetThemeMetric, kThemeMetricSmallScrollBarWidth, &metrics[1].width);
- ChkErr(GetThemeMetric, kThemeMetricSmallScrollBarMinThumbHeight,
- &metrics[1].minThumbHeight);
- info.kind = kThemeScrollBarSmall;
- ChkErr(HIThemeGetTrackDragRect, &info, &bounds);
- metrics[1].topArrowHeight = bounds.origin.y;
- metrics[1].bottomArrowHeight = height - (bounds.origin.y +
- bounds.size.height);
- metrics[1].minHeight = metrics[1].minThumbHeight +
- metrics[1].topArrowHeight + metrics[1].bottomArrowHeight;
-
- sprintf(tkDefScrollbarWidth, "%d", (int)(metrics[0].width));
-}
-
+static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr);
+static int ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr);
+static void UpdateControlValues(TkScrollbar *scrollPtr);
+
+
/*
*----------------------------------------------------------------------
*
@@ -285,41 +99,17 @@ UpdateScrollbarMetrics(void)
TkScrollbar *
TkpCreateScrollbar(
- Tk_Window tkwin)
+ Tk_Window tkwin)
{
- MacScrollbar *scrollPtr = ckalloc(sizeof(MacScrollbar));
- scrollPtr->scroller = nil;
- Tk_CreateEventHandler(tkwin, StructureNotifyMask|FocusChangeMask|
- ActivateMask|ExposureMask, ScrollbarEventProc, scrollPtr);
- return (TkScrollbar *) scrollPtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkpDestroyScrollbar --
- *
- * Free data structures associated with the scrollbar control.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
+ MacScrollbar *scrollPtr = (MacScrollbar *)ckalloc(sizeof(MacScrollbar));
-void
-TkpDestroyScrollbar(
- TkScrollbar *scrollPtr)
-{
- MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
- TkNSScroller *scroller = macScrollPtr->scroller;
- [scroller setTag:(NSInteger)-1];
+ scrollPtr->troughGC = None;
+ scrollPtr->copyGC = None;
+
+ Tk_CreateEventHandler(tkwin,ExposureMask|StructureNotifyMask|FocusChangeMask|ButtonPressMask|VisibilityChangeMask, ScrollbarEventProc, scrollPtr);
- TkMacOSXMakeCollectableAndRelease(macScrollPtr->scroller);
+ return (TkScrollbar *) scrollPtr;
}
/*
@@ -328,8 +118,8 @@ TkpDestroyScrollbar(
* TkpDisplayScrollbar --
*
* This procedure redraws the contents of a scrollbar window. It is
- * invoked as a do-when-idle handler, so it only runs when there's nothing
- * else for the application to do.
+ * invoked as a do-when-idle handler, so it only runs when there's
+ * nothing else for the application to do.
*
* Results:
* None.
@@ -342,95 +132,74 @@ TkpDestroyScrollbar(
void
TkpDisplayScrollbar(
- ClientData clientData) /* Information about window. */
+ ClientData clientData) /* Information about window. */
{
- TkScrollbar *scrollPtr = clientData;
- MacScrollbar *macScrollPtr = clientData;
- TkNSScroller *scroller = macScrollPtr->scroller;
- Tk_Window tkwin = scrollPtr->tkwin;
+ register TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
+ register Tk_Window tkwin = scrollPtr->tkwin;
+
+
+ if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
+ return;
+ }
+
TkWindow *winPtr = (TkWindow *) tkwin;
MacDrawable *macWin = (MacDrawable *) winPtr->window;
TkMacOSXDrawingContext dc;
NSView *view = TkMacOSXDrawableView(macWin);
CGFloat viewHeight = [view bounds].size.height;
CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
- .ty = viewHeight};
- NSRect frame;
- double knobProportion = scrollPtr->lastFraction - scrollPtr->firstFraction;
+ .ty = viewHeight};
+
scrollPtr->flags &= ~REDRAW_PENDING;
if (!scrollPtr->tkwin || !Tk_IsMapped(tkwin) || !view ||
- !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
- return;
+ !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) {
+ return;
}
+
CGContextConcatCTM(dc.context, t);
+
+ /*Draw Unix-style scroll trough to provide rect for native scrollbar.*/
if (scrollPtr->highlightWidth != 0) {
- GC fgGC, bgGC;
-
- bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin);
- if (scrollPtr->flags & GOT_FOCUS) {
- fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin);
- } else {
- fgGC = bgGC;
- }
- TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth,
- (Pixmap) macWin);
+ GC fgGC, bgGC;
+
+ bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin);
+ if (scrollPtr->flags & GOT_FOCUS) {
+ fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin);
+ } else {
+ fgGC = bgGC;
+ }
+ TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth,
+ (Pixmap) macWin);
}
- Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder,
- scrollPtr->highlightWidth, scrollPtr->highlightWidth,
- Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
- Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
- scrollPtr->borderWidth, scrollPtr->relief);
- Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder,
- scrollPtr->inset, scrollPtr->inset,
- Tk_Width(tkwin) - 2*scrollPtr->inset,
- Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT);
- if ([scroller superview] != view) {
- [view addSubview:scroller];
- }
- frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin),
- Tk_Height(tkwin));
- frame = NSInsetRect(frame, scrollPtr->inset, scrollPtr->inset);
- frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
- NSWindow *w = [view window];
- //This uses a private API call that is no longer needed on systems >= 10.7.
- #if 0
- if ([w showsResizeIndicator]) {
- NSRect growBox = [view convertRect:[w _growBoxRect] fromView:nil];
-
- if (NSIntersectsRect(growBox, frame)) {
- if (scrollPtr->vertical) {
- CGFloat y = frame.origin.y;
+ Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder,
+ scrollPtr->highlightWidth, scrollPtr->highlightWidth,
+ Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
+ Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
+ scrollPtr->borderWidth, scrollPtr->relief);
+ Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder,
+ scrollPtr->inset, scrollPtr->inset,
+ Tk_Width(tkwin) - 2*scrollPtr->inset,
+ Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT);
- frame.origin.y = growBox.origin.y + growBox.size.height;
- frame.size.height -= frame.origin.y - y;
- } else {
- frame.size.width = growBox.origin.x - frame.origin.x;
- }
- TkMacOSXSetScrollbarGrow(winPtr, true);
- }
- }
- #endif
- if (!NSEqualRects(frame, [scroller frame])) {
- [scroller setFrame:frame];
+ /*Update values and draw in native rect.*/
+ UpdateControlValues(scrollPtr);
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+ if (scrollPtr->vertical) {
+ HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal);
+ } else {
+ HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationInverted);
}
- [scroller setEnabled:(knobProportion < 1.0 &&
- (scrollPtr->vertical ? frame.size.height : frame.size.width) >
- metrics[macScrollPtr->variant].minHeight)];
- // [scroller setEnabled: YES];
- [scroller setDoubleValue:scrollPtr->firstFraction / (1.0 - knobProportion)];
- [scroller setKnobProportion:knobProportion];
- [scroller displayRectIgnoringOpacity:[scroller bounds]];
+#else
+ HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal);
+#endif
TkMacOSXRestoreDrawingContext(&dc);
- #ifdef TK_MAC_DEBUG_SCROLLBAR
- TKLog(@"scroller %s frame %@ width %d height %d",
- ((TkWindow *)scrollPtr->tkwin)->pathName, NSStringFromRect(frame),
- Tk_Width(tkwin), Tk_Height(tkwin));
- #endif
+
+ scrollPtr->flags &= ~REDRAW_PENDING;
}
-
+
/*
*----------------------------------------------------------------------
*
@@ -449,123 +218,106 @@ TkpDisplayScrollbar(
*----------------------------------------------------------------------
*/
-void
+extern void
TkpComputeScrollbarGeometry(
- register TkScrollbar *scrollPtr)
- /* Scrollbar whose geometry may have
- * changed. */
+ register TkScrollbar *scrollPtr)
+/* Scrollbar whose geometry may have
+ * changed. */
{
- MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
- TkNSScroller *scroller = macScrollPtr->scroller;
- int width, height, variant, fieldLength;
+
+ int variant, fieldLength;
if (scrollPtr->highlightWidth < 0) {
- scrollPtr->highlightWidth = 0;
+ scrollPtr->highlightWidth = 0;
}
scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
- width = Tk_Width(scrollPtr->tkwin) - 2 * scrollPtr->inset;
- height = Tk_Height(scrollPtr->tkwin) - 2 * scrollPtr->inset;
- variant = ((scrollPtr->vertical ? width : height) < metrics[0].width) ?
- 1 : 0;
- macScrollPtr->variant = variant;
- if (scroller) {
- NSSize size = [scroller frame].size;
-
- if ((size.width > size.height) ^ !scrollPtr->vertical) {
- /*
- * Orientation changed, need new scroller.
- */
-
- if ([scroller superview]) {
- [scroller removeFromSuperviewWithoutNeedingDisplay];
- }
- TkMacOSXMakeCollectableAndRelease(scroller);
- }
- }
- if (!scroller) {
- if ((width > height) ^ !scrollPtr->vertical) {
- /* -[NSScroller initWithFrame:] determines horizontalness for the
- * lifetime of the scroller via isHoriz = (width > height) */
- if (scrollPtr->vertical) {
- width = height;
- } else if (width > 1) {
- height = width - 1;
- } else {
- height = 1;
- width = 2;
- }
- }
- scroller = [[TkNSScroller alloc] initWithFrame:
- NSMakeRect(0, 0, width, height)];
- macScrollPtr->scroller = TkMacOSXMakeUncollectable(scroller);
- [scroller setAction:@selector(tkScroller:)];
- [scroller setTarget:NSApp];
- [scroller setTag:(NSInteger)scrollPtr];
- }
- [[scroller cell] setControlSize:metrics[variant].controlSize];
-
+ variant = ((scrollPtr->vertical ? Tk_Width(scrollPtr->tkwin) :
+ Tk_Height(scrollPtr->tkwin)) - 2 * scrollPtr->inset
+ < metrics[0].width) ? 1 : 0;
scrollPtr->arrowLength = (metrics[variant].topArrowHeight +
- metrics[variant].bottomArrowHeight) / 2;
+ metrics[variant].bottomArrowHeight) / 2;
fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
- : Tk_Width(scrollPtr->tkwin))
- - 2 * (scrollPtr->arrowLength + scrollPtr->inset);
+ : Tk_Width(scrollPtr->tkwin))
+ - 2 * (scrollPtr->arrowLength + scrollPtr->inset);
if (fieldLength < 0) {
- fieldLength = 0;
+ fieldLength = 0;
}
scrollPtr->sliderFirst = fieldLength * scrollPtr->firstFraction;
scrollPtr->sliderLast = fieldLength * scrollPtr->lastFraction;
/*
- * Adjust the slider so that some piece of it is always displayed in the
- * scrollbar and so that it has at least a minimal width (so it can be
- * grabbed with the mouse).
+ * Adjust the slider so that some piece of it is always
+ * displayed in the scrollbar and so that it has at least
+ * a minimal width (so it can be grabbed with the mouse).
*/
if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) {
- scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
+ scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
}
if (scrollPtr->sliderFirst < 0) {
- scrollPtr->sliderFirst = 0;
+ scrollPtr->sliderFirst = 0;
}
if (scrollPtr->sliderLast < (scrollPtr->sliderFirst +
- metrics[variant].minThumbHeight)) {
- scrollPtr->sliderLast = scrollPtr->sliderFirst +
- metrics[variant].minThumbHeight;
+ metrics[variant].minThumbHeight)) {
+ scrollPtr->sliderLast = scrollPtr->sliderFirst +
+ metrics[variant].minThumbHeight;
}
if (scrollPtr->sliderLast > fieldLength) {
- scrollPtr->sliderLast = fieldLength;
+ scrollPtr->sliderLast = fieldLength;
}
scrollPtr->sliderFirst += scrollPtr->inset +
- metrics[variant].topArrowHeight;
+ metrics[variant].topArrowHeight;
scrollPtr->sliderLast += scrollPtr->inset +
- metrics[variant].bottomArrowHeight;
+ metrics[variant].bottomArrowHeight;
/*
- * Register the desired geometry for the window (leave enough space for
- * the two arrows plus a minimum-size slider, plus border around the whole
- * window, if any). Then arrange for the window to be redisplayed.
+ * Register the desired geometry for the window (leave enough space
+ * for the two arrows plus a minimum-size slider, plus border around
+ * the whole window, if any). Then arrange for the window to be
+ * redisplayed.
*/
if (scrollPtr->vertical) {
- Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width +
- 2 * scrollPtr->inset, 2 * (scrollPtr->arrowLength +
- scrollPtr->borderWidth + scrollPtr->inset) +
- metrics[variant].minThumbHeight);
+ Tk_GeometryRequest(scrollPtr->tkwin, scrollPtr->width + 2 * scrollPtr->inset, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics[variant].minThumbHeight);
} else {
- Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength +
- scrollPtr->borderWidth + scrollPtr->inset) +
- metrics[variant].minThumbHeight, scrollPtr->width +
- 2 * scrollPtr->inset);
+ Tk_GeometryRequest(scrollPtr->tkwin, 2 * (scrollPtr->arrowLength + scrollPtr->borderWidth + scrollPtr->inset) + metrics[variant].minThumbHeight, scrollPtr->width + 2 * scrollPtr->inset);
}
Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset);
-#ifdef TK_MAC_DEBUG_SCROLLBAR
- TKLog(@"scroller %s bounds %@ width %d height %d inset %d borderWidth %d",
- ((TkWindow *)scrollPtr->tkwin)->pathName,
- NSStringFromRect([scroller bounds]),
- width, height, scrollPtr->inset, scrollPtr->borderWidth);
-#endif
+
}
-
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpDestroyScrollbar --
+ *
+ * Free data structures associated with the scrollbar control.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Frees the GCs associated with the scrollbar.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpDestroyScrollbar(
+ TkScrollbar *scrollPtr)
+{
+ MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr;
+
+ if (macScrollPtr->troughGC != None) {
+ Tk_FreeGC(scrollPtr->display, macScrollPtr->troughGC);
+ }
+ if (macScrollPtr->copyGC != None) {
+ Tk_FreeGC(scrollPtr->display, macScrollPtr->copyGC);
+ }
+
+ macScrollPtr=NULL;
+}
+
/*
*----------------------------------------------------------------------
*
@@ -579,19 +331,20 @@ TkpComputeScrollbarGeometry(
* None.
*
* Side effects:
- * None.
+ * Configuration info may get changed.
*
*----------------------------------------------------------------------
*/
void
TkpConfigureScrollbar(
- register TkScrollbar *scrollPtr)
- /* Information about widget; may or may not
- * already have values for some fields. */
+ register TkScrollbar *scrollPtr)
+/* Information about widget; may or may not
+ * already have values for some fields. */
{
+
}
-
+
/*
*--------------------------------------------------------------
*
@@ -616,30 +369,159 @@ TkpScrollbarPosition(
/* Scrollbar widget record. */
int x, int y) /* Coordinates within scrollPtr's window. */
{
- TkNSScroller *scroller = ((MacScrollbar *) scrollPtr)->scroller;
- MacDrawable *macWin = (MacDrawable *)
- ((TkWindow *) scrollPtr->tkwin)->window;
- NSView *view = TkMacOSXDrawableView(macWin);
- switch ([scroller testPart:NSMakePoint(macWin->xOff + x,
- [view bounds].size.height - (macWin->yOff + y))]) {
- case NSScrollerDecrementLine:
+ /*Using code from tkUnixScrlbr.c because Unix scroll bindings are driving the display at the script level. All the Mac scrollbar has to do is re-draw itself.*/
+
+ int length, width, tmp;
+ register const int inset = scrollPtr->inset;
+
+ if (scrollPtr->vertical) {
+ length = Tk_Height(scrollPtr->tkwin);
+ width = Tk_Width(scrollPtr->tkwin);
+ } else {
+ tmp = x;
+ x = y;
+ y = tmp;
+ length = Tk_Width(scrollPtr->tkwin);
+ width = Tk_Height(scrollPtr->tkwin);
+ }
+
+ if (x<inset || x>=width-inset || y<inset || y>=length-inset) {
+ return OUTSIDE;
+ }
+
+ /*
+ * All of the calculations in this procedure mirror those in
+ * TkpDisplayScrollbar. Be sure to keep the two consistent.
+ */
+
+ if (y < inset + scrollPtr->arrowLength) {
return TOP_ARROW;
- case NSScrollerDecrementPage:
+ }
+ if (y < scrollPtr->sliderFirst) {
return TOP_GAP;
- case NSScrollerKnob:
+ }
+ if (y < scrollPtr->sliderLast) {
return SLIDER;
- case NSScrollerIncrementPage:
- return BOTTOM_GAP;
- case NSScrollerIncrementLine:
+ }
+ if (y >= length - (scrollPtr->arrowLength + inset)) {
return BOTTOM_ARROW;
- case NSScrollerKnobSlot:
- case NSScrollerNoPart:
- default:
- return OUTSIDE;
}
+ return BOTTOM_GAP;
}
-
+
+/*
+ *--------------------------------------------------------------
+ *
+ * UpdateControlValues --
+ *
+ * This procedure updates the Macintosh scrollbar control to display the
+ * values defined by the Tk scrollbar. This is the key interface to the Mac-native * scrollbar; the Unix bindings drive scrolling in the Tk window and all the Mac
+ * scrollbar has to do is redraw itself.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The Macintosh control is updated.
+ *
+ *--------------------------------------------------------------
+ */
+
+static void
+UpdateControlValues(
+ TkScrollbar *scrollPtr) /* Scrollbar data struct. */
+{
+
+ Tk_Window tkwin = scrollPtr->tkwin;
+ MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin);
+ double dViewSize;
+ HIRect contrlRect;
+ int variant;
+ short width, height;
+
+ NSView *view = TkMacOSXDrawableView(macWin);
+ CGFloat viewHeight = [view bounds].size.height;
+ NSRect frame;
+ frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin),
+ Tk_Height(tkwin));
+ frame = NSInsetRect(frame, scrollPtr->inset, scrollPtr->inset);
+ frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
+
+ contrlRect = NSRectToCGRect(frame);
+ info.bounds = contrlRect;
+
+ width = contrlRect.size.width;
+ height = contrlRect.size.height;
+
+ variant = contrlRect.size.width < metrics[0].width ? 1 : 0;
+
+ /*
+ * Ensure we set scrollbar control bounds only once all size adjustments
+ * have been computed.
+ */
+
+ info.bounds = contrlRect;
+ if (!scrollPtr->vertical) {
+ info.attributes |= kThemeTrackHorizontal;
+ }
+
+ /*
+ * Given the Tk parameters for the fractions of the start and end of the
+ * thumb, the following calculation determines the location for the
+ * Macintosh thumb. The Aqua scroll control works as follows. The
+ * scrollbar's value is the position of the left (or top) side of the view
+ * area in the content area being scrolled. The maximum value of the
+ * control is therefore the dimension of the content area less the size of
+ * the view area.
+ */
+
+ double maximum = 100, factor;
+ factor = RangeToFactor(maximum);
+ dViewSize = (scrollPtr->lastFraction - scrollPtr->firstFraction)
+ * factor;
+ info.max = MIN_SCROLLBAR_VALUE +
+ factor - dViewSize;
+ info.trackInfo.scrollbar.viewsize = dViewSize;
+ if (scrollPtr->vertical) {
+ info.value = info.max - factor * scrollPtr->firstFraction;
+ } else {
+ info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction;
+ }
+
+ if((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0)
+ || height <= metrics[variant].minHeight) {
+ info.enableState = kThemeTrackHideTrack;
+ } else {
+ info.enableState = kThemeTrackActive;
+ info.attributes = kThemeTrackShowThumb | kThemeTrackThumbRgnIsNotGhost;
+ }
+
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ScrollbarPress --
+ *
+ * This procedure is invoked in response to <ButtonPress> events.
+ * Enters a modal loop to handle scrollbar interactions.
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr)
+{
+
+ if (eventPtr->type == ButtonPress) {
+ UpdateControlValues(scrollPtr);
+ }
+ return TCL_OK;
+}
+
+
+
/*
*--------------------------------------------------------------
*
@@ -660,8 +542,8 @@ TkpScrollbarPosition(
static void
ScrollbarEventProc(
- ClientData clientData, /* Information about window. */
- XEvent *eventPtr) /* Information about event. */
+ ClientData clientData, /* Information about window. */
+ XEvent *eventPtr) /* Information about event. */
{
TkScrollbar *scrollPtr = clientData;
@@ -673,55 +555,10 @@ ScrollbarEventProc(
case DeactivateNotify:
TkScrollbarEventuallyRedraw(scrollPtr);
break;
+ case ButtonPress:
+ ScrollbarPress(clientData, eventPtr);
+ break;
default:
TkScrollbarEventProc(clientData, eventPtr);
}
}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * TkMacOSXGetScrollFrame --
- *
- * Computes a frame for an NSScroller that will correspond to where
- * Tk thinks the scroller is located.
- *
- * Results:
- * Returns an NSRect describing a frame for an NSScrollbar.
- *
- * Side effects:
- * None
- *
- *----------------------------------------------------------------------
- */
-NSRect TkMacOSXGetScrollFrame(
- TkScrollbar *scrlPtr)
-{
- MacScrollbar *macscrlPtr = (MacScrollbar *) scrlPtr;
- Tk_Window tkwin = scrlPtr->tkwin;
- TkWindow *winPtr = (TkWindow *) tkwin;
- if (tkwin) {
- MacDrawable *macWin = (MacDrawable *) winPtr->window;
- NSView *view = TkMacOSXDrawableView(macWin);
- CGFloat viewHeight = [view bounds].size.height;
- NSRect frame = NSMakeRect(macWin->xOff, macWin->yOff,
- Tk_Width(tkwin), Tk_Height(tkwin));
-
- frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);
- return frame;
- } else {
- return NSZeroRect;
- }
-}
-
-
-
-/*
- * Local Variables:
- * mode: objc
- * c-basic-offset: 4
- * fill-column: 79
- * coding: utf-8
- * End:
- */
diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c
index d016790..5f782c5 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -6,6 +6,8 @@
*
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright (c) 2015 Kevin Walzer/WordTech Communications LLC.
+ * Copyright (c) 2015 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -388,7 +390,7 @@ GenerateUpdates(
/*
* TODO: Here we should handle out of process embedding.
*/
- }
+ }
return 1;
}
@@ -760,17 +762,29 @@ Tk_MacOSXIsAppInFront(void)
#import <ApplicationServices/ApplicationServices.h>
/*
- * Custom content view for Tk NSWindows, containing standard NSView subviews.
- * The goal is to emulate X11-style drawing in response to Expose events:
- * during the normal AppKit drawing cycle, we supress drawing of all subviews
- * and instead send Expose events about the subviews that would be redrawn.
+ * Custom content view for use in Tk NSWindows.
+ *
+ * Since Tk handles all drawing of widgets, we only use the AppKit event loop
+ * as a source of input events. To do this, we overload the NSView drawRect
+ * method with a method which generates Expose events for Tk but does no
+ * drawing. The redrawing operations are then done when Tk processes these
+ * events.
+ *
+ * Earlier versions of Mac Tk used subclasses of NSView, e.g. NSButton, as the
+ * basis for Tk widgets. These would then appear as subviews of the
+ * TKContentView. To prevent the AppKit from redrawing and corrupting the Tk
+ * Widgets it was necessary to use Apple private API calls. In order to avoid
+ * using private API calls, the NSView-based widgets have been replaced with
+ * normal Tk widgets which draw themselves as native widgets by using the
+ * HITheme API.
+ *
*/
@interface TKContentView(TKWindowEvent)
- (void) drawRect: (NSRect) rect;
- (void) generateExposeEvents: (HIMutableShapeRef) shape;
- (void) viewDidEndLiveResize;
-- (void) viewWillDraw;
+- (void) tkToolbarButton: (id) sender;
- (BOOL) isOpaque;
- (BOOL) wantsDefaultClipping;
- (BOOL) acceptsFirstResponder;
@@ -780,15 +794,6 @@ Tk_MacOSXIsAppInFront(void)
@implementation TKContentView
@end
-double drawTime;
-
-/*
- * Set a minimum time for drawing to render. With removal of private NSView API's, default drawing
- * is slower and less responsive. This number, which seems feasible after some experimentatation, skips
- * some drawing to avoid lag.
- */
-
-#define MAX_DYNAMIC_TIME .000000001
/*Restrict event processing to Expose events.*/
static Tk_RestrictAction
@@ -800,7 +805,6 @@ ExposeRestrictProc(
? TK_PROCESS_EVENT : TK_DEFER_EVENT);
}
-
@implementation TKContentView(TKWindowEvent)
- (void) drawRect: (NSRect) rect
@@ -809,6 +813,7 @@ ExposeRestrictProc(
NSInteger rectsBeingDrawnCount;
[self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount];
+
#ifdef TK_MAC_DEBUG_DRAWING
TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, NSStringFromRect(rect));
[[NSColor colorWithDeviceRed:0.0 green:1.0 blue:0.0 alpha:.1] setFill];
@@ -816,17 +821,11 @@ ExposeRestrictProc(
NSCompositeSourceOver);
#endif
- NSDate *beginTime=[NSDate date];
-
- /*Skip drawing during live resize if redraw is too slow.*/
- if([self inLiveResize] && drawTime>MAX_DYNAMIC_TIME) return;
-
CGFloat height = [self bounds].size.height;
HIMutableShapeRef drawShape = HIShapeCreateMutable();
while (rectsBeingDrawnCount--) {
CGRect r = NSRectToCGRect(*rectsBeingDrawn++);
-
r.origin.y = height - (r.origin.y + r.size.height);
HIShapeUnionWithRect(drawShape, &r);
}
@@ -839,23 +838,24 @@ ExposeRestrictProc(
NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode,
nil]];
}
+
CFRelease(drawShape);
- drawTime=-[beginTime timeIntervalSinceNow];
}
-/*At conclusion of resize event, send notification and set view for redraw if earlier drawing was skipped because of lagginess.*/
+/*
+ * As insurance against bugs that might cause layout glitches during a live
+ * resize, we redraw the window at the end of the resize operation.
+ */
+
- (void)viewDidEndLiveResize
{
- if(drawTime>MAX_DYNAMIC_TIME) {
- [self setNeedsDisplay:YES];
- [super viewDidEndLiveResize];
- }
-}
+ HIRect bounds = NSRectToCGRect([self bounds]);
+ HIShapeRef shape = HIShapeCreateWithRect(&bounds);
+ [self generateExposeEvents: shape];
--(void) viewWillDraw {
- [self setNeedsDisplay:YES];
- }
+}
+/*Core function of this class, generates expose events for redrawing.*/
- (void) generateExposeEvents: (HIMutableShapeRef) shape
{
@@ -867,21 +867,23 @@ ExposeRestrictProc(
return;
}
+
HIShapeGetBounds(shape, &updateBounds);
serial = LastKnownRequestProcessed(Tk_Display(winPtr));
if (GenerateUpdates(shape, &updateBounds, winPtr) &&
![[NSRunLoop currentRunLoop] currentMode] &&
Tcl_GetServiceMode() != TCL_SERVICE_NONE) {
/*
- * Ensure there are no pending idle-time redraws that could prevent the
- * just posted Expose events from generating new redraws.
+ * Ensure there are no pending idle-time redraws that could
+ * prevent the just posted Expose events from generating
+ * new redraws.
*/
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
+ while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
/*
- * For smoother drawing, process Expose events and resulting redraws
- * immediately instead of at idle time.
+ * For smoother drawing, process Expose events and resulting
+ * redraws immediately instead of at idle time.
*/
ClientData oldArg;
@@ -889,15 +891,19 @@ ExposeRestrictProc(
UINT2PTR(serial), &oldArg);
while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {}
-
+
Tk_RestrictEvents(oldProc, oldArg, &oldArg);
+
while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
- }
-
+ }
+
}
-/*This is no-op on 10.7 and up because Apple has removed this widget, but leaving here for backwards compatibility.*/
+/*
+ * 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
@@ -925,16 +931,6 @@ ExposeRestrictProc(
Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
}
-- (void) setFrameSize: (NSSize) newSize
-{
- [super setFrameSize:newSize];
-}
-
-- (void) setNeedsDisplayInRect: (NSRect) invalidRect
-{
- [super setNeedsDisplayInRect:invalidRect];
-}
-
- (BOOL) isOpaque
{
NSWindow *w = [self window];
diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c
index 370c86a..4f7b066 100644
--- a/macosx/tkMacOSXWm.c
+++ b/macosx/tkMacOSXWm.c
@@ -784,6 +784,7 @@ TkWmDeadWindow(
if (window && !Tk_IsEmbedded(winPtr) ) {
[[window parentWindow] removeChildWindow:window];
+ [window setExcludedFromWindowsMenu:YES];
[window close];
TkMacOSXUnregisterMacWindow(window);
if (winPtr->window) {
@@ -1655,8 +1656,8 @@ WmForgetCmd(
if (Tk_IsTopLevel(frameWin)) {
MacDrawable *macWin;
- Tk_MakeWindowExist(winPtr);
- Tk_MakeWindowExist(winPtr->parentPtr);
+ Tk_MakeWindowExist(frameWin);
+ Tk_MakeWindowExist((Tk_Window)winPtr->parentPtr);
macWin = (MacDrawable *) winPtr->window;
diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c
index a4abc7b..4753a40 100644
--- a/macosx/ttkMacOSXTheme.c
+++ b/macosx/ttkMacOSXTheme.c
@@ -294,21 +294,12 @@ static Ttk_StateTable TabPositionTable[] = {
* TP30000359-TPXREF116>
*/
-
-int TAB_HEIGHT = 0;
-int TAB_OVERLAP = 0;
-
static void TabElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
- TAB_HEIGHT = 10;
- TAB_OVERLAP = 10;
- /*Different metrics on 10.10/Yosemite.*/
- if (MAC_OS_X_VERSION_MIN_REQUIRED > 100000) {
- TAB_OVERLAP = 5;
- }
- *heightPtr = TAB_HEIGHT + TAB_OVERLAP - 1;
+ *heightPtr = GetThemeMetric(kThemeMetricLargeTabHeight, heightPtr);
+ *paddingPtr = Ttk_MakePadding(0, 0, 0, 2);
}
@@ -327,7 +318,6 @@ static void TabElementDraw(
.position = Ttk_StateTableLookup(TabPositionTable, state),
};
- bounds.size.height += TAB_OVERLAP;
BEGIN_DRAWING(d)
ChkErr(HIThemeDrawTab, &bounds, &info, dc.context, HIOrientation, NULL);
END_DRAWING
@@ -365,8 +355,8 @@ static void PaneElementDraw(
.adornment = kHIThemeTabPaneAdornmentNormal,
};
- bounds.origin.y -= TAB_OVERLAP;
- bounds.size.height += TAB_OVERLAP;
+ bounds.origin.y -= kThemeMetricTabFrameOverlap;
+ bounds.size.height += kThemeMetricTabFrameOverlap;
BEGIN_DRAWING(d)
ChkErr(HIThemeDrawTabPane, &bounds, &info, dc.context, HIOrientation);
END_DRAWING
@@ -528,6 +518,10 @@ static Ttk_ElementSpec ComboboxElementSpec = {
ComboboxElementDraw
};
+
+
+
+
/*----------------------------------------------------------------------
* +++ Spinbuttons.
*
@@ -600,6 +594,7 @@ static TrackElementData ScaleData = {
kThemeSlider, kThemeMetricHSliderHeight
};
+
typedef struct {
Tcl_Obj *fromObj; /* minimum value */
Tcl_Obj *toObj; /* maximum value */
@@ -661,6 +656,7 @@ static void TrackElementDraw(
info.trackInfo.slider.thumbDir = kThemeThumbPlain;
}
+
BEGIN_DRAWING(d)
ChkErr(HIThemeDrawTrack, &info, NULL, dc.context, HIOrientation);
END_DRAWING
diff --git a/tests/bind.test b/tests/bind.test
index c777d66..474771d 100644
--- a/tests/bind.test
+++ b/tests/bind.test
@@ -25,7 +25,6 @@ foreach event [bind all] {
bind all $event {}
}
-
proc unsetBindings {} {
bind all <Enter> {}
bind Test <Enter> {}
@@ -2172,6 +2171,48 @@ test bind-16.44 {ExpandPercents procedure} -setup {
destroy .t.f
} -result {?? ??}
+test bind-16.45 {ExpandPercents procedure} -setup {
+ set savedBind(Entry) [bind Entry <Key>]
+ set savedBind(All) [bind all <Key>]
+ entry .t.e
+ pack .t.e
+ focus -force .t.e
+ foreach p [event info] {event delete $p}
+ update
+} -body {
+ bind .t.e <Key> {set x "%M"}
+ bind Entry <Key> {set y "%M"}
+ bind all <Key> {set z "%M"}
+ set x none; set y none; set z none
+ event gen .t.e <Key-a>
+ list $x $y $z
+} -cleanup {
+ destroy .t.e
+ bind all <Key> $savedBind(All)
+ bind Entry <Key> $savedBind(Entry)
+ unset savedBind
+} -result {0 1 2}
+test bind-16.46 {ExpandPercents procedure} -setup {
+ set savedBind(All) [bind all <Key>]
+ set savedBind(Entry) [bind Entry <Key>]
+ entry .t.e
+ pack .t.e
+ focus -force .t.e
+ foreach p [event info] {event delete $p}
+ update
+} -body {
+ bind all <Key> {set z "%M"}
+ bind Entry <Key> {set y "%M"}
+ bind .t.e <Key> {set x "%M"}
+ set x none; set y none; set z none
+ event gen .t.e <Key-a>
+ list $x $y $z
+} -cleanup {
+ destroy .t.e
+ bind Entry <Key> $savedBind(Entry)
+ bind all <Key> $savedBind(All)
+ unset savedBind
+} -result {0 1 2}
test bind-17.1 {event command} -body {
event
diff --git a/tests/bugs.tcl b/tests/bugs.tcl
index 83d9519..55e5f84 100644
--- a/tests/bugs.tcl
+++ b/tests/bugs.tcl
@@ -1,6 +1,6 @@
# This file is a Tcl script to test out various known bugs that will
# cause Tk to crash. This file ends with .tcl instead of .test to make
-# sure it isn't run when you type "source all". We currently are not
+# sure it isn't run when you type "source all". We currently are not
# shipping this file with the rest of the source release.
#
# Copyright (c) 1996 Sun Microsystems, Inc.
diff --git a/tests/butGeom2.tcl b/tests/butGeom2.tcl
index 96ff209..096225c 100644
--- a/tests/butGeom2.tcl
+++ b/tests/butGeom2.tcl
@@ -35,7 +35,7 @@ pack .t.anchorLabel .t.control.left.f -in .t.control.left -side top -anchor w
foreach opt {activebackground activeforeground background disabledforeground foreground highlightbackground highlightcolor } {
#button .t.color-$opt -text $opt -command "config -$opt \[tk_chooseColor]"
menubutton .t.color-$opt -text $opt -menu .t.color-$opt.m -indicatoron 1 \
- -relief raised -bd 2
+ -relief raised -bd 2
menu .t.color-$opt.m -tearoff 0
.t.color-$opt.m add command -label Red -command "config -$opt red"
.t.color-$opt.m add command -label Green -command "config -$opt green"
diff --git a/tests/canvPsGrph.tcl b/tests/canvPsGrph.tcl
index 343979f..08ccd74 100644
--- a/tests/canvPsGrph.tcl
+++ b/tests/canvPsGrph.tcl
@@ -50,13 +50,13 @@ proc mkObjs c {
$c create rect 380 200 420 240 -fill black
$c create rect 200 330 240 370 -fill black
}
-
+
if {$what == "oval"} {
$c create oval 50 10 150 80 -fill black -stipple gray25 -outline {}
$c create oval 100 100 200 150 -outline {} -fill black -stipple gray50
$c create oval 250 100 400 300 -width .5c
}
-
+
if {$what == "poly"} {
$c create poly 100 200 200 50 300 200 -smooth yes -stipple gray25 \
-outline black -width 4
@@ -68,7 +68,7 @@ proc mkObjs c {
$c create poly 20 200 100 220 90 100 40 250 \
-fill {} -outline brown -width 3
}
-
+
if {$what == "line"} {
$c create line 20 20 120 20 -arrow both -width 5
$c create line 20 80 150 80 20 200 150 200 -smooth yes
diff --git a/tests/canvPsImg.tcl b/tests/canvPsImg.tcl
index c06aeaa..1f46eca 100644
--- a/tests/canvPsImg.tcl
+++ b/tests/canvPsImg.tcl
@@ -35,7 +35,7 @@ toplevel .t
wm title .t "Postscript Tests for Canvases: Images"
wm iconname .t "Postscript"
-message .t.m -text {This screen exercises the Postscript-generation abilities of Tk canvas widgets for images. Click the buttons below to select a Visual type for the canvas and colormode for the Postscript output. Then click "Print" to send the results to the default printer, or "Print to file" to put the Postscript output in a file called "/tmp/test.ps". You can also click on items in the canvas to delete them.
+message .t.m -text {This screen exercises the Postscript-generation abilities of Tk canvas widgets for images. Click the buttons below to select a Visual type for the canvas and colormode for the Postscript output. Then click "Print" to send the results to the default printer, or "Print to file" to put the Postscript output in a file called "/tmp/test.ps". You can also click on items in the canvas to delete them.
NOTE: Some Postscript printers may not be able to handle Postscript generated in color mode.} -width 6i
pack .t.m -side top -fill both
diff --git a/tests/canvText.test b/tests/canvText.test
index 094bfa2..ff5e4b9 100644
--- a/tests/canvText.test
+++ b/tests/canvText.test
@@ -832,7 +832,7 @@ test canvText-16.1 {GetSelText procedure} -setup {
test canvText-17.1 {TextToPostscript procedure} -setup {
.c delete all
- set result {/Courier-Oblique findfont [font actual $font -size] scalefont ISOEncode setfont
+ set result {findfont [font actual $font -size] scalefont ISOEncode setfont
0.000 0.000 0.000 setrgbcolor AdjustColor
0 100 200 \[
\[(000)\]
@@ -856,7 +856,7 @@ end
.c itemconfig test -font $font -text "00000000" -width [expr 3*$ax]
.c itemconfig test -anchor n -fill black
set x [.c postscript]
- set x [string range $x [string first "/Courier-Oblique" $x] end]
+ set x [string range $x [string first "findfont " $x] end]
expr {$x eq [subst $result] ? "ok" : $x}
} -result ok
diff --git a/tests/constraints.tcl b/tests/constraints.tcl
index 535d839..6402753 100644
--- a/tests/constraints.tcl
+++ b/tests/constraints.tcl
@@ -38,7 +38,7 @@ namespace eval tk {
}
namespace eval bg {
- # Manage a background process.
+ # Manage a background process.
# Replace with slave interp or thread?
namespace import ::tcltest::interpreter
namespace import ::tk::test::loadTkCommand
@@ -126,7 +126,7 @@ namespace eval tk {
eval destroy [winfo children .]
}
- namespace export fixfocus
+ namespace export fixfocus
proc fixfocus {} {
catch {destroy .focus}
toplevel .focus
@@ -185,7 +185,7 @@ testConstraint aqua [expr {[tk windowingsystem] eq "aqua"}]
testConstraint nonwin [expr {[tk windowingsystem] ne "win32"}]
testConstraint userInteraction 0
testConstraint nonUnixUserInteraction [expr {
- [testConstraint userInteraction] ||
+ [testConstraint userInteraction] ||
([testConstraint unix] && [testConstraint notAqua])
}]
testConstraint haveDISPLAY [info exists env(DISPLAY)]
diff --git a/tests/text.test b/tests/text.test
index 5089bb1..d8d01a0 100644
--- a/tests/text.test
+++ b/tests/text.test
@@ -2632,7 +2632,65 @@ test text-10.39 {TextWidgetCmd procedure, "count" option} -setup {
lappend res [.t count -displaylines 1.19 3.24] [.t count -displaylines 1.0 end]
} -cleanup {
destroy .t
-} -result {2 6 2 5}
+} -result {2 6 1 5}
+test text-9.2.45 {TextWidgetCmd procedure, "count" option} -setup {
+ text .t
+ pack .t
+ update
+ set res {}
+} -body {
+ for {set i 1} {$i < 5} {incr i} {
+ .t insert end "Line $i+++Line $i---Line $i///Line $i - This is Line [format %c [expr 64+$i]]\n"
+ }
+ .t tag configure hidden -elide true
+ .t tag add hidden 2.15 3.10
+ .t configure -wrap none
+ set res [.t count -displaylines 2.0 3.0]
+} -cleanup {
+ destroy .t
+} -result {0}
+test text-9.2.46 {TextWidgetCmd procedure, "count" option} -setup {
+ toplevel .mytop
+ pack [text .mytop.t]
+ wm geometry .mytop 100x300+0+0
+ .mytop.t delete 1.0 end
+ update
+ set res {}
+} -body {
+ for {set i 1} {$i < 5} {incr i} {
+ # 0 1 2 3 4
+ # 012345 678901234 567890123 456789012 34567890123456789
+ .mytop.t insert end "Line $i+++Line $i---Line $i///Line $i - This is Line [format %c [expr 64+$i]]\n"
+ }
+ .mytop.t tag configure hidden -elide true
+ .mytop.t tag add hidden 2.15 3.10
+ .mytop.t configure -wrap char
+ lappend res [.mytop.t count -displaylines 2.0 3.0]
+ lappend res [.mytop.t count -displaylines 2.0 3.40]
+} -cleanup {
+ destroy .mytop
+} -result {1 3}
+test text-9.2.47 {TextWidgetCmd procedure, "count" option} -setup {
+ text .t
+ pack .t
+ update
+ set res {}
+} -body {
+ for {set i 1} {$i < 25} {incr i} {
+ .t insert end "Line $i\n"
+ }
+ .t tag configure hidden -elide true
+ .t tag add hidden 5.7 11.0
+ update
+ set y1 [lindex [.t yview] 1]
+ .t count -displaylines 5.0 11.0
+ set y2 [lindex [.t yview] 1]
+ .t count -displaylines 5.0 12.0
+ set y3 [lindex [.t yview] 1]
+ list [expr {$y1 == $y2}] [expr {$y1 == $y3}]
+} -cleanup {
+ destroy .t
+} -result {1 1}
test text-11.1 {counting with tag priority eliding} -setup {
diff --git a/tests/textBTree.test b/tests/textBTree.test
index 41b3d98..ebd6c50 100644
--- a/tests/textBTree.test
+++ b/tests/textBTree.test
@@ -872,7 +872,21 @@ test btree-14.1 {check tag presence} -setup {
} -cleanup {
destroy .t
} -result {x y z}
-
+test btree-14.2 {TkTextIsElided} -setup {
+ destroy .t
+ text .t
+} -body {
+ .t delete 1.0 end
+ .t tag config hidden -elide 1
+ .t insert end "Line1\nLine2\nLine3\n"
+ .t tag add hidden 2.0 3.0
+ .t tag add sel 1.2 3.2
+ # next line used to panic because of "Bad tag priority being toggled on"
+ # (see bug [382da038c9])
+ .t index "2.0 - 1 display line linestart"
+} -cleanup {
+ destroy .t
+} -result {1.0}
test btree-15.1 {rebalance with empty node} -setup {
destroy .t
diff --git a/tests/textDisp.test b/tests/textDisp.test
index 70c7208..aed842c 100644
--- a/tests/textDisp.test
+++ b/tests/textDisp.test
@@ -537,20 +537,24 @@ test textDisp-4.1 {UpdateDisplayInfo, basic} {textfonts} {
.t insert end "Line 1\nLine 2\nLine 3\n"
update
.t delete 2.0 2.end
+ update
+ set res $tk_textRelayout
.t insert 2.0 "New Line 2"
update
- list [.t bbox 1.0] [.t bbox 2.0] [.t bbox 3.0] $tk_textRelayout
-} [list [list 5 5 7 $fixedHeight] [list 5 [expr {$fixedDiff + 18}] 7 $fixedHeight] [list 5 [expr {2*$fixedDiff + 31}] 7 $fixedHeight] 2.0]
+ lappend res [.t bbox 1.0] [.t bbox 2.0] [.t bbox 3.0] $tk_textRelayout
+} [list 2.0 [list 5 5 7 $fixedHeight] [list 5 [expr {$fixedDiff + 18}] 7 $fixedHeight] [list 5 [expr {2*$fixedDiff + 31}] 7 $fixedHeight] 2.0]
test textDisp-4.2 {UpdateDisplayInfo, re-use tail of text line} {textfonts} {
.t delete 1.0 end
.t insert end "Line 1\nLine 2 is so long that it wraps around\nLine 3"
update
.t mark set x 2.21
.t delete 2.2
+ update
+ set res $tk_textRelayout
.t insert 2.0 X
update
- list [.t bbox 2.0] [.t bbox x] [.t bbox 3.0] $tk_textRelayout
-} [list [list 5 [expr {$fixedDiff + 18}] 7 $fixedHeight] [list 12 [expr {2*$fixedDiff + 31}] 7 $fixedHeight] [list 5 [expr {3*$fixedDiff + 44}] 7 $fixedHeight] {2.0 2.20}]
+ lappend res [.t bbox 2.0] [.t bbox x] [.t bbox 3.0] $tk_textRelayout
+} [list 2.0 2.20 [list 5 [expr {$fixedDiff + 18}] 7 $fixedHeight] [list 12 [expr {2*$fixedDiff + 31}] 7 $fixedHeight] [list 5 [expr {3*$fixedDiff + 44}] 7 $fixedHeight] {2.0 2.20}]
test textDisp-4.3 {UpdateDisplayInfo, tail of text line shifts} {textfonts} {
.t delete 1.0 end
.t insert end "Line 1\nLine 2 is so long that it wraps around\nLine 3"
@@ -1148,6 +1152,41 @@ test textDisp-8.11 {TkTextChanged, scrollbar notification when changes are off-s
.t configure -yscrollcommand ""
set scrollInfo
} {0.0 0.625}
+test textDisp-8.12 {TkTextChanged, moving the insert cursor redraws only past and new lines} {
+ .t delete 1.0 end
+ .t configure -wrap none
+ for {set i 1} {$i < 25} {incr i} {
+ .t insert end "Line $i Line $i\n"
+ }
+ .t tag add hidden 5.0 8.0
+ .t tag configure hidden -elide true
+ .t mark set insert 9.0
+ update
+ .t mark set insert 8.0 ; # up one line
+ update
+ set res [list $tk_textRedraw]
+ .t mark set insert 12.2 ; # in the visible text
+ update
+ lappend res $tk_textRedraw
+ .t mark set insert 6.5 ; # in the hidden text
+ update
+ lappend res $tk_textRedraw
+ .t mark set insert 3.5 ; # in the visible text again
+ update
+ lappend res $tk_textRedraw
+ .t mark set insert 3.8 ; # within the same line
+ update
+ lappend res $tk_textRedraw
+ # This last one is tricky: correct result really is {2.0 3.0} when
+ # calling .t mark set insert, two calls to TkTextChanged are done:
+ # (a) to redraw the line of the past position of the cursor
+ # (b) to redraw the line of the new position of the cursor
+ # During (a) the display line showing the cursor gets unlinked,
+ # which leads TkTextChanged in (b) to schedule a redraw starting
+ # one line _before_ the line containing the insert cursor. This is
+ # because during (b) findDLine cannot return the display line the
+ # cursor is in since this display line was just unlinked in (a).
+} {{8.0 9.0} {8.0 12.0} {8.0 12.0} {3.0 8.0} {2.0 3.0}}
test textDisp-9.1 {TkTextRedrawTag} {
.t configure -wrap char
@@ -1173,40 +1212,44 @@ test textDisp-9.3 {TkTextRedrawTag} {
.t insert 1.0 "Line 1\nLine 2 is long enough to wrap around\nLine 3\nLine 4"
update
.t tag add big 2.2 2.4
+ update
.t tag remove big 1.0 end
update
list $tk_textRelayout $tk_textRedraw
-} {2.0 2.0}
+} {{2.0 2.20} {2.0 2.20 eof}}
test textDisp-9.4 {TkTextRedrawTag} {
.t configure -wrap char
.t delete 1.0 end
.t insert 1.0 "Line 1\nLine 2 is long enough to wrap around\nLine 3\nLine 4"
update
.t tag add big 2.2 2.20
+ update
.t tag remove big 1.0 end
update
list $tk_textRelayout $tk_textRedraw
-} {2.0 2.0}
+} {{2.0 2.20} {2.0 2.20 eof}}
test textDisp-9.5 {TkTextRedrawTag} {
.t configure -wrap char
.t delete 1.0 end
.t insert 1.0 "Line 1\nLine 2 is long enough to wrap around\nLine 3\nLine 4"
update
.t tag add big 2.2 2.end
+ update
.t tag remove big 1.0 end
update
list $tk_textRelayout $tk_textRedraw
-} {{2.0 2.20} {2.0 2.20}}
+} {{2.0 2.20} {2.0 2.20 eof}}
test textDisp-9.6 {TkTextRedrawTag} {
.t configure -wrap char
.t delete 1.0 end
- .t insert 1.0 "Line 1\nLine 2 is long enough to wrap\nLine 3 is also long enough to wrap\nLine 4"
+ .t insert 1.0 "Line 1\nLine 2 is long enough to wrap\nLine 3 is also long enough to wrap"
update
.t tag add big 2.2 3.5
+ update
.t tag remove big 1.0 end
update
list $tk_textRelayout $tk_textRedraw
-} {{2.0 2.20 3.0} {2.0 2.20 3.0}}
+} {{2.0 2.20 3.0 3.20} {2.0 2.20 3.0 3.20 eof}}
test textDisp-9.7 {TkTextRedrawTag} {
.t configure -wrap char
.t delete 1.0 end
@@ -1258,6 +1301,34 @@ test textDisp-9.11 {TkTextRedrawTag} {
update
set tk_textRedraw
} {}
+test textDisp-9.12 {TkTextRedrawTag} {
+ .t configure -wrap char
+ .t delete 1.0 end
+ for {set i 1} {$i < 5} {incr i} {
+ .t insert end "Line $i+++Line $i\n"
+ }
+ .t tag configure hidden -elide true
+ .t tag add hidden 2.6 3.6
+ update
+ .t tag add hidden 3.11 4.6
+ update
+ list $tk_textRelayout $tk_textRedraw
+} {2.0 {2.0 eof}}
+test textDisp-9.13 {TkTextRedrawTag} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ for {set i 1} {$i < 10} {incr i} {
+ .t insert end "Line $i - This is Line [format %c [expr 64+$i]]\n"
+ }
+ .t tag add hidden 2.8 2.17
+ .t tag add hidden 6.8 7.17
+ .t tag configure hidden -background red
+ .t tag configure hidden -elide true
+ update
+ .t tag configure hidden -elide false
+ update
+ list $tk_textRelayout $tk_textRedraw
+} {{2.0 6.0 7.0} {2.0 6.0 7.0}}
test textDisp-10.1 {TkTextRelayoutWindow} {
.t configure -wrap char
@@ -1426,7 +1497,7 @@ test textDisp-11.15 {TkTextSetYView, only a few lines visible} {
update
.top.t see 11.0
.top.t index @0,0
- # Thie index 9.0 should be just visible by a couple of pixels
+ # The index 9.0 should be just visible by a couple of pixels
} {9.0}
test textDisp-11.16 {TkTextSetYView, only a few lines visible} {
.top.t yview 8.0
@@ -1439,9 +1510,66 @@ test textDisp-11.17 {TkTextSetYView, only a few lines visible} {
update
.top.t see 4.0
.top.t index @0,0
- # Thie index 2.0 should be just visible by a couple of pixels
+ # The index 2.0 should be just visible by a couple of pixels
} {2.0}
-destroy .top
+test textDisp-11.18 {TkTextSetYView, see in elided lines} {
+ .top.t delete 1.0 end
+ for {set i 1} {$i < 20} {incr i} {
+ .top.t insert end [string repeat "Line $i" 10]
+ .top.t insert end "\n"
+ }
+ .top.t yview 4.0
+ .top.t tag add hidden 4.10 "4.10 lineend"
+ .top.t tag add hidden 5.15 10.3
+ .top.t tag configure hidden -elide true
+ update
+ .top.t see "8.0 lineend"
+ # The index "8.0 lineend" is on screen despite elided -> no scroll
+ .top.t index @0,0
+} {4.0}
+test textDisp-11.19 {TkTextSetYView, see in elided lines} {
+ .top.t delete 1.0 end
+ for {set i 1} {$i < 50} {incr i} {
+ .top.t insert end "Line $i\n"
+ }
+ # button just for having a line with a larger height
+ button .top.t.b -text "Test" -bd 2 -highlightthickness 2
+ .top.t window create 21.0 -window .top.t.b
+ .top.t tag add hidden 15.36 21.0
+ .top.t tag configure hidden -elide true
+ .top.t configure -height 15
+ wm geometry .top 300x200+0+0
+ # Indices 21.0, 17.0 and 15.0 are all on the same display line
+ # therefore index @0,0 shall be the same for all of them
+ .top.t see end
+ update
+ .top.t see 21.0
+ update
+ set ind1 [.top.t index @0,0]
+ .top.t see end
+ update
+ .top.t see 17.0
+ update
+ set ind2 [.top.t index @0,0]
+ .top.t see end
+ update
+ .top.t see 15.0
+ update
+ set ind3 [.top.t index @0,0]
+ list [expr {$ind1 == $ind2}] [expr {$ind1 == $ind3}]
+} {1 1}
+test textDisp-11.20 {TkTextSetYView, see in elided lines} {
+ .top.t delete 1.0 end
+ .top.t configure -wrap none
+ for {set i 1} {$i < 5} {incr i} {
+ .top.t insert end [string repeat "Line $i " 50]
+ .top.t insert end "\n"
+ }
+ .top.t delete 3.11 3.14
+ .top.t tag add hidden 3.0 4.0
+ # this shall not crash (null chunkPtr in TkTextSeeCmd is tested)
+ .top.t see 3.0
+} {}
.t configure -wrap word
.t delete 50.0 51.0
@@ -1583,6 +1711,29 @@ test textDisp-13.10 {TkTextSeeCmd procedure} {} {
destroy $w
set res
} {}
+test textDisp-13.11 {TkTextSeeCmd procedure} {} {
+ # insertion of a character at end of a line containing multi-byte
+ # characters and calling see at the line end shall actually show
+ # this character
+ toplevel .top2
+ pack [text .top2.t2 -wrap none]
+ for {set i 1} {$i < 5} {incr i} {
+ .top2.t2 insert end [string repeat "Line $i: éèàçù" 5]\n
+
+ }
+ wm geometry .top2 300x200+0+0
+ update
+ .top2.t2 see "1.0 lineend"
+ update
+ set ref [.top2.t2 index @0,0]
+ .top2.t2 insert "1.0 lineend" ç
+ .top2.t2 see "1.0 lineend"
+ update
+ set new [.top2.t2 index @0,0]
+ set res [.top2.t2 compare $ref == $new]
+ destroy .top2
+ set res
+} {0}
wm geom . {}
.t configure -wrap none
@@ -2019,6 +2170,70 @@ test textDisp-16.40 {text count -xpixels} {
[.t count -xpixels 1.0 "1.0 displaylineend"] \
[.t count -xpixels 1.0 end]
} {35 -35 0 42 42 42 0}
+test textDisp-16.41 {text count -xpixels with indices in elided lines} {
+ set res {}
+ .t delete 1.0 end
+ for {set i 1} {$i < 40} {incr i} {
+ .t insert end [string repeat "Line $i" 20]
+ .t insert end "\n"
+ }
+ .t configure -wrap none
+ .t tag add hidden 5.15 20.15
+ .t tag configure hidden -elide true
+ lappend res [.t count -xpixels 5.15 6.0] \
+ [.t count -xpixels 5.15 6.1] \
+ [.t count -xpixels 6.0 6.1] \
+ [.t count -xpixels 6.1 6.2] \
+ [.t count -xpixels 6.1 6.0] \
+ [.t count -xpixels 6.0 7.0] \
+ [.t count -xpixels 6.1 7.1] \
+ [.t count -xpixels 15.0 20.15] \
+ [.t count -xpixels 20.15 20.16] \
+ [.t count -xpixels 20.16 20.15]
+ .t tag remove hidden 20.0 20.15
+ lappend res [expr {[.t count -xpixels 5.0 20.0] != 0}]
+} [list 0 0 0 0 0 0 0 0 $fixedWidth -$fixedWidth 1]
+test textDisp-16.42 {TkTextYviewCmd procedure with indices in elided lines} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ for {set i 1} {$i < 100} {incr i} {
+ .t insert end [string repeat "Line $i" 20]
+ .t insert end "\n"
+ }
+ .t tag add hidden 5.15 20.15
+ .t tag configure hidden -elide true
+ .t yview 35.0
+ .t yview scroll [expr {- 15 * $fixedHeight}] pixels
+ update
+ .t index @0,0
+} {5.0}
+test textDisp-16.43 {TkTextYviewCmd procedure with indices in elided lines} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ for {set i 1} {$i < 100} {incr i} {
+ .t insert end [string repeat "Line $i" 20]
+ .t insert end "\n"
+ }
+ .t tag add hidden 5.15 20.15
+ .t tag configure hidden -elide true
+ .t yview 35.0
+ .t yview scroll -15 units
+ update
+ .t index @0,0
+} {5.0}
+test textDisp-16.44 {TkTextYviewCmd procedure, scroll down, with elided lines} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ foreach x [list 0 1 2 3 4 5 6 7 8 9 0] {
+ .t insert end "$x aaa1\n$x bbb2\n$x ccc3\n$x ddd4\n$x eee5\n$x fff6"
+ .t insert end "$x 1111\n$x 2222\n$x 3333\n$x 4444\n$x 5555\n$x 6666" hidden
+ }
+ .t tag configure hidden -elide true ; # 5 hidden lines
+ update
+ .t see [expr {5 + [winfo height .t] / $fixedHeight} + 1].0
+ update
+ .t index @0,0
+} {2.0}
.t delete 1.0 end
foreach i {a b c d e f g h i j k l m n o p q r s t u v w x y z} {
@@ -2444,7 +2659,7 @@ test textDisp-19.11.23 {TextWidgetCmd procedure, "index +displaylines"} {
[.t index "12.0 +2d lines"] [.t index "11.0 +2d lines"] \
[.t index "13.0 +2d lines"] [.t index "13.0 +3d lines"] \
[.t index "13.0 +4d lines"]
-} {16.17 16.33 16.28 16.46 16.28 16.49 16.65 17.0}
+} {16.17 16.33 16.28 16.46 16.28 16.49 16.65 16.72}
.t tag remove elide 1.0 end
test textDisp-19.11.24 {TextWidgetCmd procedure, "index +/-displaylines"} {
list [.t index "11.5 + -1 display lines"] \
@@ -2553,6 +2768,63 @@ test textDisp-19.16 {count -ypixels} {
[.t count -ypixels 16.0 "16.0 displaylineend +1c"] \
[.t count -ypixels "16.0 +1 displaylines" "16.0 +4 displaylines +3c"]
} [list [expr {260 + 20 * $fixedDiff}] [expr {260 + 20 * $fixedDiff}] $fixedHeight [expr {2*$fixedHeight}] $fixedHeight [expr {3*$fixedHeight}]]
+test textDisp-19.17 {count -ypixels with indices in elided lines} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ for {set i 1} {$i < 100} {incr i} {
+ .t insert end [string repeat "Line $i" 20]
+ .t insert end "\n"
+ }
+ .t tag add hidden 5.15 20.15
+ .t tag configure hidden -elide true
+ set res {}
+ update
+ lappend res \
+ [.t count -ypixels 1.0 6.0] \
+ [.t count -ypixels 2.0 7.5] \
+ [.t count -ypixels 5.0 8.5] \
+ [.t count -ypixels 6.1 6.2] \
+ [.t count -ypixels 6.1 18.8] \
+ [.t count -ypixels 18.0 20.50] \
+ [.t count -ypixels 5.2 20.60] \
+ [.t count -ypixels 20.60 20.70] \
+ [.t count -ypixels 5.0 25.0] \
+ [.t count -ypixels 25.0 5.0] \
+ [.t count -ypixels 25.4 27.50] \
+ [.t count -ypixels 35.0 38.0]
+ .t yview 35.0
+ lappend res [.t count -ypixels 5.0 25.0]
+} [list [expr {4 * $fixedHeight}] [expr {3 * $fixedHeight}] 0 0 0 0 0 0 [expr {5 * $fixedHeight}] [expr {- 5 * $fixedHeight}] [expr {2 * $fixedHeight}] [expr {3 * $fixedHeight}] [expr {5 * $fixedHeight}]]
+test textDisp-19.18 {count -ypixels with indices in elided lines} {
+ .t configure -wrap none
+ .t delete 1.0 end
+ for {set i 1} {$i < 100} {incr i} {
+ .t insert end [string repeat "Line $i" 20]
+ .t insert end "\n"
+ }
+ .t tag add hidden 5.15 20.15
+ .t tag configure hidden -elide true
+ .t yview 35.0
+ set res {}
+ update
+ lappend res [.t count -ypixels 5.0 25.0]
+ .t yview scroll [expr {- 15 * $fixedHeight}] pixels
+ update
+ lappend res [.t count -ypixels 5.0 25.0]
+} [list [expr {5 * $fixedHeight}] [expr {5 * $fixedHeight}]]
+test textDisp-19.19 {count -ypixels with indices in elided lines} {
+ .t configure -wrap char
+ .t delete 1.0 end
+ for {set i 1} {$i < 25} {incr i} {
+ .t insert end [string repeat "Line $i -" 6]
+ .t insert end "\n"
+ }
+ .t tag add hidden 5.27 11.0
+ .t tag configure hidden -elide true
+ .t yview 5.0
+ update
+ set res [list [.t count -ypixels 5.0 11.0] [.t count -ypixels 5.0 11.20]]
+} [list [expr {1 * $fixedHeight}] [expr {2 * $fixedHeight}]]
.t delete 1.0 end
.t insert end "Line 1"
for {set i 2} {$i <= 200} {incr i} {
@@ -2722,6 +2994,42 @@ test textDisp-22.9 {TkTextCharBbox, handling of spacing} {textfonts} {
[.t bbox 1.1] [.t bbox 2.9]
} [list [list 24 11 10 4] [list 55 [expr {$fixedDiff/2 + 15}] 10 4] [list 10 [expr {2*$fixedDiff + 43}] 10 4] [list 76 [expr {2*$fixedDiff + 40}] 10 4] [list 10 11 7 $fixedHeight] [list 69 [expr {$fixedDiff + 34}] 7 $fixedHeight]]
.t tag delete spacing
+test textDisp-22.10 {TkTextCharBbox, handling of elided lines} {textfonts} {
+ .t configure -wrap char
+ .t delete 1.0 end
+ for {set i 1} {$i < 10} {incr i} {
+ .t insert end "Line $i - Line [format %c [expr 64+$i]]\n"
+ }
+ .t tag add hidden 2.8 2.13
+ .t tag add hidden 6.8 7.13
+ .t tag configure hidden -elide true
+ update
+ list \
+ [expr {[lindex [.t bbox 2.9] 0] - [lindex [.t bbox 2.8] 0]}] \
+ [expr {[lindex [.t bbox 2.10] 0] - [lindex [.t bbox 2.8] 0]}] \
+ [expr {[lindex [.t bbox 2.13] 0] - [lindex [.t bbox 2.8] 0]}] \
+ [expr {[lindex [.t bbox 6.9] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 6.10] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 6.13] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 6.14] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 6.15] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 7.0] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 7.1] 0] - [lindex [.t bbox 6.8] 0]}] \
+ [expr {[lindex [.t bbox 7.12] 0] - [lindex [.t bbox 6.8] 0]}]
+} [list 0 0 0 0 0 0 0 0 0 0 0]
+test textDisp-22.11 {TkTextCharBbox, handling of wrapped elided lines} {textfonts} {
+ .t configure -wrap char
+ .t delete 1.0 end
+ for {set i 1} {$i < 10} {incr i} {
+ .t insert end "Line $i - Line _$i - Lines .$i - Line [format %c [expr 64+$i]]\n"
+ }
+ .t tag add hidden 1.30 2.5
+ .t tag configure hidden -elide true
+ update
+ list \
+ [expr {[lindex [.t bbox 1.30] 0] - [lindex [.t bbox 2.4] 0]}] \
+ [expr {[lindex [.t bbox 1.30] 0] - [lindex [.t bbox 2.5] 0]}]
+} [list 0 0]
.t delete 1.0 end
.t insert end "Line 1"
diff --git a/tests/textImage.test b/tests/textImage.test
index 24246cc..4bb190c 100644
--- a/tests/textImage.test
+++ b/tests/textImage.test
@@ -316,8 +316,7 @@ test textImage-3.1 {image change propagation} -setup {
image delete vary
} -result {{base:0 0 5 5} {10:0 0 10 10} {20:0 0 20 20} {40:0 0 40 40}}
-# Fails in some environments (both in Linux and winXP)
-test textImage-3.2 {delayed image management} -setup {
+test textImage-3.2 {delayed image management, see also bug 1591493} -setup {
destroy .t
set result ""
} -body {
@@ -329,14 +328,16 @@ test textImage-3.2 {delayed image management} -setup {
pack .t
.t image create end -name test
update
- lappend result [.t bbox test]
+ foreach {x1 y1 w1 h1} [.t bbox test] {}
+ lappend result [list $x1 $w1 $h1]
.t image configure test -image small -align top
update
- lappend result [.t bbox test]
+ foreach {x2 y2 w2 h2} [.t bbox test] {}
+ lappend result [list [expr {$x1==$x2}] [expr {$w2>0}] [expr {$h2>0}]]
} -cleanup {
destroy .t
image delete small
-} -result {{} {0 0 5 5}}
+} -result {{0 0 0} {1 1 1}}
# some temporary random tests
diff --git a/tests/ttk/spinbox.test b/tests/ttk/spinbox.test
index 3397e37..f7741c6 100644
--- a/tests/ttk/spinbox.test
+++ b/tests/ttk/spinbox.test
@@ -144,7 +144,7 @@ test spinbox-1.8.4 "-validate option: " -setup {
pack .sb
.sb set 50
focus .sb
- after 100 {set ::spinbox_wait 1} ; vwait ::spinbox_wait
+ after 500 {set ::spinbox_wait 1} ; vwait ::spinbox_wait
set ::spinbox_test
} -cleanup {
destroy .sb
diff --git a/tests/winDialog.test b/tests/winDialog.test
index cd8d937..b7847a5 100644
--- a/tests/winDialog.test
+++ b/tests/winDialog.test
@@ -251,10 +251,14 @@ test winDialog-5.4 {GetFileName: Tcl_GetIndexFromObj() != TCL_OK} -constraints {
test winDialog-5.5 {GetFileName: Tcl_GetIndexFromObj() == TCL_OK} -constraints {
nt testwinevent
} -body {
- start {tk_getOpenFile -title bar}
- then {
+ start {set x [tk_getOpenFile -title bar]}
+ set y [then {
Click cancel
- }
+ }]
+ # Note this also tests fix for
+ # http://core.tcl.tk/tk/tktview/4a0451f5291b3c9168cc560747dae9264e1d2ef6
+ # $x is expected to be empty
+ append x $y
} -result {0}
test winDialog-5.6 {GetFileName: valid option, but missing value} -constraints {
nt
@@ -533,10 +537,12 @@ test winDialog-8.1 {OFNHookProc} -constraints {emptyTest nt} -body {}
test winDialog-9.1 {Tk_ChooseDirectoryObjCmd: no arguments} -constraints {
nt testwinevent
} -body {
- start {tk_chooseDirectory}
- then {
+ start {set x [tk_chooseDirectory]}
+ set y [then {
Click cancel
- }
+ }]
+ # $x should be "" on a Cancel
+ append x $y
} -result {0}
test winDialog-9.2 {Tk_ChooseDirectoryObjCmd: one argument} -constraints {
nt
diff --git a/unix/configure b/unix/configure
index 7d4a3e4..21a053e 100755
--- a/unix/configure
+++ b/unix/configure
@@ -1338,7 +1338,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
TK_VERSION=8.6
TK_MAJOR_VERSION=8
TK_MINOR_VERSION=6
-TK_PATCH_LEVEL=".3"
+TK_PATCH_LEVEL=".4"
VERSION=${TK_VERSION}
LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv"
@@ -9755,7 +9755,7 @@ ac_x_header_dirs='
/usr/openwin/share/include'
if test "$ac_x_includes" = no; then
- # Guess where to find include files, by looking for Xlib.h.
+ # Guess where to find include files, by looking for Intrinsic.h.
# First, try using that file with no special directory specified.
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
@@ -9763,7 +9763,7 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
_ACEOF
if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
(eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
@@ -9790,7 +9790,7 @@ else
sed 's/^/| /' conftest.$ac_ext >&5
for ac_dir in $ac_x_header_dirs; do
- if test -r "$ac_dir/X11/Xlib.h"; then
+ if test -r "$ac_dir/X11/Intrinsic.h"; then
ac_x_includes=$ac_dir
break
fi
@@ -9804,18 +9804,18 @@ if test "$ac_x_libraries" = no; then
# See if we find them without any special options.
# Don't add to $LIBS permanently.
ac_save_LIBS=$LIBS
- LIBS="-lX11 $LIBS"
+ LIBS="-lXt $LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
int
main ()
{
-XrmInitialize ()
+XtMalloc (0)
;
return 0;
}
diff --git a/unix/configure.in b/unix/configure.in
index ba1f077..26aadfd 100644
--- a/unix/configure.in
+++ b/unix/configure.in
@@ -25,7 +25,7 @@ m4_ifdef([SC_USE_CONFIG_HEADERS], [
TK_VERSION=8.6
TK_MAJOR_VERSION=8
TK_MINOR_VERSION=6
-TK_PATCH_LEVEL=".3"
+TK_PATCH_LEVEL=".4"
VERSION=${TK_VERSION}
LOCALES="cs da de el en en_gb eo es fr hu it nl pl pt ru sv"
diff --git a/unix/tk.spec b/unix/tk.spec
index 3b40820..af982f7 100644
--- a/unix/tk.spec
+++ b/unix/tk.spec
@@ -4,7 +4,7 @@
Name: tk
Summary: Tk graphical toolkit for the Tcl scripting language.
-Version: 8.6.3
+Version: 8.6.4
Release: 2
License: BSD
Group: Development/Languages
diff --git a/unix/tkConfig.h.in b/unix/tkConfig.h.in
index 392566b..1e5593c 100644
--- a/unix/tkConfig.h.in
+++ b/unix/tkConfig.h.in
@@ -4,9 +4,6 @@
#ifndef _TKCONFIG
#define _TKCONFIG
-/* Define if building universal (internal helper macro) */
-#undef AC_APPLE_UNIVERSAL_BUILD
-
/* Define to 1 if you have the <AvailabilityMacros.h> header file. */
#undef HAVE_AVAILABILITYMACROS_H
@@ -136,9 +133,6 @@
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
-/* Define to the home page for this package. */
-#undef PACKAGE_URL
-
/* Define to the version of this package. */
#undef PACKAGE_VERSION
@@ -187,17 +181,9 @@
/* Do we want to use the threaded memory allocator? */
#undef USE_THREAD_ALLOC
-/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
- significant byte first (like Motorola and SPARC, unlike Intel). */
-#if defined AC_APPLE_UNIVERSAL_BUILD
-# if defined __BIG_ENDIAN__
-# define WORDS_BIGENDIAN 1
-# endif
-#else
-# ifndef WORDS_BIGENDIAN
-# undef WORDS_BIGENDIAN
-# endif
-#endif
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
/* Is XKeycodeToKeysym deprecated? */
#undef XKEYCODETOKEYSYM_IS_DEPRECATED
@@ -255,7 +241,7 @@
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
-/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* Define to `unsigned' if <sys/types.h> does not define. */
#undef size_t
/* Do we want to use the strtod() in compat? */
diff --git a/unix/tkUnixButton.c b/unix/tkUnixButton.c
index e45812e..1aeefac 100644
--- a/unix/tkUnixButton.c
+++ b/unix/tkUnixButton.c
@@ -363,7 +363,7 @@ TkpDisplayButton(
* warning. */
int y, relief;
Tk_Window tkwin = butPtr->tkwin;
- int width, height, fullWidth, fullHeight;
+ int width = 0, height = 0, fullWidth, fullHeight;
int textXOffset, textYOffset;
int haveImage = 0, haveText = 0;
int offset; /* 1 means this is a button widget, so we
diff --git a/win/configure b/win/configure
index 0504f70..8b7ae07 100755
--- a/win/configure
+++ b/win/configure
@@ -1312,7 +1312,7 @@ SHELL=/bin/sh
TK_VERSION=8.6
TK_MAJOR_VERSION=8
TK_MINOR_VERSION=6
-TK_PATCH_LEVEL=".3"
+TK_PATCH_LEVEL=".4"
VER=$TK_MAJOR_VERSION$TK_MINOR_VERSION
#------------------------------------------------------------------------
diff --git a/win/configure.in b/win/configure.in
index ce49151..709b97f 100644
--- a/win/configure.in
+++ b/win/configure.in
@@ -14,7 +14,7 @@ SHELL=/bin/sh
TK_VERSION=8.6
TK_MAJOR_VERSION=8
TK_MINOR_VERSION=6
-TK_PATCH_LEVEL=".3"
+TK_PATCH_LEVEL=".4"
VER=$TK_MAJOR_VERSION$TK_MINOR_VERSION
#------------------------------------------------------------------------
diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c
index 69dcb06..c137111 100644
--- a/win/tkWinDialog.c
+++ b/win/tkWinDialog.c
@@ -209,19 +209,9 @@ enum OFNOper {
* older compilers? Should we prefix definitions with Tcl_ instead
* of using the same names as in the SDK?
*/
-#ifndef __IShellItemArray_INTERFACE_DEFINED__
-#define __IShellItemArray_INTERFACE_DEFINED__
-
-typedef enum SIATTRIBFLAGS {
- SIATTRIBFLAGS_AND = 0x1,
- SIATTRIBFLAGS_OR = 0x2,
- SIATTRIBFLAGS_APPCOMPAT = 0x3,
- SIATTRIBFLAGS_MASK = 0x3,
- SIATTRIBFLAGS_ALLITEMS = 0x4000
-} SIATTRIBFLAGS;
+#ifndef __IShellItem_INTERFACE_DEFINED__
+# define __IShellItem_INTERFACE_DEFINED__
#ifdef __MSVCRT__
-typedef ULONG SFGAOF;
-
typedef struct IShellItem IShellItem;
typedef enum __MIDL_IShellItem_0001 {
@@ -250,6 +240,21 @@ typedef struct IShellItemVtbl
struct IShellItem {
CONST_VTBL struct IShellItemVtbl *lpVtbl;
};
+#endif
+#endif
+
+#ifndef __IShellItemArray_INTERFACE_DEFINED__
+#define __IShellItemArray_INTERFACE_DEFINED__
+
+typedef enum SIATTRIBFLAGS {
+ SIATTRIBFLAGS_AND = 0x1,
+ SIATTRIBFLAGS_OR = 0x2,
+ SIATTRIBFLAGS_APPCOMPAT = 0x3,
+ SIATTRIBFLAGS_MASK = 0x3,
+ SIATTRIBFLAGS_ALLITEMS = 0x4000
+} SIATTRIBFLAGS;
+#ifdef __MSVCRT__
+typedef ULONG SFGAOF;
#endif /* __MSVCRT__ */
typedef struct IShellItemArray IShellItemArray;
typedef struct IShellItemArrayVtbl
@@ -1009,28 +1014,10 @@ Tk_GetSaveFileObjCmd(
*/
static void CleanupOFNOptions(OFNOpts *optsPtr)
{
- if (optsPtr->extObj) {
- Tcl_DecrRefCount(optsPtr->extObj);
- optsPtr->extObj = NULL;
- }
- if (optsPtr->titleObj) {
- Tcl_DecrRefCount(optsPtr->titleObj);
- optsPtr->titleObj = NULL;
- }
- if (optsPtr->filterObj) {
- Tcl_DecrRefCount(optsPtr->filterObj);
- optsPtr->filterObj = NULL;
- }
- if (optsPtr->typeVariableObj) {
- Tcl_DecrRefCount(optsPtr->typeVariableObj);
- optsPtr->typeVariableObj = NULL;
- }
- if (optsPtr->initialTypeObj) {
- Tcl_DecrRefCount(optsPtr->initialTypeObj);
- optsPtr->initialTypeObj = NULL;
- }
Tcl_DStringFree(&optsPtr->utfDirString);
}
+
+
/*
*----------------------------------------------------------------------
@@ -1142,21 +1129,9 @@ ParseOFNOptions(
string = Tcl_GetString(valuePtr);
switch (options[index].value) {
case FILE_DEFAULT:
- if (valuePtr) {
- Tcl_IncrRefCount(valuePtr);
- }
- if (optsPtr->extObj) {
- Tcl_DecrRefCount(optsPtr->extObj);
- }
optsPtr->extObj = valuePtr;
break;
case FILE_TYPES:
- if (valuePtr) {
- Tcl_IncrRefCount(valuePtr);
- }
- if (optsPtr->filterObj) {
- Tcl_DecrRefCount(optsPtr->filterObj);
- }
optsPtr->filterObj = valuePtr;
break;
case FILE_INITDIR:
@@ -1180,30 +1155,12 @@ ParseOFNOptions(
goto error_return;
break;
case FILE_TITLE:
- if (valuePtr) {
- Tcl_IncrRefCount(valuePtr);
- }
- if (optsPtr->titleObj) {
- Tcl_DecrRefCount(optsPtr->titleObj);
- }
optsPtr->titleObj = valuePtr;
break;
case FILE_TYPEVARIABLE:
- if (valuePtr) {
- Tcl_IncrRefCount(valuePtr);
- }
- if (optsPtr->typeVariableObj) {
- Tcl_DecrRefCount(optsPtr->typeVariableObj);
- }
optsPtr->typeVariableObj = valuePtr;
- if (optsPtr->initialTypeObj) {
- Tcl_DecrRefCount(optsPtr->initialTypeObj);
- }
optsPtr->initialTypeObj = Tcl_ObjGetVar2(interp, valuePtr,
NULL, TCL_GLOBAL_ONLY);
- if (optsPtr->initialTypeObj) {
- Tcl_IncrRefCount(optsPtr->initialTypeObj);
- }
break;
case FILE_MULTIPLE:
if (Tcl_GetBooleanFromObj(interp, valuePtr,
@@ -1450,6 +1407,21 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr,
hr = fdlgIf->lpVtbl->Show(fdlgIf, hWnd);
Tcl_SetServiceMode(oldMode);
+ /*
+ * Ensure that hWnd is enabled, because it can happen that we have updated
+ * the wrapper of the parent, which causes us to leave this child disabled
+ * (Windows loses sync).
+ */
+
+ if (hWnd)
+ EnableWindow(hWnd, 1);
+
+ /*
+ * Clear interp result since it might have been set during the modal loop.
+ * http://core.tcl.tk/tk/tktview/4a0451f5291b3c9168cc560747dae9264e1d2ef6
+ */
+ Tcl_ResetResult(interp);
+
if (SUCCEEDED(hr)) {
if ((oper == OFN_FILE_OPEN) && optsPtr->multi) {
IShellItemArray *multiIf;
@@ -1787,9 +1759,24 @@ static int GetFileNameXP(Tcl_Interp *interp, OFNOpts *optsPtr, enum OFNOper oper
listObjv[ofn.nFilterIndex - 1], &count,
&typeInfo) != TCL_OK) {
result = TCL_ERROR;
- } else if (Tcl_ObjSetVar2(interp, optsPtr->typeVariableObj, NULL,
- typeInfo[0], TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
- result = TCL_ERROR;
+ } else {
+ /*
+ * BUGFIX for d43a10ce2fed950e00890049f3c273f2cdd12583
+ * The original code was broken because it passed typeinfo[0]
+ * directly into Tcl_ObjSetVar2. In the case of typeInfo[0]
+ * pointing into a list which is also referenced by
+ * typeVariableObj, TOSV2 shimmers the object into
+ * variable intrep which loses the list representation.
+ * This invalidates typeInfo[0] which is freed but
+ * nevertheless stored as the value of the variable.
+ */
+ Tcl_Obj *selFilterObj = typeInfo[0];
+ Tcl_IncrRefCount(selFilterObj);
+ if (Tcl_ObjSetVar2(interp, optsPtr->typeVariableObj, NULL,
+ selFilterObj, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
+ result = TCL_ERROR;
+ }
+ Tcl_DecrRefCount(selFilterObj);
}
}
} else if (cdlgerr == FNERR_INVALIDFILENAME) {
diff --git a/win/tkWinTest.c b/win/tkWinTest.c
index 8a92f5a..d824ee4 100644
--- a/win/tkWinTest.c
+++ b/win/tkWinTest.c
@@ -82,7 +82,7 @@ TkplatformtestInit(
struct TestFindControlState {
int id;
HWND control;
-};
+};
/* Callback for window enumeration - used for TestFindControl */
BOOL CALLBACK TestFindControlCallback(