summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfvogel <fvogelnew1@free.fr>2016-05-20 15:43:02 (GMT)
committerfvogel <fvogelnew1@free.fr>2016-05-20 15:43:02 (GMT)
commit0529352ef03d575aa2df3317cd1e3145209c5292 (patch)
tree8b543030b85167824d0f31f1c0d3ce71a9782f92
parent1a64042e82238940c820745c5057df95c98e1c5d (diff)
parent2f150c8d18e576998e9d30ac08c562a1365b3051 (diff)
downloadtk-0529352ef03d575aa2df3317cd1e3145209c5292.zip
tk-0529352ef03d575aa2df3317cd1e3145209c5292.tar.gz
tk-0529352ef03d575aa2df3317cd1e3145209c5292.tar.bz2
Merged core-8-6-branchmultiscreens
-rw-r--r--generic/tkInt.h2
-rw-r--r--generic/tkListbox.c11
-rw-r--r--generic/tkText.c31
-rw-r--r--generic/tkTextDisp.c17
-rw-r--r--generic/tkUtil.c9
-rw-r--r--library/button.tcl19
-rw-r--r--library/scrlbar.tcl11
-rw-r--r--macosx/tkMacOSXDialog.c8
-rw-r--r--macosx/tkMacOSXNotify.c7
-rw-r--r--tests/button.test34
-rw-r--r--tests/listbox.test1
-rw-r--r--tests/scrollbar.test37
-rw-r--r--tests/text.test40
-rw-r--r--unix/tkUnixRFont.c150
-rw-r--r--win/tkWinDialog.c43
15 files changed, 285 insertions, 135 deletions
diff --git a/generic/tkInt.h b/generic/tkInt.h
index b644c5b..029f0f1 100644
--- a/generic/tkInt.h
+++ b/generic/tkInt.h
@@ -1208,7 +1208,7 @@ MODULE_SCOPE void TkpCreateBusy(Tk_FakeWin *winPtr, Tk_Window tkRef,
MODULE_SCOPE int TkBackgroundEvalObjv(Tcl_Interp *interp,
int objc, Tcl_Obj *const *objv, int flags);
MODULE_SCOPE void TkSendVirtualEvent(Tk_Window tgtWin,
- const char *eventName);
+ const char *eventName, Tcl_Obj *detail);
MODULE_SCOPE Tcl_Command TkMakeEnsemble(Tcl_Interp *interp,
const char *nsname, const char *name,
ClientData clientData, const TkEnsemble *map);
diff --git a/generic/tkListbox.c b/generic/tkListbox.c
index c7effdd..b059727 100644
--- a/generic/tkListbox.c
+++ b/generic/tkListbox.c
@@ -3223,16 +3223,7 @@ static void
GenerateListboxSelectEvent(
Listbox *listPtr) /* Information about widget. */
{
- union {XEvent general; XVirtualEvent virtual;} event;
-
- memset(&event, 0, sizeof(event));
- event.general.xany.type = VirtualEvent;
- event.general.xany.serial = NextRequest(Tk_Display(listPtr->tkwin));
- event.general.xany.send_event = False;
- event.general.xany.window = Tk_WindowId(listPtr->tkwin);
- event.general.xany.display = Tk_Display(listPtr->tkwin);
- event.virtual.name = Tk_GetUid("ListboxSelect");
- Tk_HandleEvent(&event.general);
+ TkSendVirtualEvent(listPtr->tkwin, "ListboxSelect", NULL);
}
/*
diff --git a/generic/tkText.c b/generic/tkText.c
index 506075d..3e8d625 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -3554,16 +3554,7 @@ TkTextSelectionEvent(
* event generate $textWidget <<Selection>>
*/
- union {XEvent general; XVirtualEvent virtual;} event;
-
- memset(&event, 0, sizeof(event));
- event.general.xany.type = VirtualEvent;
- event.general.xany.serial = NextRequest(Tk_Display(textPtr->tkwin));
- event.general.xany.send_event = False;
- event.general.xany.window = Tk_WindowId(textPtr->tkwin);
- event.general.xany.display = Tk_Display(textPtr->tkwin);
- event.virtual.name = Tk_GetUid("Selection");
- Tk_HandleEvent(&event.general);
+ TkSendVirtualEvent(textPtr->tkwin, "Selection", NULL);
}
/*
@@ -5215,7 +5206,10 @@ TextEditCmd(
*/
if ((!oldModified) != (!setModified)) {
- GenerateModifiedEvent(textPtr);
+ for (textPtr = textPtr->sharedTextPtr->peers; textPtr != NULL;
+ textPtr = textPtr->next) {
+ GenerateModifiedEvent(textPtr);
+ }
}
break;
case EDIT_REDO:
@@ -5361,21 +5355,8 @@ static void
GenerateModifiedEvent(
TkText *textPtr) /* Information about text widget. */
{
- union {
- XEvent general;
- XVirtualEvent virtual;
- } event;
-
Tk_MakeWindowExist(textPtr->tkwin);
-
- memset(&event, 0, sizeof(event));
- event.general.xany.type = VirtualEvent;
- event.general.xany.serial = NextRequest(Tk_Display(textPtr->tkwin));
- event.general.xany.send_event = False;
- event.general.xany.window = Tk_WindowId(textPtr->tkwin);
- event.general.xany.display = Tk_Display(textPtr->tkwin);
- event.virtual.name = Tk_GetUid("Modified");
- Tk_HandleEvent(&event.general);
+ TkSendVirtualEvent(textPtr->tkwin, "Modified", NULL);
}
/*
diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c
index 0849307..81bce94 100644
--- a/generic/tkTextDisp.c
+++ b/generic/tkTextDisp.c
@@ -3104,7 +3104,7 @@ AsyncUpdateLineMetrics(
* Send the <<WidgetViewSync>> event related to the text widget
* line metrics asynchronous update.
* This is equivalent to:
- * event generate $textWidget <<WidgetViewSync>> -detail $s
+ * event generate $textWidget <<WidgetViewSync>> -data $s
* where $s is the sync status: true (when the widget view is in
* sync with its internal data) or false (when it is not).
*
@@ -3120,19 +3120,10 @@ AsyncUpdateLineMetrics(
static void
GenerateWidgetViewSyncEvent(
TkText *textPtr, /* Information about text widget. */
- Bool InSync) /* True if in sync, false otherwise */
+ Bool InSync) /* true if in sync, false otherwise */
{
- union {XEvent general; XVirtualEvent virtual;} event;
-
- memset(&event, 0, sizeof(event));
- event.general.xany.type = VirtualEvent;
- event.general.xany.serial = NextRequest(Tk_Display(textPtr->tkwin));
- event.general.xany.send_event = False;
- event.general.xany.window = Tk_WindowId(textPtr->tkwin);
- event.general.xany.display = Tk_Display(textPtr->tkwin);
- event.virtual.name = Tk_GetUid("WidgetViewSync");
- event.virtual.user_data = Tcl_NewBooleanObj(InSync);
- Tk_HandleEvent(&event.general);
+ TkSendVirtualEvent(textPtr->tkwin, "WidgetViewSync",
+ Tcl_NewBooleanObj(InSync));
}
/*
diff --git a/generic/tkUtil.c b/generic/tkUtil.c
index 7ff9ecb..6563165 100644
--- a/generic/tkUtil.c
+++ b/generic/tkUtil.c
@@ -1162,7 +1162,8 @@ TkMakeEnsemble(
* TkSendVirtualEvent --
*
* Send a virtual event notification to the specified target window.
- * Equivalent to "event generate $target <<$eventName>>"
+ * Equivalent to:
+ * "event generate $target <<$eventName>> -data $detail"
*
* Note that we use Tk_QueueWindowEvent, not Tk_HandleEvent, so this
* routine does not reenter the interpreter.
@@ -1173,7 +1174,8 @@ TkMakeEnsemble(
void
TkSendVirtualEvent(
Tk_Window target,
- const char *eventName)
+ const char *eventName,
+ Tcl_Obj *detail)
{
union {XEvent general; XVirtualEvent virtual;} event;
@@ -1184,6 +1186,9 @@ TkSendVirtualEvent(
event.general.xany.window = Tk_WindowId(target);
event.general.xany.display = Tk_Display(target);
event.virtual.name = Tk_GetUid(eventName);
+ if (detail != NULL) {
+ event.virtual.user_data = detail;
+ }
Tk_QueueWindowEvent(&event.general, TCL_QUEUE_TAIL);
}
diff --git a/library/button.tcl b/library/button.tcl
index b2bafb2..80d8bf9 100644
--- a/library/button.tcl
+++ b/library/button.tcl
@@ -597,12 +597,25 @@ proc ::tk::ButtonUp w {
# w - The name of the widget.
proc ::tk::ButtonInvoke w {
- if {[$w cget -state] ne "disabled"} {
+ if {[winfo exists $w] && [$w cget -state] ne "disabled"} {
set oldRelief [$w cget -relief]
set oldState [$w cget -state]
$w configure -state active -relief sunken
- update idletasks
- after 100
+ after 100 [list ::tk::ButtonInvokeEnd $w $oldState $oldRelief]
+ }
+}
+
+# ::tk::ButtonInvokeEnd --
+# The procedure below is called after a button is invoked through
+# the keyboard. It simulate a release of the button via the mouse.
+#
+# Arguments:
+# w - The name of the widget.
+# oldState - Old state to be set back.
+# oldRelief - Old relief to be set back.
+
+proc ::tk::ButtonInvokeEnd {w oldState oldRelief} {
+ if {[winfo exists $w]} {
$w configure -state $oldState -relief $oldRelief
uplevel #0 [list $w invoke]
}
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/macosx/tkMacOSXDialog.c b/macosx/tkMacOSXDialog.c
index f6edb6d..80a7a11 100644
--- a/macosx/tkMacOSXDialog.c
+++ b/macosx/tkMacOSXDialog.c
@@ -1320,7 +1320,7 @@ FontchooserEvent(
switch (kind) {
case FontchooserClosed:
if (fcdPtr->parent != None) {
- TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserVisibility");
+ TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserVisibility", NULL);
fontchooserInterp = NULL;
}
break;
@@ -1343,7 +1343,7 @@ FontchooserEvent(
ckfree(tmpv);
}
}
- TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserFontChanged");
+ TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserFontChanged", NULL);
}
break;
}
@@ -1553,7 +1553,7 @@ FontchooserConfigureCmd(
[fm setSelectedAttributes:fontPanelFontAttributes
isMultiple:NO];
if ([fp isVisible]) {
- TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserFontChanged");
+ TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserFontChanged", NULL);
}
break;
case FontchooserCmd:
@@ -1616,7 +1616,7 @@ FontchooserShowCmd(
}
if (![fp isVisible]) {
[fm orderFrontFontPanel:NSApp];
- TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserVisibility");
+ TkSendVirtualEvent(fcdPtr->parent, "TkFontchooserVisibility", NULL);
}
fontchooserInterp = interp;
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/button.test b/tests/button.test
index 984fd43..708fc30 100644
--- a/tests/button.test
+++ b/tests/button.test
@@ -3750,7 +3750,7 @@ test button-12.1 {button widget vs hidden commands} -body {
destroy .b
} -result {1}
-test button-13.1 {size behaviouor: label} -setup {
+test button-13.1 {size behavior: label} -setup {
label .a -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
label .b -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
label .c -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
@@ -3769,7 +3769,7 @@ test button-13.1 {size behaviouor: label} -setup {
} -cleanup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.2 {size behaviouor: label} -setup {
+test button-13.2 {size behavior: label} -setup {
label .a -borderwidth 2 -highlightthickness 2 -font {Arial 20}
label .b -borderwidth 2 -highlightthickness 2 -font {Arial 20}
label .c -borderwidth 2 -highlightthickness 2 -font {Arial 20}
@@ -3789,7 +3789,7 @@ test button-13.2 {size behaviouor: label} -setup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.3 {size behaviouor: button} -setup {
+test button-13.3 {size behavior: button} -setup {
button .a -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
button .b -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
button .c -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
@@ -3808,7 +3808,7 @@ test button-13.3 {size behaviouor: button} -setup {
} -cleanup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.4 {size behaviouor: button} -setup {
+test button-13.4 {size behavior: button} -setup {
button .a -borderwidth 2 -highlightthickness 2 -font {Arial 20}
button .b -borderwidth 2 -highlightthickness 2 -font {Arial 20}
button .c -borderwidth 2 -highlightthickness 2 -font {Arial 20}
@@ -3828,7 +3828,7 @@ test button-13.4 {size behaviouor: button} -setup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.5 {size behaviouor: radiobutton} -setup {
+test button-13.5 {size behavior: radiobutton} -setup {
radiobutton .a -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
radiobutton .b -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
radiobutton .c -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
@@ -3848,7 +3848,7 @@ test button-13.5 {size behaviouor: radiobutton} -setup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.6 {size behaviouor: radiobutton} -setup {
+test button-13.6 {size behavior: radiobutton} -setup {
radiobutton .a -borderwidth 2 -highlightthickness 2 -font {Arial 20}
radiobutton .b -borderwidth 2 -highlightthickness 2 -font {Arial 20}
radiobutton .c -borderwidth 2 -highlightthickness 2 -font {Arial 20}
@@ -3868,7 +3868,7 @@ test button-13.6 {size behaviouor: radiobutton} -setup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.7 {size behaviouor: checkbutton} -setup {
+test button-13.7 {size behavior: checkbutton} -setup {
checkbutton .a -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
checkbutton .b -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
checkbutton .c -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
@@ -3888,7 +3888,7 @@ test button-13.7 {size behaviouor: checkbutton} -setup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.8 {size behaviouor: checkbutton} -setup {
+test button-13.8 {size behavior: checkbutton} -setup {
checkbutton .a -borderwidth 2 -highlightthickness 2 -font {Arial 20}
checkbutton .b -borderwidth 2 -highlightthickness 2 -font {Arial 20}
checkbutton .c -borderwidth 2 -highlightthickness 2 -font {Arial 20}
@@ -3908,6 +3908,24 @@ test button-13.8 {size behaviouor: checkbutton} -setup {
destroy .a .b .c
} -result {1 1 1}
+test button-14.1 {bug fix: [011706ec42] tk::ButtonInvoke unsafe wrt widget destruction} -body {
+ proc destroy_button {} {
+ if {[winfo exists .top.b]} {
+ destroy .top.b
+ }
+ }
+ toplevel .top
+ button .top.b -text Foo -command destroy_button
+ bind .top.b <space> destroy_button
+ pack .top.b
+ focus -force .top.b
+ update
+ event generate .top.b <space>
+ update ; # shall not trigger error invalid command name ".top.b"
+} -cleanup {
+ destroy .top.b .top
+} -result {}
+
imageFinish
cleanupTests
return
diff --git a/tests/listbox.test b/tests/listbox.test
index 76a4349..407420c 100644
--- a/tests/listbox.test
+++ b/tests/listbox.test
@@ -3170,6 +3170,7 @@ test listbox-31.2 {<<ListboxSelect>> event on lost selection} -setup {
focus -force .l
event generate .l <1> -x 5 -y 5 ; # <<ListboxSelect>> fires
selection clear ; # <<ListboxSelect>> fires again
+ update
set res
} -cleanup {
destroy .l
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/text.test b/tests/text.test
index a778b79..f217bcf 100644
--- a/tests/text.test
+++ b/tests/text.test
@@ -3053,6 +3053,25 @@ test text-11a.41 {"sync" "pendingsync" and <<WidgetViewSync>>} -setup {
destroy .top.yt .top
} -result {Sync:0 Pending:1 Sync:1 Pending:0}
+test text-11a.51 {<<WidgetViewSync>> calls TkSendVirtualEvent(),
+ NOT Tk_HandleEvent().
+ Bug [b362182e45704dd7bbd6aed91e48122035ea3d16]} -setup {
+ destroy .top.t .top
+} -body {
+ set res {}
+ toplevel .top
+ pack [text .top.t]
+ for {set i 1} {$i < 10000} {incr i} {
+ .top.t insert end "Hello world!\n"
+ }
+ bind .top.t <<WidgetViewSync>> {destroy .top.t}
+ .top.t tag add mytag 1.5 8000.8 ; # shall not crash
+ update
+ set res "Still doing fine!"
+} -cleanup {
+ destroy .top.t .top
+} -result {Still doing fine!}
+
test text-12.1 {TextWidgetCmd procedure, "index" option} -setup {
text .t
} -body {
@@ -6280,7 +6299,7 @@ test text-27.11 {TextEditCmd procedure, set modified flag repeat} -setup {
# Shouldn't require [update idle] to trigger event [Bug 1809538]
lappend ::retval [.t edit modified]
.t edit modified 1
- update idletasks
+ update
lappend ::retval [.t edit modified]
.t edit modified 1 ; # binding should only fire once [Bug 1799782]
update idletasks
@@ -6295,6 +6314,7 @@ test text-27.12 {<<Modified>> virtual event} -body {
bind .t <<Modified>> "set ::retval modified"
update idletasks
.t insert end "nothing special\n"
+ update
return $::retval
} -cleanup {
destroy .t
@@ -6305,6 +6325,7 @@ test text-27.13 {<<Modified>> virtual event - insert before Modified} -body {
bind .t <<Modified>> { set ::retval [.t get 1.0 end-1c] }
update idletasks
.t insert end "nothing special"
+ update
return $::retval
} -cleanup {
destroy .t
@@ -6317,10 +6338,26 @@ test text-27.14 {<<Modified>> virtual event - delete before Modified} -body {
.t insert end "nothing special"
.t edit modified 0
.t delete 1.0 1.2
+ update
set ::retval
} -cleanup {
destroy .t
} -result {thing special}
+test text-27.14a {<<Modified>> virtual event - propagation to peers} -body {
+# Bug [fd3a4dc111], <<Modified>> event is not always sent to peers
+ set ::retval 0
+ text .t -undo 1
+ .t peer create .tt
+ pack .t .tt
+ bind .t <<Modified>> {incr ::retval}
+ bind .tt <<Modified>> {incr ::retval}
+ .t insert end "This increments ::retval once for each peer, i.e. twice."
+ .t edit modified 0 ; # shall increment twice as well, not just once
+ update
+ set ::retval
+} -cleanup {
+ destroy .t .tt
+} -result {4}
test text-27.15 {<<Selection>> virtual event} -body {
set ::retval no_selection
pack [text .t -undo 1]
@@ -6328,6 +6365,7 @@ test text-27.15 {<<Selection>> virtual event} -body {
update idletasks
.t insert end "nothing special\n"
.t tag add sel 1.0 1.1
+ update
set ::retval
} -cleanup {
destroy .t
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 */
diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c
index d7f63fb..a7d8c7d 100644
--- a/win/tkWinDialog.c
+++ b/win/tkWinDialog.c
@@ -674,19 +674,25 @@ static void LoadShellProcs()
* processing functions are used to cope with keyboard navigation of
* controls.)
*
- * Here is one solution. After returning, we poll the message queue for
- * 1/4s looking for WM_LBUTTON up messages. If we see one it's consumed.
- * If we get a WM_LBUTTONDOWN message, then we exit early, since the user
- * must be doing something new. This fix only works for the current
- * application, so the problem will still occur if the open dialog
- * happens to be over another applications button. However this is a
- * fairly rare occurrance.
+ * Here is one solution. After returning, we flush all mouse events
+ * for 1/4 second. In 8.6.5 and earlier, the code used to
+ * poll the message queue consuming WM_LBUTTONUP messages.
+ * On seeing a WM_LBUTTONDOWN message, it would exit early, since the user
+ * must be doing something new. However this early exit does not work
+ * on Vista and later because the Windows sends both BUTTONDOWN and
+ * BUTTONUP after the DBLCLICK instead of just BUTTONUP as on XP.
+ * Rather than try and figure out version specific sequences, we
+ * ignore all mouse events in that interval.
+ *
+ * This fix only works for the current application, so the problem will
+ * still occur if the open dialog happens to be over another applications
+ * button. However this is a fairly rare occurrance.
*
* Results:
* None.
*
* Side effects:
- * Consumes an unwanted BUTTON messages.
+ * Consumes unwanted mouse related messages.
*
*-------------------------------------------------------------------------
*/
@@ -698,10 +704,7 @@ EatSpuriousMessageBugFix(void)
DWORD nTime = GetTickCount() + 250;
while (GetTickCount() < nTime) {
- if (PeekMessageA(&msg, 0, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE)){
- break;
- }
- PeekMessageA(&msg, 0, WM_LBUTTONUP, WM_LBUTTONUP, PM_REMOVE);
+ PeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE);
}
}
@@ -1113,7 +1116,7 @@ ParseOFNOptions(
if (strcmp(Tcl_GetString(objv[i]), "-xpstyle"))
goto error_return;
if (i + 1 == objc) {
- Tcl_SetResult(interp, "value for \"-xpstyle\" missing", TCL_STATIC);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj("value for \"-xpstyle\" missing", -1));
Tcl_SetErrorCode(interp, "TK", "FILEDIALOG", "VALUE", NULL);
goto error_return;
}
@@ -1281,9 +1284,8 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr,
int oldMode;
if (tsdPtr->newFileDialogsState != FDLG_STATE_USE_NEW) {
- /* XXX - should be an assert but Tcl does not seem to have one? */
- Tcl_SetResult(interp, "Internal error: GetFileNameVista: IFileDialog API not available", TCL_STATIC);
- return TCL_ERROR;
+ Tcl_Panic("Internal error: GetFileNameVista: IFileDialog API not available");
+ return TCL_ERROR;
}
/*
@@ -1425,6 +1427,7 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr,
oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
hr = fdlgIf->lpVtbl->Show(fdlgIf, hWnd);
Tcl_SetServiceMode(oldMode);
+ EatSpuriousMessageBugFix();
/*
* Ensure that hWnd is enabled, because it can happen that we have updated
@@ -3145,13 +3148,13 @@ HookProc(
if (IsWindow(hwndCtrl)) {
EnableWindow(hwndCtrl, FALSE);
}
- TkSendVirtualEvent(phd->parent, "TkFontchooserVisibility");
+ TkSendVirtualEvent(phd->parent, "TkFontchooserVisibility", NULL);
return 1; /* we handled the message */
}
if (WM_DESTROY == msg) {
phd->hwnd = NULL;
- TkSendVirtualEvent(phd->parent, "TkFontchooserVisibility");
+ TkSendVirtualEvent(phd->parent, "TkFontchooserVisibility", NULL);
return 0;
}
@@ -3169,7 +3172,7 @@ HookProc(
ApplyLogfont(phd->interp, phd->cmdObj, hdc, &lf);
}
if (phd && phd->parent) {
- TkSendVirtualEvent(phd->parent, "TkFontchooserFontChanged");
+ TkSendVirtualEvent(phd->parent, "TkFontchooserFontChanged", NULL);
}
return 1;
}
@@ -3481,7 +3484,7 @@ FontchooserShowCmd(
ApplyLogfont(hdPtr->interp, hdPtr->cmdObj, hdc, &lf);
}
if (hdPtr->parent) {
- TkSendVirtualEvent(hdPtr->parent, "TkFontchooserFontChanged");
+ TkSendVirtualEvent(hdPtr->parent, "TkFontchooserFontChanged", NULL);
}
}
Tcl_SetServiceMode(oldMode);