summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/menu.n10
-rw-r--r--doc/text.n12
-rw-r--r--generic/tkBind.c2
-rw-r--r--generic/tkEntry.c3
-rw-r--r--generic/tkText.c4
-rw-r--r--generic/ttk/ttkButton.c13
-rw-r--r--generic/ttk/ttkEntry.c3
-rw-r--r--generic/ttk/ttkImage.c34
-rw-r--r--generic/ttk/ttkTheme.h2
-rw-r--r--library/menu.tcl4
-rw-r--r--library/ttk/vistaTheme.tcl2
-rw-r--r--tests/button.test48
-rw-r--r--tests/listbox.test3
-rw-r--r--tests/menu.test29
-rw-r--r--tests/text.test44
-rw-r--r--tests/ttk/spinbox.test21
-rw-r--r--win/Makefile.in2
-rw-r--r--win/rules.vc2
-rw-r--r--win/tkWinFont.c2
-rw-r--r--win/tkWinKey.c51
-rw-r--r--win/tkWinX.c64
21 files changed, 284 insertions, 71 deletions
diff --git a/doc/menu.n b/doc/menu.n
index ed1bb33..9dd7ef4 100644
--- a/doc/menu.n
+++ b/doc/menu.n
@@ -98,8 +98,10 @@ a bitmap, or an image, controlled by the \fB\-label\fR,
\fB\-bitmap\fR, and \fB\-image\fR options for the entry.
If the \fB\-accelerator\fR option is specified for an entry then a second
textual field is displayed to the right of the label. The accelerator
-typically describes a keystroke sequence that may be typed in the
+typically describes a keystroke sequence that may be used in the
application to cause the same result as invoking the menu entry.
+This is a display option, it does not actually set the corresponding
+binding (which can be achieved using the \fBbind\fR command).
The third field is an \fIindicator\fR. The indicator is present only for
checkbutton or radiobutton entries. It indicates whether the entry
is selected or not, and is displayed to the left of the entry's
@@ -537,8 +539,10 @@ This option is not available for separator or tear-off entries.
.
Specifies a string to display at the right side of the menu entry.
Normally describes an accelerator keystroke sequence that may be
-typed to invoke the same function as the menu entry. This option
-is not available for separator or tear-off entries.
+used to invoke the same function as the menu entry. This is a display
+option, it does not actually set the corresponding binding (which can
+be achieved using the \fBbind\fR command). This option is not available
+for separator or tear-off entries.
.TP
\fB\-background \fIvalue\fR
.
diff --git a/doc/text.n b/doc/text.n
index e2bb01f..481580d 100644
--- a/doc/text.n
+++ b/doc/text.n
@@ -491,9 +491,10 @@ second and later display lines for a text line.
\fIColor\fR specifies the background color to use in regions that do not
contain characters because they are indented by \fB\-lmargin1\fR or
\fB\-lmargin2\fR. It may have any of the forms accepted by
-\fBTk_GetColor\fR.If \fIcolor\fR has not been specified, or if it is
-specified as an empty string, then the color specified by the
-\fB-background\fR widget option is used.
+\fBTk_GetColor\fR. If \fIcolor\fR has not been specified, or if it is
+specified as an empty string, then the color used is specified by the
+\fB-background\fR tag option (or, if this is also unspecified, by the
+\fB-background\fR widget option).
.TP
\fB\-offset \fIpixels\fR
.
@@ -537,9 +538,10 @@ character of that display line.
.
\fIColor\fR specifies the background color to use in regions that do not
contain characters because they are indented by \fB\-rmargin1\fR. It may
-have any of the forms accepted by \fBTk_GetColor\fR.If \fIcolor\fR has not
+have any of the forms accepted by \fBTk_GetColor\fR. If \fIcolor\fR has not
been specified, or if it is specified as an empty string, then the color
-specified by the \fB-background\fR widget option is used.
+used is specified by the \fB-background\fR tag option (or, if this is also
+unspecified, by the \fB-background\fR widget option).
.TP
\fB\-selectbackground \fIcolor\fR
\fIColor\fR specifies the background color to use when displaying selected
diff --git a/generic/tkBind.c b/generic/tkBind.c
index 3b05066..d3fdc96 100644
--- a/generic/tkBind.c
+++ b/generic/tkBind.c
@@ -3460,7 +3460,7 @@ HandleEventGenerate(
Tcl_DoWhenIdle(DoWarp, dispPtr);
dispPtr->flags |= TK_DISPLAY_IN_WARP;
}
- dispPtr->warpWindow = Tk_IdToWindow(Tk_Display(mainWin),
+ dispPtr->warpWindow = Tk_IdToWindow(dispPtr->display,
event.general.xmotion.window);
dispPtr->warpMainwin = mainWin;
dispPtr->warpX = event.general.xmotion.x;
diff --git a/generic/tkEntry.c b/generic/tkEntry.c
index ea8d7f1..c0ce47b 100644
--- a/generic/tkEntry.c
+++ b/generic/tkEntry.c
@@ -1943,7 +1943,8 @@ EntryComputeGeometry(
entryPtr->displayString = p;
for (i = entryPtr->numChars; --i >= 0; ) {
- p += Tcl_UniCharToUtf(ch, p);
+ memcpy(p, buf, size);
+ p += size;
}
*p = '\0';
}
diff --git a/generic/tkText.c b/generic/tkText.c
index 5ad527a..0e41ac8 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -547,7 +547,7 @@ CreateWidget(
Tcl_InitHashTable(&sharedPtr->windowTable, TCL_STRING_KEYS);
Tcl_InitHashTable(&sharedPtr->imageTable, TCL_STRING_KEYS);
sharedPtr->undoStack = TkUndoInitStack(interp,0);
- sharedPtr->undo = 1;
+ sharedPtr->undo = 0;
sharedPtr->isDirty = 0;
sharedPtr->dirtyMode = TK_TEXT_DIRTY_NORMAL;
sharedPtr->autoSeparators = 1;
@@ -3042,7 +3042,7 @@ CountIndices(
* If 'viewUpdate' is true, we may adjust the window contents'
* y-position, and scrollbar setting.
*
- * If 'viewUpdate' is false, true we can guarantee that textPtr->topIndex
+ * If 'viewUpdate' is true we can guarantee that textPtr->topIndex
* points to a valid TkTextLine after this function returns. However, if
* 'viewUpdate' is false, then there is no such guarantee (since
* topIndex.linePtr can be garbage). The caller is expected to take
diff --git a/generic/ttk/ttkButton.c b/generic/ttk/ttkButton.c
index bc44f25..c00754b 100644
--- a/generic/ttk/ttkButton.c
+++ b/generic/ttk/ttkButton.c
@@ -136,6 +136,15 @@ BaseCleanup(void *recordPtr)
TtkFreeImageSpec(basePtr->base.imageSpec);
}
+static void
+BaseImageChanged(
+ ClientData clientData, int x, int y, int width, int height,
+ int imageWidth, int imageHeight)
+{
+ Base *basePtr = (Base *)clientData;
+ TtkResizeWidget(&basePtr->core);
+}
+
static int BaseConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Base *basePtr = recordPtr;
@@ -149,8 +158,8 @@ static int BaseConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
}
if (basePtr->base.imageObj) {
- imageSpec = TtkGetImageSpec(
- interp, basePtr->core.tkwin, basePtr->base.imageObj);
+ imageSpec = TtkGetImageSpecEx(
+ interp, basePtr->core.tkwin, basePtr->base.imageObj, BaseImageChanged, basePtr);
if (!imageSpec) {
goto error;
}
diff --git a/generic/ttk/ttkEntry.c b/generic/ttk/ttkEntry.c
index f395649..533637d 100644
--- a/generic/ttk/ttkEntry.c
+++ b/generic/ttk/ttkEntry.c
@@ -290,7 +290,8 @@ static char *EntryDisplayString(const char *showChar, int numChars)
p = displayString = ckalloc(numChars * size + 1);
while (numChars--) {
- p += Tcl_UniCharToUtf(ch, p);
+ memcpy(p, buf, size);
+ p += size;
}
*p = '\0';
diff --git a/generic/ttk/ttkImage.c b/generic/ttk/ttkImage.c
index a5a3a52..e403e2d 100644
--- a/generic/ttk/ttkImage.c
+++ b/generic/ttk/ttkImage.c
@@ -25,6 +25,8 @@ struct TtkImageSpec {
int mapCount; /* #state-specific overrides */
Ttk_StateSpec *states; /* array[mapCount] of states ... */
Tk_Image *images; /* ... per-state images to use */
+ Tk_ImageChangedProc *imageChanged;
+ ClientData imageChangedClientData;
};
/* NullImageChanged --
@@ -34,15 +36,41 @@ static void NullImageChanged(ClientData clientData,
int x, int y, int width, int height, int imageWidth, int imageHeight)
{ /* No-op */ }
+/* ImageSpecImageChanged --
+ * Image changes should trigger a repaint.
+ */
+static void ImageSpecImageChanged(ClientData clientData,
+ int x, int y, int width, int height, int imageWidth, int imageHeight)
+{
+ Ttk_ImageSpec *imageSpec = (Ttk_ImageSpec *)clientData;
+ if (imageSpec->imageChanged != NULL) {
+ imageSpec->imageChanged(imageSpec->imageChangedClientData,
+ x, y, width, height,
+ imageWidth, imageHeight);
+ }
+}
+
/* TtkGetImageSpec --
* Constructs a Ttk_ImageSpec * from a Tcl_Obj *.
* Result must be released using TtkFreeImageSpec.
*
- * TODO: Need a variant of this that takes a user-specified ImageChanged proc
*/
Ttk_ImageSpec *
TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)
{
+ return TtkGetImageSpecEx(interp, tkwin, objPtr, NULL, NULL);
+}
+
+/* TtkGetImageSpecEx --
+ * Constructs a Ttk_ImageSpec * from a Tcl_Obj *.
+ * Result must be released using TtkFreeImageSpec.
+ * imageChangedProc will be called when not NULL when
+ * the image changes to allow widgets to repaint.
+ */
+Ttk_ImageSpec *
+TtkGetImageSpecEx(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr,
+ Tk_ImageChangedProc *imageChangedProc, ClientData imageChangedClientData)
+{
Ttk_ImageSpec *imageSpec = 0;
int i = 0, n = 0, objc;
Tcl_Obj **objv;
@@ -52,6 +80,8 @@ TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)
imageSpec->mapCount = 0;
imageSpec->states = 0;
imageSpec->images = 0;
+ imageSpec->imageChanged = imageChangedProc;
+ imageSpec->imageChangedClientData = imageChangedClientData;
if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
goto error;
@@ -74,7 +104,7 @@ TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)
/* Get base image:
*/
imageSpec->baseImage = Tk_GetImage(
- interp, tkwin, Tcl_GetString(objv[0]), NullImageChanged, NULL);
+ interp, tkwin, Tcl_GetString(objv[0]), ImageSpecImageChanged, imageSpec);
if (!imageSpec->baseImage) {
goto error;
}
diff --git a/generic/ttk/ttkTheme.h b/generic/ttk/ttkTheme.h
index 7bf2a7f..9251dea 100644
--- a/generic/ttk/ttkTheme.h
+++ b/generic/ttk/ttkTheme.h
@@ -372,6 +372,8 @@ MODULE_SCOPE void Ttk_RegisterNamedColor(Ttk_ResourceCache, const char *, XColor
typedef struct TtkImageSpec Ttk_ImageSpec;
TTKAPI Ttk_ImageSpec *TtkGetImageSpec(Tcl_Interp *, Tk_Window, Tcl_Obj *);
+TTKAPI Ttk_ImageSpec *TtkGetImageSpecEx(Tcl_Interp *, Tk_Window, Tcl_Obj *,
+ Tk_ImageChangedProc *, ClientData);
TTKAPI void TtkFreeImageSpec(Ttk_ImageSpec *);
TTKAPI Tk_Image TtkSelectImage(Ttk_ImageSpec *, Ttk_State);
diff --git a/library/menu.tcl b/library/menu.tcl
index a7aaa3f..b5dd88e 100644
--- a/library/menu.tcl
+++ b/library/menu.tcl
@@ -607,6 +607,10 @@ proc ::tk::MenuButtonDown menu {
if {![winfo viewable $menu]} {
return
}
+ if {[$menu index active] eq "none"} {
+ set Priv(window) {}
+ return
+ }
$menu postcascade active
if {$Priv(postedMb) ne "" && [winfo viewable $Priv(postedMb)]} {
grab -global $Priv(postedMb)
diff --git a/library/ttk/vistaTheme.tcl b/library/ttk/vistaTheme.tcl
index 99410cb..3f75f51 100644
--- a/library/ttk/vistaTheme.tcl
+++ b/library/ttk/vistaTheme.tcl
@@ -133,7 +133,7 @@ namespace eval ttk::theme::vista {
Spinbox.background -sticky news -children {
Spinbox.padding -sticky news -children {
Spinbox.innerbg -sticky news -children {
- Spinbox.textarea -expand 1 -sticky {}
+ Spinbox.textarea -expand 1
}
}
Spinbox.uparrow -side top -sticky ens
diff --git a/tests/button.test b/tests/button.test
index 708fc30..d4db317 100644
--- a/tests/button.test
+++ b/tests/button.test
@@ -3435,15 +3435,47 @@ test button-5.23 {ConfigureButton - -height option} -constraints {
test button-5.24 {ConfigureButton - computing geometry} -constraints {
fonts
} -body {
- button .b -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
- .b configure -text "Sample text" -width 10 -height 2
+ button .b -borderwidth 2 -highlightthickness 2 -font {Helvetica -12} \
+ -padx 30 -pady 20
+ # 1. button with text
+ .b configure -text "Sample text"
pack .b
- set result "[winfo reqwidth .b] [winfo reqheight .b]"
- .b configure -bitmap questhead
- lappend result [winfo reqwidth .b] [winfo reqheight .b]
-} -cleanup {
- destroy .b
-} -result {104 46 20 12}
+ set textwidth [font measure [.b cget -font] -displayof .b [.b cget -text]]
+ set expectedwidth [expr {$textwidth + 2*[.b cget -borderwidth] \
+ + 2*[.b cget -highlightthickness] + 2*[.b cget -padx]}]
+ incr expectedwidth 2 ; # added (hardcoded) in tkUnixButton.c
+ set result [expr $expectedwidth == [winfo reqwidth .b]]
+ set linespace [lindex [font metrics [.b cget -font] -displayof .b] 5]
+ set expectedheight [expr {$linespace + 2*[.b cget -borderwidth] \
+ + 2*[.b cget -highlightthickness] + 2*[.b cget -pady]}]
+ incr expectedheight 2 ; # added (hardcoded) in tkUnixButton.c
+ lappend result [expr $expectedheight == [winfo reqheight .b]]
+ # 2. button with a bitmap image
+ # there is no access to characteristics the predefined bitmaps,
+ # so define one as an image (copied from questhead.xbm)
+ set myquesthead [image create bitmap -data {
+ #define myquesthead_width 20
+ #define myquesthead_height 22
+ static unsigned char myquesthead_bits[] = {
+ 0xf8, 0x1f, 0x00, 0xac, 0x2a, 0x00, 0x56, 0x55, 0x00, 0xeb, 0xaf, 0x00,
+ 0xf5, 0x5f, 0x01, 0xfb, 0xbf, 0x00, 0x75, 0x5d, 0x01, 0xfb, 0xbe, 0x02,
+ 0x75, 0x5d, 0x05, 0xab, 0xbe, 0x0a, 0x55, 0x5f, 0x07, 0xab, 0xaf, 0x00,
+ 0xd6, 0x57, 0x01, 0xac, 0xab, 0x00, 0xd8, 0x57, 0x00, 0xb0, 0xaa, 0x00,
+ 0x50, 0x55, 0x00, 0xb0, 0x0b, 0x00, 0xd0, 0x17, 0x00, 0xb0, 0x0b, 0x00,
+ 0x58, 0x15, 0x00, 0xa8, 0x2a, 0x00};
+ }]
+ .b configure -image $myquesthead
+ set expectedwidth [expr {[image width $myquesthead] + 2*[.b cget -borderwidth] \
+ + 2*[.b cget -highlightthickness]}]
+ incr expectedwidth 2 ; # added (hardcoded) in tkUnixButton.c
+ lappend result [expr $expectedwidth == [winfo reqwidth .b]]
+ set expectedheight [expr {[image height $myquesthead] + 2*[.b cget -borderwidth] \
+ + 2*[.b cget -highlightthickness]}]
+ incr expectedheight 2 ; # added (hardcoded) in tkUnixButton.c
+ lappend result [expr $expectedheight == [winfo reqheight .b]]
+} -cleanup {
+ destroy .b
+} -result {1 1 1 1}
test button-5.25 {ConfigureButton - computing geometry} -setup {
button .b -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
diff --git a/tests/listbox.test b/tests/listbox.test
index 407420c..99c84a7 100644
--- a/tests/listbox.test
+++ b/tests/listbox.test
@@ -1222,6 +1222,7 @@ test listbox-4.1 {ConfigureListbox procedure} -constraints {
pack .l
update
} -body {
+ update
set x [getsize .]
.l configure -setgrid 0
update
@@ -2306,7 +2307,7 @@ test listbox-13.3 {ListboxScanTo procedure} -constraints {
.l scan dragto [expr 5+$width] [expr 10+$height]
update
lappend x [format {%.6g %.6g} {*}[.l xview]] [format {%.6g %.6g} {*}[.l yview]]
-} -result {{0.8 1} {0.75 1} {0.64 0.84} {0.25 0.5}}
+} -result {{0.8 1} {0.75 1} {0.6 0.8} {0.25 0.5}}
test listbox-14.1 {NearestListboxElement procedure, partial last line} -body {
diff --git a/tests/menu.test b/tests/menu.test
index aaadc86..05356e3 100644
--- a/tests/menu.test
+++ b/tests/menu.test
@@ -3878,6 +3878,35 @@ test menu-37.1 {menubar menues cannot be posted - bug 2160206} -setup {
destroy .m
} -result {1 {a menubar menu cannot be posted}}
+test menu-38.1 {Can't dismiss ttk::menubutton menu until mouse has hovered over it - bug fa32290898} -setup {
+} -constraints {macOrUnix} -body {
+ toplevel .top
+ ttk::menubutton .top.mb -text "Some menu";
+ menu .top.mb.m;
+ .top.mb.m add command -label "Item 1";
+ .top.mb.m add command -label "Item 2";
+ .top.mb configure -menu .top.mb.m;
+ pack .top.mb
+ update
+ # simulate mouse click on the menubutton, which posts its menu
+ event generate .top.mb <ButtonPress-1> -warp 1
+ update
+ after 50
+ event generate .top.mb <ButtonRelease-1>
+ update
+ # simulate mouse click on the menu again, i.e. without
+ # entering/leaving the posted menu
+ event generate .top.mb <ButtonPress-1>
+ update
+ after 50
+ event generate .top.mb <ButtonRelease-1>
+ update
+ # the menu shall have been unposted by the second click
+ winfo ismapped .top.mb.m
+} -cleanup {
+ destroy .top.mb.m .top.m .top
+} -result {0}
+
# cleanup
imageFinish
diff --git a/tests/text.test b/tests/text.test
index 720afbe..f640817 100644
--- a/tests/text.test
+++ b/tests/text.test
@@ -29,6 +29,15 @@ test text-1.1 {configuration option: "autoseparators"} -setup {
} -cleanup {
destroy .t
} -result {1}
+test text-1.1b {configuration option: "autoseparators", default} -setup {
+ text .t -borderwidth 2 -highlightthickness 2 -font {Courier -12 bold}
+ pack .t
+ update
+} -body {
+ .t cget -autoseparators
+} -cleanup {
+ destroy .t
+} -result {1}
test text-1.2 {configuration option: "autoseparators"} -setup {
text .t -borderwidth 2 -highlightthickness 2 -font {Courier -12 bold}
pack .t
@@ -428,6 +437,15 @@ test text-1.43 {configuration option: "maxundo"} -setup {
} -cleanup {
destroy .t
} -result {5}
+test text-1.43b {configuration option: "maxundo", default} -setup {
+ text .t -borderwidth 2 -highlightthickness 2 -font {Courier -12 bold}
+ pack .t
+ update
+} -body {
+ .t cget -maxundo
+} -cleanup {
+ destroy .t
+} -result {0}
test text-1.44 {configuration option: "maxundo"} -setup {
text .t -borderwidth 2 -highlightthickness 2 -font {Courier -12 bold}
pack .t
@@ -732,6 +750,15 @@ test text-1.75 {configuration option: "undo"} -setup {
} -cleanup {
destroy .t
} -result {1}
+test text-1.75b {configuration option: "undo", default} -setup {
+ text .t -borderwidth 2 -highlightthickness 2 -font {Courier -12 bold}
+ pack .t
+ update
+} -body {
+ .t cget -undo
+} -cleanup {
+ destroy .t
+} -result {0}
test text-1.76 {configuration option: "undo"} -setup {
text .t -borderwidth 2 -highlightthickness 2 -font {Courier -12 bold}
pack .t
@@ -6396,8 +6423,23 @@ test text-27.16a {undo configuration options with peers} -body {
lappend res [.t edit canundo]
lappend res [.tt edit canundo]
} -cleanup {
- destroy .t
+ destroy .t .tt
} -result {1 1 0 0 100 100 1 1}
+test text-27.16b {undo configuration options with peers, defaults} -body {
+ text .t
+ .t peer create .tt
+ set res [.t cget -undo]
+ lappend res [.tt cget -undo]
+ lappend res [.t cget -autoseparators]
+ lappend res [.tt cget -autoseparators]
+ lappend res [.t cget -maxundo]
+ lappend res [.tt cget -maxundo]
+ .t insert end "The undo stack is common between peers"
+ lappend res [.t edit canundo]
+ lappend res [.tt edit canundo]
+} -cleanup {
+ destroy .t .tt
+} -result {0 0 1 1 0 0 0 0}
test text-27.17 {bug fix 1536735 - undo with empty text} -body {
text .t -undo 1
set r [.t edit modified]
diff --git a/tests/ttk/spinbox.test b/tests/ttk/spinbox.test
index 32b77af..08f2bda 100644
--- a/tests/ttk/spinbox.test
+++ b/tests/ttk/spinbox.test
@@ -199,6 +199,27 @@ test spinbox-2.4 "current command -- value not in list" -constraints nyi -setup
destroy .sb
} -result -1
+test spinbox-3.0 "textarea should expand to fill widget" -setup {
+ set SBV 5
+ set ::spinbox_test {}
+ ttk::spinbox .sb -from 0 -to 10 -textvariable SBV
+} -body {
+ grid .sb -sticky ew
+ grid columnconfigure . 0 -weight 1
+ bind . <Map> {
+ after idle {
+ wm geometry . "210x80"
+ after 100 {set ::spinbox_test [.sb identify element 5 5]}
+ }
+ bind . <Map> {}
+ }
+ after 500 {set ::spinbox_wait 1} ; vwait ::spinbox_wait
+ set ::spinbox_test
+} -cleanup {
+ destroy .sb
+ unset -nocomplain ::spinbox_test SBV
+} -result {textarea}
+
# nostomp: NB intentional difference between ttk::spinbox and tk::spinbox;
# see also #1439266
#
diff --git a/win/Makefile.in b/win/Makefile.in
index 7b1766d..cc90b71 100644
--- a/win/Makefile.in
+++ b/win/Makefile.in
@@ -169,7 +169,7 @@ LDFLAGS_OPTIMIZE = @LDFLAGS_OPTIMIZE@
#CFLAGS = $(CFLAGS_DEBUG)
#CFLAGS = $(CFLAGS_OPTIMIZE)
#CFLAGS = $(CFLAGS_DEBUG) $(CFLAGS_OPTIMIZE)
-CFLAGS = @CFLAGS@ @CFLAGS_DEFAULT@ -DUNICODE -D_UNICODE
+CFLAGS = @CFLAGS@ @CFLAGS_DEFAULT@ -DUNICODE -D_UNICODE -D_ATL_XP_TARGETING
# Special compiler flags to use when building man2tcl on Windows.
MAN2TCLFLAGS = @MAN2TCLFLAGS@
diff --git a/win/rules.vc b/win/rules.vc
index 503df50..2cd711b 100644
--- a/win/rules.vc
+++ b/win/rules.vc
@@ -159,7 +159,7 @@ DEBUGFLAGS = $(DEBUGFLAGS) -RTC1
DEBUGFLAGS = $(DEBUGFLAGS) -GZ
!endif
-COMPILERFLAGS =-W3 -DUNICODE -D_UNICODE -D_USING_V110_SDK71_=1
+COMPILERFLAGS =-W3 /DUNICODE /D_UNICODE /D_ATL_XP_TARGETING
# In v13 -GL and -YX are incompatible.
!if [nmakehlp -c -YX]
diff --git a/win/tkWinFont.c b/win/tkWinFont.c
index 9172b00..940bc10 100644
--- a/win/tkWinFont.c
+++ b/win/tkWinFont.c
@@ -2188,7 +2188,7 @@ FontMapLoadPage(
{
FontFamily *familyPtr;
Tcl_Encoding encoding;
- char src[TCL_UTF_MAX], buf[16];
+ char src[XMaxTransChars], buf[16];
USHORT *startCount, *endCount;
int i, j, bitOffset, end, segCount;
diff --git a/win/tkWinKey.c b/win/tkWinKey.c
index ed546f7..2698c4d 100644
--- a/win/tkWinKey.c
+++ b/win/tkWinKey.c
@@ -102,7 +102,7 @@ TkpGetString(
*/
int unichar;
- char buf[TCL_UTF_MAX];
+ char buf[XMaxTransChars];
int len;
unichar = keyEv->trans_chars[1] & 0xff;
@@ -113,12 +113,23 @@ TkpGetString(
Tcl_DStringAppend(dsPtr, buf, len);
} else if (keyEv->send_event == -3) {
+
+ char buf[XMaxTransChars];
+ int len;
+
/*
- * Special case for WM_UNICHAR. xkey.trans_chars[] already contains a
- * UTF-8 char.
+ * Special case for WM_UNICHAR.
*/
- Tcl_DStringAppend(dsPtr, keyEv->trans_chars, keyEv->nbytes);
+ len = Tcl_UniCharToUtf(keyEv->keycode, buf);
+ if ((keyEv->keycode <= 0xffff) || (len == XMaxTransChars)) {
+ Tcl_DStringAppend(dsPtr, buf, len);
+ } else {
+ Tcl_UniCharToUtf(((keyEv->keycode - 0x10000) >> 10) | 0xd800, buf);
+ Tcl_DStringAppend(dsPtr, buf, 3);
+ Tcl_UniCharToUtf(((keyEv->keycode - 0x10000) & 0x3ff) | 0xdc00, buf);
+ Tcl_DStringAppend(dsPtr, buf, 3);
+ }
} else {
/*
* This is an event generated from generic code. It has no nchars or
@@ -129,7 +140,7 @@ TkpGetString(
if (((keysym != NoSymbol) && (keysym > 0) && (keysym < 256))
|| (keysym == XK_Return) || (keysym == XK_Tab)) {
- char buf[TCL_UTF_MAX];
+ char buf[XMaxTransChars];
int len;
len = Tcl_UniCharToUtf((Tcl_UniChar) (keysym & 255), buf);
@@ -335,18 +346,24 @@ KeycodeToKeysym(
/*
* Windows only gives us an undifferentiated VK_CONTROL code (for
* example) when either Control key is pressed. To distinguish between
- * left and right, we have to query the state of one of the two to
- * determine which was actually pressed. So if the keycode indicates
- * Control, Shift, or Menu (the key that everybody else calls Alt), do
- * this extra test. If the right-side key was pressed, return the
- * appropriate keycode. Otherwise, we fall through and rely on the
- * keymap table to hold the correct keysym value.
+ * left and right, we use the Extended flag. Indeed, the right Control
+ * and Alt (aka Menu) keys are such extended keys (which their left
+ * counterparts are not).
+ * Regarding the shift case, Windows does not set the Extended flag for
+ * the neither the left nor the right shift key. As a consequence another
+ * way to distinguish between the two keys is to query the state of one
+ * of the two to determine which was actually pressed. So if the keycode
+ * indicates Shift, do this extra test. If the right-side key was
+ * pressed, return the appropriate keycode. Otherwise, we fall through
+ * and rely on the keymap table to hold the correct keysym value.
+ * Note: this little trick only works for KeyPress, not for KeyRelease,
+ * for reasons stated in bug [2945130]
*/
case VK_CONTROL:
- if (GetKeyState(VK_RCONTROL) & 0x80) {
- return XK_Control_R;
- }
+ if (state & EXTENDED_MASK) {
+ return XK_Control_R;
+ }
break;
case VK_SHIFT:
if (GetKeyState(VK_RSHIFT) & 0x80) {
@@ -354,9 +371,9 @@ KeycodeToKeysym(
}
break;
case VK_MENU:
- if (GetKeyState(VK_RMENU) & 0x80) {
- return XK_Alt_R;
- }
+ if (state & EXTENDED_MASK) {
+ return XK_Alt_R;
+ }
break;
}
return keymap[keycode];
diff --git a/win/tkWinX.c b/win/tkWinX.c
index 6c44059..bb60a2d 100644
--- a/win/tkWinX.c
+++ b/win/tkWinX.c
@@ -81,6 +81,7 @@ typedef struct ThreadSpecificData {
TkDisplay *winDisplay; /* TkDisplay structure that represents Windows
* screen. */
int updatingClipboard; /* If 1, we are updating the clipboard. */
+ int surrogateBuffer; /* Buffer for first of surrogate pair. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
@@ -911,15 +912,24 @@ Tk_TranslateWinEvent(
Tk_PointerEvent(hwnd, (short) LOWORD(lParam), (short) HIWORD(lParam));
return 1;
+ case WM_SYSKEYDOWN:
+ case WM_KEYDOWN:
+ if (wParam == VK_PACKET) {
+ /*
+ * This will trigger WM_CHAR event(s) with unicode data.
+ */
+ *resultPtr =
+ PostMessageW(hwnd, message, HIWORD(lParam), LOWORD(lParam));
+ return 1;
+ }
+ /* else fall through */
case WM_CLOSE:
case WM_SETFOCUS:
case WM_KILLFOCUS:
case WM_DESTROYCLIPBOARD:
case WM_UNICHAR:
case WM_CHAR:
- case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
- case WM_KEYDOWN:
case WM_KEYUP:
case WM_MOUSEWHEEL:
GenerateXEvent(hwnd, message, wParam, lParam);
@@ -1197,17 +1207,34 @@ GenerateXEvent(
event.type = KeyPress;
event.xany.send_event = -1;
event.xkey.keycode = 0;
- event.xkey.nbytes = 1;
- event.xkey.trans_chars[0] = (char) wParam;
-
- if (IsDBCSLeadByte((BYTE) wParam)) {
- MSG msg;
+ if ((int)wParam & 0xff00) {
+ int ch1 = wParam & 0xffff;
- if ((PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) != 0)
- && (msg.message == WM_CHAR)) {
- GetMessage(&msg, NULL, 0, 0);
- event.xkey.nbytes = 2;
- event.xkey.trans_chars[1] = (char) msg.wParam;
+ if ((ch1 & 0xfc00) == 0xd800) {
+ tsdPtr->surrogateBuffer = ch1;
+ return;
+ }
+ if ((ch1 & 0xfc00) == 0xdc00) {
+ ch1 = ((tsdPtr->surrogateBuffer & 0x3ff) << 10) |
+ (ch1 & 0x3ff) | 0x10000;
+ tsdPtr->surrogateBuffer = 0;
+ }
+ event.xany.send_event = -3;
+ event.xkey.nbytes = 0;
+ event.xkey.keycode = ch1;
+ } else {
+ event.xkey.nbytes = 1;
+ event.xkey.trans_chars[0] = (char) wParam;
+
+ if (IsDBCSLeadByte((BYTE) wParam)) {
+ MSG msg;
+
+ if ((PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) != 0)
+ && (msg.message == WM_CHAR)) {
+ GetMessage(&msg, NULL, 0, 0);
+ event.xkey.nbytes = 2;
+ event.xkey.trans_chars[1] = (char) msg.wParam;
+ }
}
}
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
@@ -1215,15 +1242,10 @@ GenerateXEvent(
break;
case WM_UNICHAR: {
- char buffer[TCL_UTF_MAX+1];
- int i;
event.type = KeyPress;
event.xany.send_event = -3;
event.xkey.keycode = wParam;
- event.xkey.nbytes = Tcl_UniCharToUtf((int)wParam, buffer);
- for (i=0; i<event.xkey.nbytes && i<TCL_UTF_MAX; ++i) {
- event.xkey.trans_chars[i] = buffer[i];
- }
+ event.xkey.nbytes = 0;
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
event.type = KeyRelease;
break;
@@ -1321,11 +1343,7 @@ GetState(
state &= ~mask;
}
if (HIWORD(lParam) & KF_EXTENDED) {
- if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) {
- state |= EXTENDED_MASK;
- } else {
- state &= ~EXTENDED_MASK;
- }
+ state |= EXTENDED_MASK;
}
}
return state;