summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--library/scrlbar.tcl11
-rw-r--r--library/ttk/menubutton.tcl2
-rw-r--r--macosx/tkMacOSXNotify.c7
-rw-r--r--tests/scrollbar.test37
-rw-r--r--tests/ttk/checkbutton.test16
-rw-r--r--unix/tkUnixRFont.c150
6 files changed, 174 insertions, 49 deletions
diff --git a/library/scrlbar.tcl b/library/scrlbar.tcl
index b7be014..6f1caa2 100644
--- a/library/scrlbar.tcl
+++ b/library/scrlbar.tcl
@@ -430,6 +430,9 @@ proc ::tk::ScrollTopBottom {w x y} {
proc ::tk::ScrollButton2Down {w x y} {
variable ::tk::Priv
+ if {![winfo exists $w]} {
+ return
+ }
set element [$w identify $x $y]
if {[string match {arrow[12]} $element]} {
ScrollButtonDown $w $x $y
@@ -443,7 +446,9 @@ proc ::tk::ScrollButton2Down {w x y} {
# slider drag.
update idletasks
- $w configure -activerelief sunken
- $w activate slider
- ScrollStartDrag $w $x $y
+ if {[winfo exists $w]} {
+ $w configure -activerelief sunken
+ $w activate slider
+ ScrollStartDrag $w $x $y
+ }
}
diff --git a/library/ttk/menubutton.tcl b/library/ttk/menubutton.tcl
index 093bb02..2be064c 100644
--- a/library/ttk/menubutton.tcl
+++ b/library/ttk/menubutton.tcl
@@ -57,7 +57,7 @@ if {[tk windowingsystem] eq "x11"} {
bind TMenubutton <ButtonPress-1> \
{ %W state pressed ; ttk::menubutton::Popdown %W }
bind TMenubutton <ButtonRelease-1> \
- { %W state !pressed }
+ { if {[winfo exists %W]} { %W state !pressed } }
}
# PostPosition --
diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c
index 1455688..f14e1b8 100644
--- a/macosx/tkMacOSXNotify.c
+++ b/macosx/tkMacOSXNotify.c
@@ -270,10 +270,15 @@ TkMacOSXEventsCheckProc(
inMode:GetRunLoopMode(modalSession)
dequeue:NO];
/* We must not steal any events during LiveResize. */
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
if (testEvent && [[testEvent window] inLiveResize]) {
break;
}
-
+#else
+ if (testEvent && [[[testEvent window] contentView] inLiveResize]) {
+ break;
+ }
+#endif
currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(modalSession)
diff --git a/tests/scrollbar.test b/tests/scrollbar.test
index 3b16821..bd14067 100644
--- a/tests/scrollbar.test
+++ b/tests/scrollbar.test
@@ -662,6 +662,43 @@ test scrollbar-10.2 {<MouseWheel> event on scrollbar} -constraints {win|unix} -s
destroy .t .s
} -result {1.4}
+test scrollbar-11.1 {bug fix: [011706ec42] Scrollbar unsafe wrt widget destruction} -body {
+ proc destroy_scrollbar {} {
+ if {[winfo exists .top.s]} {
+ destroy .top.s
+ }
+ }
+ toplevel .top
+ scrollbar .top.s
+ bind .top.s <2> {destroy_scrollbar}
+ pack .top.s
+ focus -force .top.s
+ update
+ event generate .top.s <2>
+ update ; # shall not trigger error invalid command name ".top.s"
+} -cleanup {
+ destroy .top.s .top
+} -result {}
+test scrollbar-11.2 {bug fix: [011706ec42] Scrollbar unsafe wrt widget destruction} -body {
+ proc destroy_scrollbar {{y 0}} {
+ if {[winfo exists .top.s]} {
+ destroy .top.s
+ }
+ }
+ toplevel .top
+ wm minsize .top 50 400
+ update
+ scrollbar .top.s
+ bind .top.s <2> {after idle destroy_scrollbar}
+ pack .top.s -expand true -fill y
+ focus -force .top.s
+ update
+ event generate .top.s <2> -x 2 -y [expr {[winfo height .top.s] / 2}]
+ update ; # shall not trigger error invalid command name ".top.s"
+} -cleanup {
+ destroy .top.s .top
+} -result {}
+
catch {destroy .s}
catch {destroy .t}
diff --git a/tests/ttk/checkbutton.test b/tests/ttk/checkbutton.test
index e18ff32..6b79287 100644
--- a/tests/ttk/checkbutton.test
+++ b/tests/ttk/checkbutton.test
@@ -45,4 +45,20 @@ test checkbutton-1.6 "Checkbutton default variable" -body {
lappend result [info exists .cb] [set .cb] [.cb state]
} -result [list .cb 0 alternate 1 on selected 1 off {}]
+# Bug [109865fa01]
+test checkbutton-1.7 "Button destroyed by click" -body {
+ proc destroy_button {} {
+ destroy .top
+ }
+ toplevel .top
+ ttk::menubutton .top.mb -text Button -style TLabel
+ bind .top.mb <ButtonRelease-1> destroy_button
+ pack .top.mb
+ focus -force .top.mb
+ update
+ event generate .top.mb <1>
+ event generate .top.mb <ButtonRelease-1>
+ update ; # shall not trigger error invalid command name ".top.b"
+} -result {}
+
tcltest::cleanupTests
diff --git a/unix/tkUnixRFont.c b/unix/tkUnixRFont.c
index ab2ed4a..36e5462 100644
--- a/unix/tkUnixRFont.c
+++ b/unix/tkUnixRFont.c
@@ -14,6 +14,8 @@
#include <X11/Xft/Xft.h>
#include <ctype.h>
+#define MAX_CACHED_COLORS 16
+
typedef struct {
XftFont *ftFont;
XftFont *ft0Font;
@@ -23,6 +25,11 @@ typedef struct {
} UnixFtFace;
typedef struct {
+ XftColor color;
+ int next;
+} UnixFtColorList;
+
+typedef struct {
TkFont font; /* Stuff used by generic font package. Must be
* first in structure. */
UnixFtFace *faces;
@@ -33,7 +40,9 @@ typedef struct {
Display *display;
int screen;
XftDraw *ftDraw;
- XftColor color;
+ int ncolors;
+ int firstColor;
+ UnixFtColorList colors[MAX_CACHED_COLORS];
} UnixFtFont;
/*
@@ -289,11 +298,8 @@ InitFont(
fontPtr->display = Tk_Display(tkwin);
fontPtr->screen = Tk_ScreenNumber(tkwin);
fontPtr->ftDraw = 0;
- fontPtr->color.color.red = 0;
- fontPtr->color.color.green = 0;
- fontPtr->color.color.blue = 0;
- fontPtr->color.color.alpha = 0xffff;
- fontPtr->color.pixel = 0xffffffff;
+ fontPtr->ncolors = 0;
+ fontPtr->firstColor = -1;
/*
* Fill in platform-specific fields of TkFont.
@@ -737,6 +743,89 @@ TkpMeasureCharsInContext(
maxLength, flags, lengthPtr);
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * LookUpColor --
+ *
+ * Convert a pixel value to an XftColor. This can be slow due to the
+ * need to call XQueryColor, which involves a server round-trip. To
+ * avoid that, a least-recently-used cache of up to MAX_CACHED_COLORS
+ * is kept, in the form of a linked list. The returned color is moved
+ * to the front of the list, so repeatedly asking for the same one
+ * should be fast.
+ *
+ * Results:
+ * A pointer to the XftColor structure for the requested color is
+ * returned.
+ *
+ * Side effects:
+ * The converted color is stored in a cache in the UnixFtFont structure. The cache
+ * can hold at most MAX_CACHED_COLORS colors. If no more slots are available, the least
+ * recently used color is replaced with the new one.
+ *----------------------------------------------------------------------
+ */
+
+static XftColor *
+LookUpColor(Display *display, /* Display to lookup colors on */
+ UnixFtFont *fontPtr, /* Font to search for cached colors */
+ unsigned long pixel) /* Pixel value to translate to XftColor */
+{
+ int i, last = -1, last2 = -1;
+ XColor xcolor;
+
+ for (i = fontPtr->firstColor;
+ i >= 0; last2 = last, last = i, i = fontPtr->colors[i].next) {
+
+ if (pixel == fontPtr->colors[i].color.pixel) {
+ /*
+ * Color found in cache. Move it to the front of the list and return it.
+ */
+ if (last >= 0) {
+ fontPtr->colors[last].next = fontPtr->colors[i].next;
+ fontPtr->colors[i].next = fontPtr->firstColor;
+ fontPtr->firstColor = i;
+ }
+
+ return &fontPtr->colors[i].color;
+ }
+ }
+
+ /*
+ * Color wasn't found, so it needs to be added to the cache.
+ * If a spare slot is available, it can be put there. If not, last
+ * will now point to the least recently used color, so replace that one.
+ */
+
+ if (fontPtr->ncolors < MAX_CACHED_COLORS) {
+ last2 = -1;
+ last = fontPtr->ncolors++;
+ }
+
+ /*
+ * Translate the pixel value to a color. Needs a server round-trip.
+ */
+ xcolor.pixel = pixel;
+ XQueryColor(display, DefaultColormap(display, fontPtr->screen), &xcolor);
+
+ fontPtr->colors[last].color.color.red = xcolor.red;
+ fontPtr->colors[last].color.color.green = xcolor.green;
+ fontPtr->colors[last].color.color.blue = xcolor.blue;
+ fontPtr->colors[last].color.color.alpha = 0xffff;
+ fontPtr->colors[last].color.pixel = pixel;
+
+ /*
+ * Put at the front of the list.
+ */
+ if (last2 >= 0) {
+ fontPtr->colors[last2].next = fontPtr->colors[last].next;
+ }
+ fontPtr->colors[last].next = fontPtr->firstColor;
+ fontPtr->firstColor = last;
+
+ return &fontPtr->colors[last].color;
+}
+
#define NUM_SPEC 1024
void
@@ -760,7 +849,7 @@ Tk_DrawChars(
const int maxCoord = 0x7FFF;/* Xft coordinates are 16 bit values */
UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
XGCValues values;
- XColor xcolor;
+ XftColor *xftcolor;
int clen, nspec, xStart = x;
XftGlyphFontSpec specs[NUM_SPEC];
XGlyphInfo metrics;
@@ -782,16 +871,7 @@ Tk_DrawChars(
Tk_DeleteErrorHandler(handler);
}
XGetGCValues(display, gc, GCForeground, &values);
- if (values.foreground != fontPtr->color.pixel) {
- xcolor.pixel = values.foreground;
- XQueryColor(display, DefaultColormap(display, fontPtr->screen),
- &xcolor);
- fontPtr->color.color.red = xcolor.red;
- fontPtr->color.color.green = xcolor.green;
- fontPtr->color.color.blue = xcolor.blue;
- fontPtr->color.color.alpha = 0xffff;
- fontPtr->color.pixel = values.foreground;
- }
+ xftcolor = LookUpColor(display, fontPtr, values.foreground);
if (tsdPtr->clipRegion != None) {
XftDrawSetClip(fontPtr->ftDraw, tsdPtr->clipRegion);
}
@@ -823,14 +903,14 @@ Tk_DrawChars(
y += metrics.yOff;
nspec++;
if (nspec == NUM_SPEC) {
- XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color,
+ XftDrawGlyphFontSpec(fontPtr->ftDraw, xftcolor,
specs, nspec);
nspec = 0;
}
}
}
if (nspec) {
- XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, specs, nspec);
+ XftDrawGlyphFontSpec(fontPtr->ftDraw, xftcolor, specs, nspec);
}
doUnderlineStrikeout:
@@ -892,7 +972,7 @@ TkDrawAngledChars(
const int minCoord = -1000; /* Should be good enough... */
UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
XGCValues values;
- XColor xcolor;
+ XftColor *xftcolor;
int xStart = x, yStart = y;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
@@ -919,16 +999,7 @@ TkDrawAngledChars(
}
XGetGCValues(display, gc, GCForeground, &values);
- if (values.foreground != fontPtr->color.pixel) {
- xcolor.pixel = values.foreground;
- XQueryColor(display, DefaultColormap(display, fontPtr->screen),
- &xcolor);
- fontPtr->color.color.red = xcolor.red;
- fontPtr->color.color.green = xcolor.green;
- fontPtr->color.color.blue = xcolor.blue;
- fontPtr->color.color.alpha = 0xffff;
- fontPtr->color.pixel = values.foreground;
- }
+ xftcolor = LookUpColor(display, fontPtr, values.foreground);
if (tsdPtr->clipRegion != None) {
XftDrawSetClip(fontPtr->ftDraw, tsdPtr->clipRegion);
}
@@ -967,7 +1038,7 @@ TkDrawAngledChars(
* this information... but we'll be ready when it does!
*/
- XftDrawGlyphs(fontPtr->ftDraw, &fontPtr->color, currentFtFont,
+ XftDrawGlyphs(fontPtr->ftDraw, xftcolor, currentFtFont,
originX, originY, glyphs, nglyph);
}
originX = ROUND16(x);
@@ -984,7 +1055,7 @@ TkDrawAngledChars(
glyphs[nglyph++] = XftCharIndex(fontPtr->display, ftFont, c);
}
if (nglyph) {
- XftDrawGlyphs(fontPtr->ftDraw, &fontPtr->color, currentFtFont,
+ XftDrawGlyphs(fontPtr->ftDraw, xftcolor, currentFtFont,
originX, originY, glyphs, nglyph);
}
#else /* !XFT_HAS_FIXED_ROTATED_PLACEMENT */
@@ -1008,16 +1079,7 @@ TkDrawAngledChars(
Tk_DeleteErrorHandler(handler);
}
XGetGCValues(display, gc, GCForeground, &values);
- if (values.foreground != fontPtr->color.pixel) {
- xcolor.pixel = values.foreground;
- XQueryColor(display, DefaultColormap(display, fontPtr->screen),
- &xcolor);
- fontPtr->color.color.red = xcolor.red;
- fontPtr->color.color.green = xcolor.green;
- fontPtr->color.color.blue = xcolor.blue;
- fontPtr->color.color.alpha = 0xffff;
- fontPtr->color.pixel = values.foreground;
- }
+ xftcolor = LookUpColor(display, fontPtr, values.foreground);
if (tsdPtr->clipRegion != None) {
XftDrawSetClip(fontPtr->ftDraw, tsdPtr->clipRegion);
}
@@ -1051,14 +1113,14 @@ TkDrawAngledChars(
y += metrics.yOff*cosA - metrics.xOff*sinA;
nspec++;
if (nspec == NUM_SPEC) {
- XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color,
+ XftDrawGlyphFontSpec(fontPtr->ftDraw, xftcolor,
specs, nspec);
nspec = 0;
}
}
}
if (nspec) {
- XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, specs, nspec);
+ XftDrawGlyphFontSpec(fontPtr->ftDraw, xftcolor, specs, nspec);
}
#endif /* XFT_HAS_FIXED_ROTATED_PLACEMENT */