diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2019-11-22 08:54:22 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2019-11-22 08:54:22 (GMT) |
commit | 20a005ef0c7ab42b7f4f703572c56ac2af790137 (patch) | |
tree | 295f11b07b62234a45581c7e7e7d58a8a02c01d3 | |
parent | 371daa9f78b7f888ce06ec270477e2dc174a54a1 (diff) | |
parent | 8e65c4de1acc5309017fcc308dc64b435509e719 (diff) | |
download | tk-20a005ef0c7ab42b7f4f703572c56ac2af790137.zip tk-20a005ef0c7ab42b7f4f703572c56ac2af790137.tar.gz tk-20a005ef0c7ab42b7f4f703572c56ac2af790137.tar.bz2 |
Merge trunk
62 files changed, 775 insertions, 453 deletions
diff --git a/doc/ttk_button.n b/doc/ttk_button.n index 2b091ad..eb40d9d 100644 --- a/doc/ttk_button.n +++ b/doc/ttk_button.n @@ -72,6 +72,8 @@ are: .br \fB\-bordercolor\fP \fIcolor\fP .br +\fB\-compound\fP \fIcompound\fP +.br \fB\-darkcolor\fP \fIcolor\fP .br \fB\-foreground\fP \fIcolor\fP diff --git a/doc/ttk_checkbutton.n b/doc/ttk_checkbutton.n index a18a886..c78dc0e 100644 --- a/doc/ttk_checkbutton.n +++ b/doc/ttk_checkbutton.n @@ -80,6 +80,8 @@ are: .PP \fB\-background\fP \fIcolor\fP .br +\fB\-compound\fP \fIcompound\fP +.br \fB\-foreground\fP \fIcolor\fP .br \fB\-indicatorbackground\fP \fIcolor\fP diff --git a/doc/ttk_label.n b/doc/ttk_label.n index 8553a08..1b25f9f 100644 --- a/doc/ttk_label.n +++ b/doc/ttk_label.n @@ -56,6 +56,8 @@ are: .PP \fB\-background\fP \fIcolor\fP .br +\fB\-compound\fP \fIcompound\fP +.br \fB\-foreground\fP \fIcolor\fP .br \fB\-font\fP \fIfont\fP diff --git a/doc/ttk_menubutton.n b/doc/ttk_menubutton.n index 76d3829..0d80c1e 100644 --- a/doc/ttk_menubutton.n +++ b/doc/ttk_menubutton.n @@ -58,6 +58,8 @@ are: .br \fB\-background\fP \fIcolor\fP .br +\fB\-compound\fP \fIcompound\fP +.br \fB\-foreground\fP \fIcolor\fP .br \fB\-font\fP \fIfont\fP diff --git a/doc/ttk_notebook.n b/doc/ttk_notebook.n index 19416b5..ae32a44 100644 --- a/doc/ttk_notebook.n +++ b/doc/ttk_notebook.n @@ -242,6 +242,8 @@ are: .br \fB\-bordercolor\fP \fIcolor\fP .br +\fB\-compound\fP \fIcompound\fP +.br \fB\-expand\fP \fIpadding\fP .RS Defines how much the tab grows in size. Usually used with the diff --git a/doc/ttk_radiobutton.n b/doc/ttk_radiobutton.n index 1344ae2..2dc84be 100644 --- a/doc/ttk_radiobutton.n +++ b/doc/ttk_radiobutton.n @@ -77,6 +77,8 @@ are: .PP \fB\-background\fP \fIcolor\fP .br +\fB\-compound\fP \fIcompound\fP +.br \fB\-foreground\fP \fIcolor\fP .br \fB\-indicatorbackground\fP \fIcolor\fP diff --git a/doc/ttk_treeview.n b/doc/ttk_treeview.n index 125cc78..2deb5b5 100644 --- a/doc/ttk_treeview.n +++ b/doc/ttk_treeview.n @@ -235,7 +235,7 @@ A data cell. Returns the item ID of the item at position \fIy\fR. .TP \fIpathname \fBidentify column \fIx y\fR -Returns the data column identifier of the cell at position \fIx\fR. +Returns the display column identifier of the cell at position \fIx\fR. The tree column has ID \fB#0\fR. .TP \fIpathname \fBidentify element \fIx y\fR diff --git a/generic/ks_names.h b/generic/ks_names.h index b4c185f..a21b02b 100644 --- a/generic/ks_names.h +++ b/generic/ks_names.h @@ -521,7 +521,9 @@ { "Odiaeresis", 0xD6 }, { "multiply", 0xD7 }, { "Oslash", 0xD8 }, +#ifndef TK_NO_DEPRECATED { "Ooblique", 0xD8 }, +#endif { "Ugrave", 0xD9 }, { "Uacute", 0xDA }, { "Ucircumflex", 0xDB }, @@ -555,7 +557,9 @@ { "odiaeresis", 0xF6 }, { "division", 0xF7 }, { "oslash", 0xF8 }, +#ifndef TK_NO_DEPRECATED { "ooblique", 0xF8 }, +#endif { "ugrave", 0xF9 }, { "uacute", 0xFA }, { "ucircumflex", 0xFB }, @@ -960,9 +964,11 @@ { "Greek_IOTAaccent", 0x7A4 }, { "Greek_IOTAdieresis", 0x7A5 }, { "Greek_IOTAdiaeresis", 0x7A5 }, +{ "Greek_IOTAaccentdiaeresis", 0x7A6 }, { "Greek_OMICRONaccent", 0x7A7 }, { "Greek_UPSILONaccent", 0x7A8 }, { "Greek_UPSILONdieresis", 0x7A9 }, +{ "Greek_UPSILONaccentdieresis", 0x7AA }, { "Greek_OMEGAaccent", 0x7AB }, { "Greek_accentdieresis", 0x7AE }, { "Greek_horizbar", 0x7AF }, diff --git a/generic/nanosvg.h b/generic/nanosvg.h index b449dc2..5377ae0 100755 --- a/generic/nanosvg.h +++ b/generic/nanosvg.h @@ -704,10 +704,10 @@ static void nsvg__deleteStyles(NSVGstyles* style) { while (style) { NSVGstyles *next = style->next; if (style->name!= NULL) - free(style->name); + NANOSVG_free(style->name); if (style->description != NULL) - free(style->description); - free(style); + NANOSVG_free(style->description); + NANOSVG_free(style); style = next; } } @@ -2843,7 +2843,7 @@ static void nsvg__content(void* ud, const char* s) if (state == 1) { NSVGstyles* next = p->styles; - p->styles = (NSVGstyles*)malloc(sizeof(NSVGstyles)); + p->styles = (NSVGstyles*)NANOSVG_malloc(sizeof(NSVGstyles)); p->styles->next = next; p->styles->name = nsvg__strndup(start, (size_t)(s - start)); start = s + 1; diff --git a/generic/tkFocus.c b/generic/tkFocus.c index 7a4bdbc..7b5acfb 100644 --- a/generic/tkFocus.c +++ b/generic/tkFocus.c @@ -629,7 +629,8 @@ TkSetFocusWin( } tlFocusPtr->focusWinPtr = winPtr; - if (topLevelPtr->flags & TK_EMBEDDED) { + if (topLevelPtr->flags & TK_EMBEDDED && + (displayFocusPtr->focusWinPtr == NULL)) { /* * We are assigning focus to an embedded toplevel. The platform diff --git a/generic/tkFont.c b/generic/tkFont.c index cc7861f..44e2aad 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -13,7 +13,9 @@ #include "tkInt.h" #include "tkFont.h" - +#if defined(MAC_OSX_TK) +#include "tkMacOSXInt.h" +#endif /* * The following structure is used to keep track of all the fonts that exist * in the current application. It must be stored in the TkMainInfo for the @@ -873,7 +875,18 @@ TheWorldHasChanged( ClientData clientData) /* Info about application's fonts. */ { TkFontInfo *fiPtr = clientData; +#if defined(MAC_OSX_TK) + + /* + * On macOS it is catastrophic to recompute all widgets while the + * [NSView drawRect] method is drawing. The best that we can do in + * that situation is to abort the recomputation and hope for the best. + */ + if (TkpAppIsDrawing()) { + return; + } +#endif fiPtr->updatePending = 0; RecomputeWidgets(fiPtr->mainPtr->winPtr); } diff --git a/generic/ttk/ttkButton.c b/generic/ttk/ttkButton.c index d05a514..47e704c 100644 --- a/generic/ttk/ttkButton.c +++ b/generic/ttk/ttkButton.c @@ -84,8 +84,9 @@ static Tk_OptionSpec BaseOptionSpecs[] = * Compound base/image options */ {TK_OPTION_STRING_TABLE, "-compound", "compound", "Compound", - "none", offsetof(Base,base.compoundObj), -1, - 0,(ClientData)ttkCompoundStrings,GEOMETRY_CHANGED }, + NULL, offsetof(Base,base.compoundObj), -1, + TK_OPTION_NULL_OK,(ClientData)ttkCompoundStrings, + GEOMETRY_CHANGED }, {TK_OPTION_STRING, "-padding", "padding", "Pad", NULL, offsetof(Base,base.paddingObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED}, diff --git a/generic/ttk/ttkNotebook.c b/generic/ttk/ttkNotebook.c index 159a88d..e167374 100644 --- a/generic/ttk/ttkNotebook.c +++ b/generic/ttk/ttkNotebook.c @@ -65,8 +65,8 @@ static Tk_OptionSpec TabOptionSpecs[] = {TK_OPTION_STRING, "-image", "image", "Image", NULL/*default*/, offsetof(Tab,imageObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED }, {TK_OPTION_STRING_TABLE, "-compound", "compound", "Compound", - "none", offsetof(Tab,compoundObj), -1, - 0,(ClientData)ttkCompoundStrings,GEOMETRY_CHANGED }, + NULL, offsetof(Tab,compoundObj), -1, + TK_OPTION_NULL_OK,(ClientData)ttkCompoundStrings,GEOMETRY_CHANGED }, {TK_OPTION_INT, "-underline", "underline", "Underline", "-1", offsetof(Tab,underlineObj), -1, 0,0,GEOMETRY_CHANGED }, {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0 } diff --git a/generic/ttk/ttkTreeview.c b/generic/ttk/ttkTreeview.c index 5e5c2f6..a11389b 100644 --- a/generic/ttk/ttkTreeview.c +++ b/generic/ttk/ttkTreeview.c @@ -2886,28 +2886,8 @@ static int TreeviewDragCommand( TreeColumn *c = tv->tree.displayColumns[i]; int right = left + c->width; if (c == column) { - /* The limit not to exceed at the right is given by the tree width - minus the sum of the min widths of the columns at the right of - the one being resized (and don't forget possible x scrolling!). - For stretchable columns, this min width really is the minWidth, - for non-stretchable columns, this is the column width. - */ - int newxRightLimit = tv->tree.treeArea.x - tv->tree.xscroll.first - + tv->tree.treeArea.width; - int j = i + 1; - while (j < tv->tree.nDisplayColumns) { - TreeColumn *cr = tv->tree.displayColumns[j]; - if (cr->stretch) { - newxRightLimit -= cr->minWidth; - } else { - newxRightLimit -= cr->width; - } - ++j; - } - if (newx <= newxRightLimit) { - DragColumn(tv, i, newx - right); - TtkRedisplayWidget(&tv->core); - } + DragColumn(tv, i, newx - right); + TtkRedisplayWidget(&tv->core); return TCL_OK; } left = right; diff --git a/library/demos/unicodeout.tcl b/library/demos/unicodeout.tcl index 9cd3661..25ee932 100644 --- a/library/demos/unicodeout.tcl +++ b/library/demos/unicodeout.tcl @@ -131,8 +131,13 @@ addSample $w Japanese \ addSample $w Korean "\uB300\uD55C\uBBFC\uAD6D\uC758 \uD55C\uAE00" addSample $w Russian \ "\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u044F\u0437\u044B\u043A" -addSample $w Emoji \ - "\U1F600\U1F4A9\U1F44D\U1F1F3\U1F1F1" +if {[package vsatisfies [package provide Tcl] 8.7-]} { + addSample $w Emoji \ + "\U1F600\U1F4A9\U1F44D\U1F1F3\U1F1F1" +} elseif {([tk windowingsystem] ne "x11") || (![catch {tk::pkgconfig get fontsystem} fs] && ($fs eq "xft"))} { + addSample $w Emoji \ + "\uD83D\uDE00\uD83D\uDCA9\uD83D\uDC4D\uD83C\uDDF3\uD83C\uDDF1" +} ## We're done processing, so change things back to normal running... destroy $w.wait diff --git a/library/entry.tcl b/library/entry.tcl index 0cc9ffb..2aab934 100644 --- a/library/entry.tcl +++ b/library/entry.tcl @@ -74,11 +74,6 @@ bind Entry <<TraverseIn>> { # Standard Motif bindings: -bind Entry <Map> { - if {[tk windowingsystem] eq "aqua"} { - ::tk::RegisterServiceWidget %W - } -} bind Entry <1> { tk::EntryButton1 %W %x %W selection clear @@ -277,6 +272,25 @@ bind Entry <Meta-Delete> { } } +# Bindings for IME text input and accents. + +bind Entry <<TkStartIMEMarkedText>> { + dict set ::tk::Priv(IMETextMark) "%W" [%W index insert] +} +bind Entry <<TkEndIMEMarkedText>> { + if { [catch {dict get $::tk::Priv(IMETextMark) "%W"} mark] } { + bell + } else { + %W selection range $mark insert + } +} +bind Entry <<TkClearIMEMarkedText>> { + %W delete [dict get $::tk::Priv(IMETextMark) "%W"] [%W index insert] +} +bind Entry <<TkAccentBackspace>> { + tk::EntryBackspace %W +} + # A few additional bindings of my own. bind Entry <2> { diff --git a/library/iconlist.tcl b/library/iconlist.tcl index 2095ad6..753f183 100644 --- a/library/iconlist.tcl +++ b/library/iconlist.tcl @@ -447,10 +447,10 @@ package require Tk 8.6 bind $canvas <Shift-B1-Motion> [namespace code {my ShiftMotion1 %x %y}] if {[tk windowingsystem] eq "aqua"} { - bind $canvas <Shift-MouseWheel> [namespace code {my MouseWheel [expr {40 * (%W)}]}] - bind $canvas <Option-Shift-MouseWheel> [namespace code {my MouseWheel [expr {400 * (%W)}]}] + bind $canvas <Shift-MouseWheel> [namespace code {my MouseWheel [expr {40 * (%D)}]}] + bind $canvas <Option-Shift-MouseWheel> [namespace code {my MouseWheel [expr {400 * (%D)}]}] } else { - bind $canvas <Shift-MouseWheel> [namespace code {my MouseWheel %W}] + bind $canvas <Shift-MouseWheel> [namespace code {my MouseWheel %D}] } if {[tk windowingsystem] eq "x11"} { bind $canvas <Shift-4> [namespace code {my MouseWheel 120}] diff --git a/library/listbox.tcl b/library/listbox.tcl index f057151..3802223 100644 --- a/library/listbox.tcl +++ b/library/listbox.tcl @@ -204,14 +204,14 @@ if {[tk windowingsystem] eq "aqua"} { if {%D >= 0} { %W yview scroll [expr {-%D/30}] units } else { - %W yview scroll [expr {29-%D/30}] units + %W yview scroll [expr {(29-%D)/30}] units } } bind Listbox <Shift-MouseWheel> { if {%D >= 0} { %W xview scroll [expr {-%D/30}] units } else { - %W xview scroll [expr {29-%D/30}] units + %W xview scroll [expr {(29-%D)/30}] units } } } diff --git a/library/text.tcl b/library/text.tcl index ddc0490..96ab6d2 100644 --- a/library/text.tcl +++ b/library/text.tcl @@ -42,12 +42,6 @@ # Standard Motif bindings: -bind Text <Map> { - if {[tk windowingsystem] eq "aqua"} { - ::tk::RegisterServiceWidget %W - } -} - bind Text <1> { tk::TextButton1 %W %x %y %W tag remove sel 0.0 end @@ -397,6 +391,26 @@ bind Text <Meta-Delete> { } } +# Bindings for IME text input. + +bind Text <<TkStartIMEMarkedText>> { + dict set ::tk::Priv(IMETextMark) "%W" [%W index insert] +} +bind Text <<TkEndIMEMarkedText>> { + if { [catch {dict get $::tk::Priv(IMETextMark) "%W"} mark] } { + bell + } else { + %W tag add IMEmarkedtext $mark insert + %W tag configure IMEmarkedtext -underline on + } +} +bind Text <<TkClearIMEMarkedText>> { + %W delete IMEmarkedtext.first IMEmarkedtext.last +} +bind Text <<TkAccentBackspace>> { + %W delete insert-1c +} + # Macintosh only bindings: if {[tk windowingsystem] eq "aqua"} { @@ -1223,7 +1237,6 @@ proc ::tk::TextScanDrag {w x y} { $w scan dragto $x $y } } - # ::tk::TextUndoRedoProcessMarks -- # # This proc is executed after an undo or redo action. diff --git a/library/tk.tcl b/library/tk.tcl index fcc987d..75574ca 100644 --- a/library/tk.tcl +++ b/library/tk.tcl @@ -687,11 +687,6 @@ if {[tk windowingsystem] eq "aqua"} { if {[tk windowingsystem] eq "aqua"} { - #register to send data to macOS Services - proc ::tk::RegisterServiceWidget {w} { - ::tk::mac::registerServiceWidget $w - } - #stub procedures to respond to "do script" Apple Events proc ::tk::mac::DoScriptFile {file} { source $file @@ -701,7 +696,10 @@ if {[tk windowingsystem] eq "aqua"} { } } +# Create a dictionary to store the starting index of the IME marked +# text in an Entry or Text widget. +set ::tk::Priv(IMETextMark) [dict create] # Run the Ttk themed widget set initialization if {$::ttk::library ne ""} { diff --git a/library/ttk/aquaTheme.tcl b/library/ttk/aquaTheme.tcl index 15e13ce..8bba226 100644 --- a/library/ttk/aquaTheme.tcl +++ b/library/ttk/aquaTheme.tcl @@ -9,8 +9,8 @@ namespace eval ttk::theme::aqua { -font TkDefaultFont \ -background systemWindowBackgroundColor \ -foreground systemLabelColor \ - -selectbackground systemHighlight \ - -selectforeground systemLabelColor \ + -selectbackground systemSelectedTextBackgroundColor \ + -selectforeground systemSelectedTextColor \ -selectborderwidth 0 \ -insertwidth 1 @@ -38,7 +38,18 @@ namespace eval ttk::theme::aqua { # Entry ttk::style configure TEntry \ -foreground systemTextColor \ - -background systemTextBackgroundColor \ + -background systemTextBackgroundColor + ttk::style map TEntry \ + -foreground { + disabled systemDisabledControlTextColor + } \ + -selectforeground { + background systemTextColor + } \ + -selectbackground { + background systemTextBackgroundColor + } + # Workaround for #1100117: # Actually, on Aqua we probably shouldn't stipple images in @@ -59,20 +70,16 @@ namespace eval ttk::theme::aqua { # Combobox: ttk::style configure TCombobox \ -foreground systemTextColor \ - -background systemTransparent \ - -selectforeground systemSelectedTextColor \ - -selectbackground systemSelectedTextBackgroundColor + -background systemTransparent ttk::style map TCombobox \ -foreground { disabled systemDisabledControlTextColor } \ -selectforeground { - !active systemTextColor + background systemTextColor } \ -selectbackground { - !active systemTextBackgroundColor - !focus systemTextBackgroundColor - focus systemSelectedTextBackgroundColor + background systemTransparent } # Spinbox diff --git a/library/ttk/entry.tcl b/library/ttk/entry.tcl index 471df28..e2920a0 100644 --- a/library/ttk/entry.tcl +++ b/library/ttk/entry.tcl @@ -58,13 +58,6 @@ option add *TEntry.cursor [ttk::cursor text] widgetDefault # and I'll put it back. # -##Bindings to register with macOS Services API. -bind T.Entry <Map> { - if {[tk windowingsystem] eq "aqua"} { - ::tk::RegisterServiceWidget %W - } -} - ## Clipboard events: # bind TEntry <<Cut>> { ttk::entry::Cut %W } @@ -152,6 +145,25 @@ bind TEntry <Control-d> { ttk::entry::Delete %W } bind TEntry <Control-h> { ttk::entry::Backspace %W } bind TEntry <Control-k> { %W delete insert end } +# Bindings for IME text input. + +bind TEntry <<TkStartIMEMarkedText>> { + dict set ::tk::Priv(IMETextMark) "%W" [%W index insert] +} +bind TEntry <<TkEndIMEMarkedText>> { + if { [catch {dict get $::tk::Priv(IMETextMark) "%W"} mark] } { + bell + } else { + %W selection range $mark insert + } +} +bind TEntry <<TkClearIMEMarkedText>> { + %W delete [dict get $::tk::Priv(IMETextMark) "%W"] [%W index insert] +} +bind TEntry <<TkAccentBackspace>> { + ttk::entry::Backspace %W +} + ### Clipboard procedures. # diff --git a/library/ttk/treeview.tcl b/library/ttk/treeview.tcl index 39273ed..ebf1451 100644 --- a/library/ttk/treeview.tcl +++ b/library/ttk/treeview.tcl @@ -121,7 +121,17 @@ proc ttk::treeview::ActivateHeading {w heading} { if {$w != $State(activeWidget) || $heading != $State(activeHeading)} { if {[winfo exists $State(activeWidget)] && $State(activeHeading) != {}} { - $State(activeWidget) heading $State(activeHeading) state !active + # It may happen that $State(activeHeading) no longer corresponds + # to an existing display column. This happens for instance when + # changing -displaycolumns in a bound script when this change + # triggers a <Leave> event. A proc checking if the display column + # $State(activeHeading) is really still present or not could be + # written but it would need to check several special cases: + # a. -displaycolumns "#all" or being an explicit columns list + # b. column #0 display is not governed by the -displaycolumn + # list but by the value of the -show option + # --> Let's rather catch the following line. + catch {$State(activeWidget) heading $State(activeHeading) state !active} } if {$heading != {}} { $w heading $heading state active diff --git a/macosx/README b/macosx/README index c2dabae..4989ec7 100644 --- a/macosx/README +++ b/macosx/README @@ -49,8 +49,8 @@ brings up the Tk console window at startup. This is the case when double clicking Wish in the Finder (or using 'open Wish.app' from the Terminal). - Tcl extensions can be installed in any of: - $HOME/Library/Tcl /Library/Tcl /System/Library/Tcl - $HOME/Library/Frameworks /Library/Frameworks /System/Library/Frameworks + $HOME/Library/Tcl /Library/Tcl + $HOME/Library/Frameworks /Library/Frameworks (searched in that order). Given a potential package directory $pkg, Tcl on OSX checks for the file $pkg/Resources/Scripts/pkgIndex.tcl as well as the usual $pkg/pkgIndex.tcl. @@ -65,7 +65,7 @@ No nroff manpages are installed by default by the GNUmakefile. - The Tcl and Tk frameworks can be installed in any of the system's standard framework directories: - $HOME/Library/Frameworks /Library/Frameworks /System/Library/Frameworks + $HOME/Library/Frameworks /Library/Frameworks - ${prefix}/bin/wish8.x is a script that calls a copy of 'Wish' contained in Tk.framework/Resources diff --git a/macosx/tkMacOSXClipboard.c b/macosx/tkMacOSXClipboard.c index 452b32f..6717afa 100644 --- a/macosx/tkMacOSXClipboard.c +++ b/macosx/tkMacOSXClipboard.c @@ -130,6 +130,7 @@ TkSelGetSelection( && selection == dispPtr->clipboardAtom && (target == XA_STRING || target == dispPtr->utf8Atom)) { NSString *string = nil; + NSString *clean; NSPasteboard *pb = [NSPasteboard generalPasteboard]; NSString *type = [pb availableTypeFromArray:[NSArray arrayWithObject: NSStringPboardType]]; @@ -137,7 +138,27 @@ TkSelGetSelection( if (type) { string = [pb stringForType:type]; } - result = proc(clientData, interp, string ? [string UTF8String] : ""); + if (string) { + /* + * Replace all non-BMP characters by the replacement character 0xfffd. + * This is a workaround until Tcl supports TCL_UTF_MAX > 3. + */ + int i, j, len = [string length]; + CFRange all = CFRangeMake(0, len); + UniChar *buffer = ckalloc(len*sizeof(UniChar)); + CFStringGetCharacters((CFStringRef) string, all, buffer); + for (i = 0, j = 0 ; j < len ; i++, j++) { + if (CFStringIsSurrogateHighCharacter(buffer[j])) { + buffer[i] = 0xfffd; + j++; + } else { + buffer[i] = buffer[j]; + } + } + clean = (NSString *)CFStringCreateWithCharacters(NULL, buffer, i); + ckfree(buffer); + result = proc(clientData, interp, [clean UTF8String]); + } } else { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "%s selection doesn't exist or form \"%s\" not defined", diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index af0cc05..724f637 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -501,9 +501,12 @@ TkMacOSXGetNSImageWithTkImage( int width, int height) { - Pixmap pixmap = Tk_GetPixmap(display, None, width, height, 0); + Pixmap pixmap; NSImage *nsImage; - + if (width == 0 || height == 0) { + return nsImage = [[NSImage alloc] initWithSize:NSMakeSize(0,0)]; + } + pixmap = Tk_GetPixmap(display, None, width, height, 0); Tk_RedrawImage(image, 0, 0, width, height, pixmap, 0, 0); nsImage = CreateNSImageWithPixmap(pixmap, width, height); Tk_FreePixmap(display, pixmap); @@ -1611,16 +1614,36 @@ TkMacOSXSetupDrawingContext( * a view's drawRect or setFrame methods. The isDrawing attribute * tells us whether we are being called from one of those methods. * - * If the CGContext is not valid, or belongs to a different View, then - * we mark our view as needing display and return failure. It should - * get drawn in a later call to drawRect. + * If the CGContext is not valid then we mark our view as needing + * display in the bounding rectangle of the clipping region and + * return failure. That rectangle should get drawn in a later call + * to drawRect. + * + * As an exception to the above, if mouse buttons are pressed at the + * moment when we fail to obtain a valid context we schedule the entire + * view for a redraw rather than just the clipping region. The purpose + * of this is to make sure that scrollbars get updated correctly. */ - if (view != [NSView focusView]) { - [view setNeedsDisplay:YES]; + if (![NSApp isDrawing] || view != [NSView focusView]) { + NSRect bounds = [view bounds]; + NSRect dirtyNS = bounds; + if ([NSEvent pressedMouseButtons]) { + [view setNeedsDisplay:YES]; + } else { + CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, + .ty = dirtyNS.size.height}; + if (dc.clipRgn) { + CGRect dirtyCG = NSRectToCGRect(dirtyNS); + HIShapeGetBounds(dc.clipRgn, &dirtyCG); + dirtyNS = NSRectToCGRect(CGRectApplyAffineTransform(dirtyCG, t)); + } + [view setNeedsDisplayInRect:dirtyNS]; + } canDraw = false; goto end; } + dc.view = view; dc.context = GET_CGCONTEXT; dc.portBounds = NSRectToCGRect([view bounds]); diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c index 7659163..41da390 100644 --- a/macosx/tkMacOSXFont.c +++ b/macosx/tkMacOSXFont.c @@ -128,11 +128,11 @@ GetTkFontAttributesForNSFont( { NSFontTraitMask traits = [[NSFontManager sharedFontManager] traitsOfFont:nsFont]; - faPtr->family = Tk_GetUid([[nsFont familyName] UTF8String]); faPtr->size = [nsFont pointSize]; faPtr->weight = (traits & NSBoldFontMask ? TK_FW_BOLD : TK_FW_NORMAL); faPtr->slant = (traits & NSItalicFontMask ? TK_FS_ITALIC : TK_FS_ROMAN); + } /* @@ -176,6 +176,18 @@ FindNSFont( size = [defaultFont pointSize]; } nsFont = [fm fontWithFamily:family traits:traits weight:weight size:size]; + + /* + * A second bug in NSFontManager that Apple created for the Catalina OS + * causes requests as above to sometimes return fonts with additional + * traits that were not requested, even though fonts without those unwanted + * traits exist on the system. See bug [90d555e088]. As a workaround + * we ask the font manager to remove any unrequested traits. + */ + + if (nsFont) { + nsFont = [fm convertFont:nsFont toNotHaveTrait:~traits]; + } if (!nsFont) { NSArray *availableFamilies = [fm availableFontFamilies]; NSString *caseFamily = nil; @@ -394,10 +406,25 @@ TkpFontPkgInit( systemFont++; } TkInitFontAttributes(&fa); +#if 0 + + /* + * In macOS 10.15.1 Apple introduced a bug in NSFontManager which caused + * it to not recognize the familyName ".SF NSMono" which is the familyName + * of the default fixed pitch system fault on that system. See bug [855049e799]. + * As a workaround we call [NSFont userFixedPitchFontOfSize:11] instead. + * This returns a user font in the "Menlo" family. + */ + nsFont = (NSFont*) CTFontCreateUIFontForLanguage(fixedPitch, 11, NULL); +#else + nsFont = [NSFont userFixedPitchFontOfSize:11]; +#endif if (nsFont) { GetTkFontAttributesForNSFont(nsFont, &fa); +#if 0 CFRelease(nsFont); +#endif } else { fa.family = Tk_GetUid("Monaco"); fa.size = 11; diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index a787e13..3d15442 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -413,8 +413,7 @@ TkpInit( /* * Initialize the NSServices object here. Apple's docs say to do this * in applicationDidFinishLaunching, but the Tcl interpreter is not - * initialized until this function call. Only the main interpreter - * is allowed to provide services. + * initialized until this function call. */ TkMacOSXServices_Init(interp); @@ -435,9 +434,6 @@ TkpInit( TkMacOSXIconBitmapObjCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "::tk::mac::GetAppPath", TkMacOSXGetAppPathCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "::tk::mac::registerServiceWidget", - TkMacOSXRegisterServiceWidgetObjCmd, NULL, NULL); - return TCL_OK; } diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index b1c1689..e3aed98 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -7,7 +7,7 @@ * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net> * Copyright (c) 2012 Adrian Robert. - * Copyright 2015 Marc Culler. + * Copyright 2015-2019 Marc Culler. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -31,13 +31,12 @@ static NSWindow *keyboardGrabNSWindow = nil; * window. */ static NSModalSession modalSession = nil; static BOOL processingCompose = NO; -static BOOL finishedCompose = NO; +static Tk_Window composeWin = NULL; static int caret_x = 0, caret_y = 0, caret_height = 0; -static void setupXEvent(XEvent *xEvent, NSWindow *w, - unsigned int state); -static unsigned isFunctionKey(unsigned int code); +static unsigned short releaseCode; -unsigned short releaseCode; +static void setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state); +static unsigned isFunctionKey(unsigned int code); #pragma mark TKApplication(TKKeyEvent) @@ -137,9 +136,9 @@ unsigned short releaseCode; } /* - * Events are only received for the front Window on the Macintosh. So + * Key events are only received for the front Window on the Macintosh. So * to build an XEvent we look up the Tk window associated to the Front - * window. If a different window has a local grab we ignore the event. + * window. */ TkWindow *winPtr = TkMacOSXGetTkWindow(w); @@ -148,11 +147,18 @@ unsigned short releaseCode; if (tkwin) { TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr; - if (grabWinPtr - && grabWinPtr != winPtr - && !winPtr->dispPtr->grabFlags /* this means the grab is local. */ - && grabWinPtr->mainPtr == winPtr->mainPtr) { - return theEvent; + /* + * If a local grab is in effect, key events for windows in the + * grabber's application are redirected to the grabber. Key events + * for other applications are delivered normally. If a global + * grab is in effect all key events are redirected to the grabber. + */ + + if (grabWinPtr) { + if (winPtr->dispPtr->grabFlags || /* global grab */ + grabWinPtr->mainPtr == winPtr->mainPtr){ /* same appl. */ + tkwin = (Tk_Window) winPtr->dispPtr->focusPtr; + } } } else { tkwin = (Tk_Window) winPtr->dispPtr->focusPtr; @@ -202,18 +208,6 @@ unsigned short releaseCode; xEvent.xany.type = KeyPress; } - /* - * For command key, take input manager's word so things like - * dvorak / qwerty layout work. - */ - - if ((modifiers & NSCommandKeyMask) == NSCommandKeyMask - && (modifiers & NSAlternateKeyMask) != NSAlternateKeyMask - && len > 0 && !isFunctionKey(code)) { - // head off keycode-based translation in tkMacOSXKeyboard.c - xEvent.xkey.nbytes = [characters length]; //len - } - if ([characters length] > 0) { xEvent.xkey.keycode = (keyCode << 16) | (UInt16) [characters characterAtIndex:0]; @@ -235,7 +229,7 @@ unsigned short releaseCode; Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); savedModifiers = modifiers; return theEvent; - } /* if send straight to TK */ + } /* if this is a function key or has modifiers */ } /* if not processing compose */ if (type == NSKeyDown) { @@ -243,12 +237,29 @@ unsigned short releaseCode; TKLog(@"keyDown: %s compose sequence.\n", processingCompose == YES ? "Continue" : "Begin"); } - processingCompose = YES; - [nsEvArray addObject: theEvent]; - [[w contentView] interpretKeyEvents: nsEvArray]; - [nsEvArray removeObject: theEvent]; - } + /* + * Call the interpretKeyEvents method to interpret composition key + * strokes. When it detects a complete composition sequence it will + * call our implementation of insertText: replacementRange, which + * generates a key down XEvent with the appropriate character. In IME + * when multiple characters have the same composition sequence and the + * chosen character is not the default it may be necessary to hit the + * enter key multiple times before the character is accepted and + * rendered. We send enter key events until inputText has cleared + * the processingCompose flag. + */ + + processingCompose = YES; + while(processingCompose) { + [nsEvArray addObject: theEvent]; + [[w contentView] interpretKeyEvents: nsEvArray]; + [nsEvArray removeObject: theEvent]; + if ([theEvent keyCode] != 36) { + break; + } + } + } savedModifiers = modifiers; return theEvent; } @@ -265,25 +276,34 @@ unsigned short releaseCode; return self; } -/* <NSTextInput> implementation (called through interpretKeyEvents:]). */ +/* + * Implementation of the NSTextInputClient protocol. + */ -/* <NSTextInput>: called when done composing; - NOTE: also called when we delete over working text, followed immed. - by doCommandBySelector: deleteBackward: */ +/* [NSTextInputClient inputText: replacementRange:] is called by + * interpretKeyEvents when a composition sequence is complete. It is also + * called when we delete over working text. In that case the call is followed + * immediately by doCommandBySelector: deleteBackward: + */ - (void)insertText: (id)aString + replacementRange: (NSRange)repRange { - int i, len = [(NSString *) aString length]; + int i, len; XEvent xEvent; + NSString *str; + + str = ([aString isKindOfClass: [NSAttributedString class]]) ? + [aString string] : aString; + len = [str length]; if (NS_KEYLOG) { TKLog(@"insertText '%@'\tlen = %d", aString, len); } processingCompose = NO; - finishedCompose = YES; /* - * First, clear any working text. + * Clear any working text. */ if (privateWorkingText != nil) { @@ -291,32 +311,104 @@ unsigned short releaseCode; } /* - * Now insert the string as keystrokes. + * Insert the string as a sequence of keystrokes. */ setupXEvent(&xEvent, [self window], 0); xEvent.xany.type = KeyPress; - for (i =0; i<len; i++) { - xEvent.xkey.keycode = (UInt16) [aString characterAtIndex: i]; - [[aString substringWithRange: NSMakeRange(i,1)] - getCString: xEvent.xkey.trans_chars - maxLength: XMaxTransChars encoding: NSUTF8StringEncoding]; - xEvent.xkey.nbytes = strlen(xEvent.xkey.trans_chars); + /* + * Apple evidently sets location to 0 to signal that an accented letter has + * been selected from the accent menu. An unaccented letter has already + * been displayed and we need to erase it before displaying the accented + * letter. + */ + + if (repRange.location == 0) { + TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); + Tk_Window focusWin = (Tk_Window) winPtr->dispPtr->focusPtr; + TkSendVirtualEvent(focusWin, "TkAccentBackspace", NULL); + } + + /* + * NSString represents a non-BMP character as a string of length 2 where + * the first character is the high surrogate and the second character is + * the low surrogate. We could record this in the XEvent by setting the + * keycode to the unicode code point and setting the trans_chars to the + * 4-byte UTF-8 string. However, that will not help as long as TCL_UTF_MAX + * is set to 3. Until that changes, we just replace non-BMP characters by + * the "replacement character" U+FFFD. + */ + + for (i = 0; i < len; i++) { + UniChar nextChar = [str characterAtIndex: i]; + if (CFStringIsSurrogateHighCharacter(nextChar)) { +#if 0 + UniChar lowChar = [str characterAtIndex: ++i]; + xEvent.xkey.keycode = CFStringGetLongCharacterForSurrogatePair( + nextChar, lowChar); + xEvent.xkey.nbytes = TkUniCharToUtf(xEvent.xkey.keycode, + &xEvent.xkey.trans_chars); +#else + i++; + xEvent.xkey.keycode = 0xfffd; + strcpy(xEvent.xkey.trans_chars, "\xef\xbf\xbd"); + xEvent.xkey.nbytes = strlen(xEvent.xkey.trans_chars); +#endif + } else { + xEvent.xkey.keycode = (int) nextChar; + [[str substringWithRange: NSMakeRange(i,1)] + getCString: xEvent.xkey.trans_chars + maxLength: XMaxTransChars encoding: NSUTF8StringEncoding]; + xEvent.xkey.nbytes = strlen(xEvent.xkey.trans_chars); + } xEvent.xany.type = KeyPress; - releaseCode = (UInt16) [aString characterAtIndex: 0]; + releaseCode = (UInt16) nextChar; Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); } - releaseCode = (UInt16) [aString characterAtIndex: 0]; + releaseCode = (UInt16) [str characterAtIndex: 0]; +} + +/* + * This required method is allowed to return nil. + */ + +- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)theRange + actualRange:(NSRangePointer)thePointer +{ + return nil; } +/* + * This method is supposed to insert (or replace selected text with) the string + * argument. If the argument is an NSString, it should be displayed with a + * distinguishing appearance, e.g underlined. + */ -/* <NSTextInput>: inserts display of composing characters */ -- (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange +- (void)setMarkedText: (id)aString + selectedRange: (NSRange)selRange + replacementRange: (NSRange)repRange { - NSString *str = [aString respondsToSelector: @selector (string)] ? - [aString string] : aString; + TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); + Tk_Window focusWin = (Tk_Window) winPtr->dispPtr->focusPtr; + NSString *temp; + NSString *str; + + str = ([aString isKindOfClass: [NSAttributedString class]]) ? + [aString string] : aString; + + if (focusWin) { + + /* + * Remember the widget where the composition is happening, in case it + * gets defocussed during the composition. + */ + + composeWin = focusWin; + } else { + return; + } if (NS_KEYLOG) { TKLog(@"setMarkedText '%@' len =%lu range %lu from %lu", str, (unsigned long) [str length], (unsigned long) selRange.length, @@ -326,17 +418,23 @@ unsigned short releaseCode; if (privateWorkingText != nil) { [self deleteWorkingText]; } + if ([str length] == 0) { return; } - processingCompose = YES; - privateWorkingText = [str copy]; + /* + * Use our insertText method to display the marked text. + */ - //PENDING: insert workingText underlined + TkSendVirtualEvent(focusWin, "TkStartIMEMarkedText", NULL); + temp = [str copy]; + [self insertText: temp replacementRange:repRange]; + privateWorkingText = temp; + processingCompose = YES; + TkSendVirtualEvent(focusWin, "TkEndIMEMarkedText", NULL); } - - (BOOL)hasMarkedText { return privateWorkingText != nil; @@ -355,23 +453,35 @@ unsigned short releaseCode; return rng; } +- (void)cancelComposingText +{ + if (NS_KEYLOG) { + TKLog(@"cancelComposingText"); + } + [self deleteWorkingText]; + processingCompose = NO; +} - (void)unmarkText { if (NS_KEYLOG) { - TKLog(@"unmark (accept) text"); + TKLog(@"unmarkText"); } [self deleteWorkingText]; processingCompose = NO; } -/* used to position char selection windows, etc. */ +/* + * Called by the system to get a position for popup character selection windows + * such as a Character Palette, or a selection menu for IME. + */ + - (NSRect)firstRectForCharacterRange: (NSRange)theRange + actualRange: (NSRangePointer)thePointer { NSRect rect; NSPoint pt; - pt.x = caret_x; pt.y = caret_y; @@ -380,18 +490,16 @@ unsigned short releaseCode; pt.y -= caret_height; rect.origin = pt; - rect.size.width = caret_height; + rect.size.width = 0; rect.size.height = caret_height; return rect; } - - (NSInteger)conversationIdentifier { return (NSInteger) self; } - - (void)doCommandBySelector: (SEL)aSelector { if (NS_KEYLOG) { @@ -399,54 +507,41 @@ unsigned short releaseCode; } processingCompose = NO; if (aSelector == @selector (deleteBackward:)) { - /* - * Happens when user backspaces over an ongoing composition: - * throw a 'delete' into the event queue. - */ - - XEvent xEvent; - - setupXEvent(&xEvent, [self window], 0); - xEvent.xany.type = KeyPress; - xEvent.xkey.nbytes = 1; - xEvent.xkey.keycode = (0x33 << 16) | 0x7F; - xEvent.xkey.trans_chars[0] = 0x7F; - xEvent.xkey.trans_chars[1] = 0x0; - Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); + TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); + Tk_Window focusWin = (Tk_Window) winPtr->dispPtr->focusPtr; + TkSendVirtualEvent(focusWin, "TkAccentBackspace", NULL); } } - - (NSArray *)validAttributesForMarkedText { static NSArray *arr = nil; - if (arr == nil) { - arr = [NSArray new]; + arr = [[NSArray alloc] initWithObjects: + NSUnderlineStyleAttributeName, + NSUnderlineColorAttributeName, + nil]; + [arr retain]; } - /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */ return arr; } - - (NSRange)selectedRange { if (NS_KEYLOG) { TKLog(@"selectedRange request"); } - return NSMakeRange(NSNotFound, 0); + return NSMakeRange(0, 0); } - - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint { if (NS_KEYLOG) { TKLog(@"characterIndexForPoint request"); } - return 0; + return NSNotFound; } - - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange { static NSAttributedString *str = nil; @@ -458,34 +553,44 @@ unsigned short releaseCode; } return str; } -/* End <NSTextInput> impl. */ +/* End of NSTextInputClient implementation. */ @synthesize needsRedisplay = _needsRedisplay; @end @implementation TKContentView(TKKeyEvent) -/* delete display of composing characters [not in <NSTextInput>] */ + +/* + * Tell the widget to erase the displayed composing characters. This + * is not part of the NSTextInputClient protocol. + */ + - (void)deleteWorkingText { if (privateWorkingText == nil) { return; - } - if (NS_KEYLOG) { - TKLog(@"deleteWorkingText len = %lu\n", - (unsigned long)[privateWorkingText length]); - } - [privateWorkingText release]; - privateWorkingText = nil; - processingCompose = NO; + } else { - //PENDING: delete working text + if (NS_KEYLOG) { + TKLog(@"deleteWorkingText len = %lu\n", + (unsigned long)[privateWorkingText length]); + } + + [privateWorkingText release]; + privateWorkingText = nil; + processingCompose = NO; + if (composeWin) { + TkSendVirtualEvent(composeWin, "TkClearIMEMarkedText", NULL); + } + } } @end /* * Set up basic fields in xevent for keyboard input. */ + static void setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state) { @@ -498,17 +603,15 @@ setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state) memset(xEvent, 0, sizeof(XEvent)); xEvent->xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); - xEvent->xany.send_event = false; xEvent->xany.display = Tk_Display(tkwin); xEvent->xany.window = Tk_WindowId(tkwin); xEvent->xkey.root = XRootWindow(Tk_Display(tkwin), 0); - xEvent->xkey.subwindow = None; xEvent->xkey.time = TkpGetMS(); xEvent->xkey.state = state; xEvent->xkey.same_screen = true; - xEvent->xkey.trans_chars[0] = 0; - xEvent->xkey.nbytes = 0; + /* No need to initialize other fields implicitly here, + * because of the memset() above. */ } #pragma mark - diff --git a/macosx/tkMacOSXKeyboard.c b/macosx/tkMacOSXKeyboard.c index 3272657..e91dfe2 100644 --- a/macosx/tkMacOSXKeyboard.c +++ b/macosx/tkMacOSXKeyboard.c @@ -443,8 +443,11 @@ TkpGetString( * result. */ { (void) winPtr; /*unused*/ + int ch; + Tcl_DStringInit(dsPtr); - return Tcl_DStringAppend(dsPtr, eventPtr->xkey.trans_chars, -1); + return Tcl_DStringAppend(dsPtr, eventPtr->xkey.trans_chars, + TkUtfToUniChar(eventPtr->xkey.trans_chars, &ch)); } /* @@ -717,7 +720,7 @@ TkpSetKeycodeAndState( } if (keysym <= LATIN1_MAX) { - int done = Tcl_UniCharToUtf(keysym, eventPtr->xkey.trans_chars); + int done = TkUniCharToUtf(keysym, eventPtr->xkey.trans_chars); eventPtr->xkey.trans_chars[done] = 0; } else { @@ -803,7 +806,7 @@ TkpGetKeySym( /* If nbytes has been set, it's not a function key, but a regular key that has been translated in tkMacOSXKeyEvent.c; just use that. */ if (eventPtr->xkey.nbytes) { - return eventPtr->xkey.keycode & 0xFFFF; + return eventPtr->xkey.keycode; } /* diff --git a/macosx/tkMacOSXMenus.c b/macosx/tkMacOSXMenus.c index 99c1191..82bcda7 100644 --- a/macosx/tkMacOSXMenus.c +++ b/macosx/tkMacOSXMenus.c @@ -70,7 +70,7 @@ static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp); [NSMenuItem itemWithTitle: [NSString stringWithFormat:@"About %@", aboutName] action:@selector(orderFrontStandardAboutPanel:)] atIndex:0]; - _defaultFileMenuItems = + _defaultFileMenuItems = [[NSArray arrayWithObjects: [NSMenuItem itemWithTitle: [NSString stringWithFormat:@"Source%C", 0x2026] diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 89cdf1b..b18b4ef 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -130,7 +130,8 @@ enum { } /* - * Make sure tkwin is the toplevel which should receive the event. + * If we still don't have a window, try using the toplevel that + * manages the NSWindow. */ if (!tkwin) { @@ -138,10 +139,15 @@ enum { tkwin = (Tk_Window) winPtr; } if (!tkwin) { + + /* + * We can't find a window for this event. We have to ignore it. + */ + #ifdef TK_MAC_DEBUG_EVENTS TkMacOSXDbgMsg("tkwin == NULL"); #endif - return theEvent; /* Give up. No window for this event. */ + return theEvent; } /* @@ -174,13 +180,25 @@ enum { * coordinates. */ - local.x -= winPtr->wmInfoPtr->xInParent; - local.y -= winPtr->wmInfoPtr->yInParent; + if (Tk_IsEmbedded(winPtr)) { + TkWindow *contPtr = TkpGetOtherWindow(winPtr); + if (Tk_IsTopLevel(contPtr)) { + local.x -= contPtr->wmInfoPtr->xInParent; + local.y -= contPtr->wmInfoPtr->yInParent; + } else { + TkWindow *topPtr = TkMacOSXGetHostToplevel(winPtr)->winPtr; + local.x -= (topPtr->wmInfoPtr->xInParent + contPtr->changes.x); + local.y -= (topPtr->wmInfoPtr->yInParent + contPtr->changes.y); + } + } else { + local.x -= winPtr->wmInfoPtr->xInParent; + local.y -= winPtr->wmInfoPtr->yInParent; + } /* - * Find the containing Tk window, and convert local into the coordinates - * of the Tk window. (The converted local coordinates are only needed - * for scrollwheel events.) + * Use the toplevel coordinates to find the containing Tk window. Then + * convert local into the coordinates of that window. (The converted + * local coordinates are only needed for scrollwheel events.) */ int win_x, win_y; diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index cb80dd8..7aa6840 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -340,7 +340,12 @@ VISIBILITY_HIDDEN @end VISIBILITY_HIDDEN -@interface TKContentView : NSView <NSTextInput> +/* + * Subclass TKContentView from NSTextInputClient to enable composition and + * input from the Character Palette. + */ + +@interface TKContentView : NSView <NSTextInputClient> { @private NSString *privateWorkingText; @@ -354,13 +359,8 @@ VISIBILITY_HIDDEN @end @interface TKContentView(TKWindowEvent) -- (void) drawRect: (NSRect) rect; - (void) generateExposeEvents: (HIShapeRef) shape; - (void) tkToolbarButton: (id) sender; -- (BOOL) isOpaque; -- (BOOL) wantsDefaultClipping; -- (BOOL) acceptsFirstResponder; -- (void) keyDown: (NSEvent *) theEvent; @end @interface NSWindow(TKWm) diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index 66619c2..dff6cc9 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -214,12 +214,20 @@ static void drawMacScrollbar( CGContextStrokeLineSegments(context, outer, 2); /* - * Do not display the thumb unless scrolling is possible. + * Do not display the thumb unless scrolling is possible, in accordance + * with macOS behavior. + * + * Native scrollbars and Ttk scrollbars are always 15 pixels wide, but we + * allow Tk scrollbars to have any width, even if it looks bad. To prevent + * sporadic assertion errors when drawing skinny thumbs we must make sure + * the radius is at most half the width. */ if (scrollPtr->firstFraction > 0.0 || scrollPtr->lastFraction < 1.0) { CGRect thumbBounds = {thumbOrigin, thumbSize}; - path = CGPathCreateWithRoundedRect(thumbBounds, 4, 4, NULL); + int width = scrollPtr->vertical ? thumbSize.width : thumbSize.height; + int radius = width >= 8 ? 4 : width >> 1; + path = CGPathCreateWithRoundedRect(thumbBounds, radius, radius, NULL); CGContextBeginPath(context); CGContextAddPath(context, path); if (msPtr->info.trackInfo.scrollbar.pressState != 0) { diff --git a/macosx/tkMacOSXServices.c b/macosx/tkMacOSXServices.c index f1e5951..e92158f 100644 --- a/macosx/tkMacOSXServices.c +++ b/macosx/tkMacOSXServices.c @@ -4,20 +4,18 @@ * This file allows the integration of Tk and the Cocoa NSServices API. * * Copyright (c) 2010-2019 Kevin Walzer/WordTech Communications LLC. + * Copyright (c) 2019 Marc Culler. * Copyright (c) 2010 Adrian Robert. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -#include <CoreServices/CoreServices.h> #include <tkInt.h> #include <tkMacOSXInt.h> -static Tcl_Interp *ServicesInterp; - /* - * Event proc which calls the PerformService procedure + * Event proc which calls the PerformService procedure. */ static int @@ -25,22 +23,28 @@ ServicesEventProc( Tcl_Event *event, int flags) { - Tcl_GlobalEval(ServicesInterp, "::tk::mac::PerformService"); + TkMainInfo *info = TkGetMainInfoList(); + Tcl_GlobalEval(info->interp, "::tk::mac::PerformService"); return 1; } /* - * Class declarations for TkService class. + * The Wish application can send the current selection in the Tk clipboard + * to other applications which accept messages of type NSString. The TkService + * object provides this service via its provideService method. (The method + * must be specified in the application's Info.plist file for this to work.) */ -@interface TkService : NSView { +@interface TkService : NSObject { } + (void) initialize; -- (void)provideService:(NSPasteboard *)pboard userData:(NSString *)data error:(NSString **)error; -- (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType; -- (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard types:(NSArray *)types; +- (void) provideService:(NSPasteboard *)pboard + userData:(NSString *)data + error:(NSString **)error; +- (BOOL) writeSelectionToPasteboard:(NSPasteboard *)pboard + types:(NSArray *)types; @end @@ -57,32 +61,8 @@ ServicesEventProc( return; } - -- (id)validRequestorForSendType:(NSString *)sendType - returnType:(NSString *)returnType -{ - if ([sendType isEqualToString:@"NSStringPboardType"] || - [sendType isEqualToString:@"NSPasteboardTypeString"]) { - return self; - } - return [super validRequestorForSendType:sendType returnType:returnType]; -} - -/* - * Make sure the view accepts events. - */ - -- (BOOL)acceptsFirstResponder -{ - return YES; -} -- (BOOL)becomeFirstResponder -{ - return YES; -} - /* - * Get selected text, copy to pasteboard. + * Get the current Tk selection and copy it to the system pasteboard. */ - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard @@ -90,6 +70,7 @@ ServicesEventProc( { NSArray *typesDeclared = nil; NSString *pboardType = nil; + TkMainInfo *info = TkGetMainInfoList(); for (NSString *typeString in types) { if ([typeString isEqualToString:@"NSStringPboardType"] || @@ -102,9 +83,9 @@ ServicesEventProc( if (!typesDeclared) { return NO; } - Tcl_Eval(ServicesInterp, "selection get"); + Tcl_Eval(info->interp, "selection get"); - char *copystring = Tcl_GetString(Tcl_GetObjResult(ServicesInterp)); + char *copystring = Tcl_GetString(Tcl_GetObjResult(info->interp)); NSString *writestring = [NSString stringWithUTF8String:copystring]; [pboard declareTypes:typesDeclared owner:nil]; @@ -112,8 +93,8 @@ ServicesEventProc( } /* - * This is the method that actually calls the Tk service; this is the method - * that must be defined in info.plist. + * This is the method that actually calls the Tk service; it must be specified + * in Info.plist. */ - (void)provideService:(NSPasteboard *)pboard @@ -125,8 +106,8 @@ ServicesEventProc( Tcl_Event *event; /* - * Get string from private pasteboard, write to general pasteboard to make - * available to Tcl service. + * Get a string from the private pasteboard and copy it to the general + * pasteboard to make it available to other applications. */ for (NSString *typeString in types) { @@ -150,69 +131,9 @@ ServicesEventProc( @end /* - * Register a specific widget to access the Services menu. - */ - -int -TkMacOSXRegisterServiceWidgetObjCmd( - ClientData cd, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - /* - * Need proper number of args. - */ - - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "path?"); - return TCL_ERROR; - } - /* - * Get the object that holds this Tk Window... - */ - - Rect bounds; - NSRect frame; - Tk_Window path = Tk_NameToWindow(interp, - Tcl_GetString(objv[1]), Tk_MainWindow(interp)); - - if (path == NULL) { - return TCL_ERROR; - } - - Tk_MakeWindowExist(path); - Tk_MapWindow(path); - Drawable d = Tk_WindowId(path); - - /* - * Get NSView from Tk window and add subview. - */ - - TkService *serviceview = [[TkService alloc] init]; - NSView *view = TkMacOSXGetRootControl(d); - - if ([serviceview superview] != view) { - [view addSubview:serviceview]; - } - TkMacOSXWinBounds((TkWindow*)path, &bounds); - - /* - * Hack to make sure subview is set to take up entire geometry of window. - */ - - frame = NSMakeRect(bounds.left, bounds.top, 100000, 100000); - frame.origin.y = 0; - if (!NSEqualRects(frame, [serviceview frame])) { - [serviceview setFrame:frame]; - } - [serviceview release]; - return TCL_OK; -} - -/* - * Initalize the package in the Tcl interpreter, create Tcl commands. + * Instantiate a TkService object and register it with the NSApplication. + * This is called exactly one time from TkpInit. */ int @@ -220,12 +141,10 @@ TkMacOSXServices_Init( Tcl_Interp *interp) { /* - * Initialize instance of TclServices to provide service functionality. + * Initialize an instance of TkService and register it with the NSApp. */ TkService *service = [[TkService alloc] init]; - - ServicesInterp = interp; [NSApp setServicesProvider:service]; return TCL_OK; } diff --git a/macosx/tkMacOSXTest.c b/macosx/tkMacOSXTest.c index 09736e6..c353efe 100644 --- a/macosx/tkMacOSXTest.c +++ b/macosx/tkMacOSXTest.c @@ -161,7 +161,7 @@ PressButtonObjCmd( if (screens && [screens count]) { ScreenHeight = [[screens objectAtIndex:0] frame].size.height; } - + if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "x y"); return TCL_ERROR; @@ -186,34 +186,34 @@ PressButtonObjCmd( loc.y = ScreenHeight - y; wNum = 0; CGWarpMouseCursorPosition(pt); - motion = [NSEvent mouseEventWithType:NSMouseMoved + motion = [NSEvent mouseEventWithType:NSMouseMoved location:loc - modifierFlags:0 - timestamp:GetCurrentEventTime() + modifierFlags:0 + timestamp:GetCurrentEventTime() windowNumber:wNum - context:nil + context:nil eventNumber:0 - clickCount:1 + clickCount:1 pressure:0.0]; [NSApp postEvent:motion atStart:NO]; - press = [NSEvent mouseEventWithType:NSLeftMouseDown + press = [NSEvent mouseEventWithType:NSLeftMouseDown location:loc - modifierFlags:0 - timestamp:GetCurrentEventTime() + modifierFlags:0 + timestamp:GetCurrentEventTime() windowNumber:wNum - context:nil + context:nil eventNumber:1 - clickCount:1 + clickCount:1 pressure:0.0]; [NSApp postEvent:press atStart:NO]; release = [NSEvent mouseEventWithType:NSLeftMouseUp location:loc - modifierFlags:0 - timestamp:GetCurrentEventTime() + modifierFlags:0 + timestamp:GetCurrentEventTime() windowNumber:wNum - context:nil + context:nil eventNumber:2 - clickCount:1 + clickCount:1 pressure:0.0]; [NSApp postEvent:release atStart:NO]; return TCL_OK; diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 2666939..fe6981d 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -1186,6 +1186,11 @@ RedisplayView( return YES; } +/* + * This keyDown method does nothing, which is a huge improvement over the + * default keyDown method which beeps every time a key is pressed. + */ + - (void) keyDown: (NSEvent *) theEvent { #ifdef TK_MAC_DEBUG_EVENTS @@ -1193,6 +1198,23 @@ RedisplayView( #endif } +/* + * When the services menu is opened this is called for each Responder in + * the Responder chain until a service provider is found. The TkContentView + * should be the first (and generally only) Responder in the chain. We + * return the TkServices object that was created in TkpInit. + */ + +- (id)validRequestorForSendType:(NSString *)sendType + returnType:(NSString *)returnType +{ + if ([sendType isEqualToString:@"NSStringPboardType"] || + [sendType isEqualToString:@"NSPasteboardTypeString"]) { + return [NSApp servicesProvider]; + } + return [super validRequestorForSendType:sendType returnType:returnType]; +} + @end /* diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 70e9cd9..4e53282 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -2518,6 +2518,7 @@ WmIconphotoCmd( { Tk_Image tk_icon; int width, height, isDefault = 0; + NSImage *newIcon = NULL; if (objc < 4) { Tcl_WrongNumArgs(interp, 2, objv, @@ -2563,12 +2564,16 @@ WmIconphotoCmd( return TCL_ERROR; } - NSImage *newIcon; Tk_SizeOfImage(tk_icon, &width, &height); - newIcon = TkMacOSXGetNSImageWithTkImage(winPtr->display, tk_icon, - width, height); + if (width != 0 && height != 0) { + newIcon = TkMacOSXGetNSImageWithTkImage(winPtr->display, tk_icon, + width, height); + } Tk_FreeImage(tk_icon); if (newIcon == NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "failed to create an iconphoto with image \"%s\"", icon)); + Tcl_SetErrorCode(interp, "TK", "WM", "ICONPHOTO", "IMAGE", NULL); return TCL_ERROR; } [NSApp setApplicationIconImage: newIcon]; @@ -3311,18 +3316,18 @@ WmStackorderCmd( if (objc == 3) { windows = TkWmStackorderToplevel(winPtr); - if (windows == NULL) { - Tcl_Panic("TkWmStackorderToplevel failed"); - } - - resultObj = Tcl_NewObj(); - for (windowPtr = windows; *windowPtr ; windowPtr++) { - Tcl_ListObjAppendElement(NULL, resultObj, + if (windows != NULL) { + resultObj = Tcl_NewObj(); + for (windowPtr = windows; *windowPtr ; windowPtr++) { + Tcl_ListObjAppendElement(NULL, resultObj, TkNewWindowObj((Tk_Window) *windowPtr)); + } + Tcl_SetObjResult(interp, resultObj); + ckfree(windows); + return TCL_OK; + } else { + return TCL_ERROR; } - Tcl_SetObjResult(interp, resultObj); - ckfree(windows); - return TCL_OK; } else { TkWindow *winPtr2; int index1 = -1, index2 = -1, result; @@ -6623,7 +6628,7 @@ WmStackorderToplevelWrapperMap( Tcl_HashEntry *hPtr; int newEntry; - if (Tk_IsMapped(winPtr) && Tk_IsTopLevel(winPtr) + if (Tk_IsMapped(winPtr) && Tk_IsTopLevel(winPtr) && !Tk_IsEmbedded(winPtr) && (winPtr->display == display)) { hPtr = Tcl_CreateHashEntry(table, (char*) TkMacOSXDrawableWindow(winPtr->window), &newEntry); @@ -6644,8 +6649,8 @@ WmStackorderToplevelWrapperMap( * This procedure returns the stack order of toplevel windows. * * Results: - * An array of pointers to tk window objects in stacking order or else - * NULL if there was an error. + * A NULL terminated array of pointers to tk window objects in stacking + * order or else NULL if there was an error. * * Side effects: * None. @@ -6660,57 +6665,24 @@ TkWmStackorderToplevel( TkWindow *childWinPtr, **windows, **windowPtr; Tcl_HashTable table; Tcl_HashEntry *hPtr; - Tcl_HashSearch search; - - /* - * Map mac windows to a TkWindow of the wrapped toplevel. - */ - - Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS); - WmStackorderToplevelWrapperMap(parentPtr, parentPtr->display, &table); - - windows = ckalloc((table.numEntries+1) * sizeof(TkWindow *)); - - /* - * Special cases: If zero or one toplevels were mapped there is no need to - * enumerate Windows. - */ - - switch (table.numEntries) { - case 0: - windows[0] = NULL; - goto done; - case 1: - hPtr = Tcl_FirstHashEntry(&table, &search); - windows[0] = Tcl_GetHashValue(hPtr); - windows[1] = NULL; - goto done; - } - NSArray *macWindows = [NSApp orderedWindows]; + NSArray* backToFront = [[macWindows reverseObjectEnumerator] allObjects]; NSInteger windowCount = [macWindows count]; - if (!windowCount) { - ckfree(windows); - windows = NULL; - } else { - windowPtr = windows + table.numEntries; - *windowPtr-- = NULL; - for (NSWindow *w in macWindows) { + windows = windowPtr = ckalloc((windowCount + 1) * sizeof(TkWindow *)); + if (windows != NULL) { + Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS); + WmStackorderToplevelWrapperMap(parentPtr, parentPtr->display, &table); + for (NSWindow *w in backToFront) { hPtr = Tcl_FindHashEntry(&table, (char*) w); if (hPtr != NULL) { childWinPtr = Tcl_GetHashValue(hPtr); - *windowPtr-- = childWinPtr; + *windowPtr++ = childWinPtr; } } - if (windowPtr != windows-1) { - Tcl_Panic("num matched toplevel windows does not equal num " - "children"); - } + *windowPtr = NULL; + Tcl_DeleteHashTable(&table); } - - done: - Tcl_DeleteHashTable(&table); return windows; } diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c index 3d88ef7..52534ce 100644 --- a/macosx/ttkMacOSXTheme.c +++ b/macosx/ttkMacOSXTheme.c @@ -1409,8 +1409,10 @@ static void ButtonElementDraw( } else if (info.kind == kThemePushButton && (state & TTK_STATE_PRESSED)) { bounds.size.height += 2; - GradientFillRoundedRectangle(dc.context, bounds, 4, - pressedPushButtonGradient, 2); + if ([NSApp macMinorVersion] > 8) { + GradientFillRoundedRectangle(dc.context, bounds, 4, + pressedPushButtonGradient, 2); + } } else { /* @@ -1859,18 +1861,17 @@ static void ComboboxElementDraw( BEGIN_DRAWING(d) bounds.origin.y += 1; if (TkMacOSXInDarkMode(tkwin)) { - bounds.size.height += 1; + bounds.size.height += 1; DrawDarkButton(bounds, info.kind, state, dc.context); - } else if ([NSApp macMinorVersion] > 8) { - if ((state & TTK_STATE_BACKGROUND) && - !(state & TTK_STATE_DISABLED)) { + } else if ([NSApp macMinorVersion] > 8) { + if ((state & TTK_STATE_BACKGROUND) && + !(state & TTK_STATE_DISABLED)) { NSColor *background = [NSColor textBackgroundColor]; CGRect innerBounds = CGRectInset(bounds, 1, 2); SolidFillRoundedRectangle(dc.context, innerBounds, 4, background); } - ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, - NULL); } + ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL); END_DRAWING } @@ -2095,7 +2096,7 @@ static void TrackElementDraw( Tcl_GetDoubleFromObj(NULL, elem->fromObj, &from); Tcl_GetDoubleFromObj(NULL, elem->toObj, &to); Tcl_GetDoubleFromObj(NULL, elem->valueObj, &value); - factor = RangeToFactor(to - from); + factor = RangeToFactor(to); HIThemeTrackDrawInfo info = { .version = 0, diff --git a/tests/bind.test b/tests/bind.test index 1b01685..c657dd5 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6743,11 +6743,13 @@ test bind-34.1 {-warp works relatively to a window} -setup { update event generate .top <Motion> -x 20 -y 20 -warp 1 update idletasks ; # DoWarp is an idle callback + after 50 ; # Win specific - wait for SendInput to be executed set pointerPos1 [winfo pointerxy .t] wm geometry .top +600+600 update event generate .top <Motion> -x 20 -y 20 -warp 1 update idletasks ; # DoWarp is an idle callback + after 50 ; # Win specific - wait for SendInput to be executed set pointerPos2 [winfo pointerxy .t] # from the first warped position to the second one, the mouse # pointer should have moved the same amount as the window moved @@ -6766,12 +6768,33 @@ test bind-34.2 {-warp works relatively to the screen} -setup { # Contrary to bind-34.1, we're directly checking screen coordinates event generate {} <Motion> -x 20 -y 20 -warp 1 update idletasks ; # DoWarp is an idle callback + after 50 ; # Win specific - wait for SendInput to be executed set res [winfo pointerxy .] event generate {} <Motion> -x 200 -y 200 -warp 1 update idletasks ; # DoWarp is an idle callback + after 50 ; # Win specific - wait for SendInput to be executed lappend res {*}[winfo pointerxy .] } -cleanup { } -result {20 20 200 200} +test bind-34.3 {-warp works with null or negative coordinates} -setup { +} -body { + event generate {} <Motion> -x 0 -y 0 -warp 1 + update idletasks ; # DoWarp is an idle callback + after 50 ; # Win specific - wait for SendInput to be executed + set res [winfo pointerxy .] + event generate {} <Motion> -x -1 -y -1 -warp 1 + update idletasks ; # DoWarp is an idle callback + after 50 ; # Win specific - wait for SendInput to be executed + foreach dim [winfo pointerxy .] { + if {$dim <= 0} { + lappend res ok + } else { + lappend res $dim + } + } + set res +} -cleanup { +} -result {0 0 ok ok} # cleanup cleanupTests diff --git a/tests/canvImg.test b/tests/canvImg.test index c0b91f8..bd9edb5 100644 --- a/tests/canvImg.test +++ b/tests/canvImg.test @@ -803,6 +803,7 @@ test canvImg-11.3 {ImageChangedProc procedure} -constraints { foo2 changed 0 0 0 0 80 60 .c create image 50 100 -image foo -tags image -anchor nw .c create image 70 110 -image foo2 -anchor nw + update set z {} set timer [after 500 {lappend z "timed out"}] image create test foo -variable x diff --git a/tests/ttk/notebook.test b/tests/ttk/notebook.test index 3a2a6ff..ac63088 100644 --- a/tests/ttk/notebook.test +++ b/tests/ttk/notebook.test @@ -69,7 +69,7 @@ test notebook-2.5 "tab - get all options" -body { .nb tab .nb.foo } -result [list \ -padding 0 -sticky nsew \ - -state normal -text "Changed Foo" -image "" -compound none -underline -1] + -state normal -text "Changed Foo" -image "" -compound {} -underline -1] test notebook-4.1 "Test .nb index end" -body { .nb index end diff --git a/tests/ttk/treeview.test b/tests/ttk/treeview.test index 9c24998..65ae55e 100644 --- a/tests/ttk/treeview.test +++ b/tests/ttk/treeview.test @@ -692,7 +692,7 @@ test treeview-368fa4561e "indicators cannot be clicked on leafs" -setup { destroy .tv } -result {0 0 0} -test treeview-ce470f20fd-1 "dragging further than the right edge of the treeview is forbidden" -setup { +test treeview-ce470f20fd-1 "dragging further than the right edge of the treeview is allowed" -setup { pack [ttk::treeview .tv] .tv heading #0 -text "Drag my right edge -->" update @@ -702,7 +702,7 @@ test treeview-ce470f20fd-1 "dragging further than the right edge of the treeview lappend res [expr {[.tv column #0 -width] > $res}] } -cleanup { destroy .tv -} -result {200 0} +} -result {200 1} proc nostretch {tv} { foreach col [$tv cget -columns] { diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index 7d26fbf..2ebf9c2 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -85,6 +85,8 @@ proc colorsFree {w {red 31} {green 245} {blue 192}} { && ([lindex $vals 2]/256 == $blue) } +testConstraint pressbutton [llength [info commands pressbutton]] + test unixEmbed-1.1 {TkpUseWindow procedure, bad window identifier} -constraints { unix } -setup { @@ -1263,6 +1265,56 @@ test unixEmbed-10.2 {geometry propagation in tkUnixWm.c/UpdateGeometryInfo} -con deleteWindows } -result {70x300+0+0} +test unixEmbed-11.1 {focus -force works for embedded toplevels} -constraints { + unix +} -setup { + deleteWindows +} -body { + toplevel .t + pack [frame .t.f -container 1 -width 200 -height 200] -fill both + update idletasks + toplevel .embed -use [winfo id .t.f] -bg green + update idletasks + focus -force .t + focus -force .embed + focus +} -cleanup { + deleteWindows +} -result .embed +test unixEmbed-11.2 {mouse coordinates in embedded toplevels} -constraints { + unix pressbutton +} -setup { + deleteWindows +} -body { + toplevel .main + set result {} + pack [button .main.b -text "Main Button" \ + -command {lappend result ".main.b"}] -padx 30 -pady 30 + pack [frame .main.f -container 1 -width 200 -height 200] -fill both + update idletasks + toplevel .embed -use [winfo id .main.f] -bg green + pack [button .embed.b -text "Emb Button" \ + -command {lappend result ".embed.b"}] -padx 30 -pady 30 + wm geometry .main 200x400+100+100 + update idletasks + focus -force .main + set x [expr {[winfo x .main ] + [winfo x .main.b] + 40}] + set y [expr {[winfo y .main ] + [winfo y .main.b] + 38}] + lappend result [winfo containing $x $y] + after 200 + pressbutton $x $y + update + set y [expr {$y + 80}] + lappend result [winfo containing $x $y] + after 200 + pressbutton $x $y + update + set result +} -cleanup { + deleteWindows +} -result {.main.b .main.b .embed.b .embed.b} + + # cleanup deleteWindows cleanupbg diff --git a/tests/wm.test b/tests/wm.test index df8d325..2978c1b 100644 --- a/tests/wm.test +++ b/tests/wm.test @@ -873,6 +873,12 @@ test wm-iconphoto-1.4 {usage} -returnCodes error -body { # we currently have no return info wm iconphoto . -default } -result {wrong # args: should be "wm iconphoto window ?-default? image1 ?image2 ...?"} +test wm-iconphoto-1.5.1 {usage} -constraints aquaOrWin32 -returnCodes error -body { + wm iconphoto . -default [image create photo -file {}] +} -match {glob} -result {failed to create an iconphoto with image *} +test wm-iconphoto-1.5.2 {usage} -constraints x11 -body { + wm iconphoto . -default [image create photo -file {}] +} -result {} # All other iconphoto tests are platform specific @@ -1553,8 +1559,8 @@ test wm-stackorder-5.3 {An overrideredirect window\ destroy .t } -result 1 -test wm-stackorder-6.1 {An embedded toplevel does not\ - appear in the stacking order on unix or win} -constraints notAqua -body { +test wm-stackorder-6.1 {An embedded toplevel does not appear in the \ + stacking order} -body { toplevel .real -container 1 toplevel .embd -bg blue -use [winfo id .real] update @@ -1562,16 +1568,6 @@ test wm-stackorder-6.1 {An embedded toplevel does not\ } -cleanup { deleteWindows } -result {. .real} -test wm-stackorder-6.1.1 {An embedded toplevel does\ - appear in the stacking order on macOS} -constraints aqua -body { - toplevel .real -container 1 - toplevel .embd -bg blue -use [winfo id .real] - update - wm stackorder . -} -cleanup { - deleteWindows -} -result {. .embd} - stdWindow diff --git a/unix/configure b/unix/configure index 5c46bac..70a5bef 100755 --- a/unix/configure +++ b/unix/configure @@ -2360,7 +2360,6 @@ $as_echo "$as_me: WARNING: --with-tcl argument should refer to directory contain for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ - `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" @@ -2377,6 +2376,7 @@ $as_echo "$as_me: WARNING: --with-tcl argument should refer to directory contain `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ + `ls -d /usr/lib/tcl8.7 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/local/lib/tcl8.7 2>/dev/null` \ @@ -4169,6 +4169,9 @@ $as_echo "$as_me: WARNING: can't find uname command" >&2;} if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi + if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then + tcl_cv_sys_version=NetBSD-Debian + fi fi fi @@ -5882,6 +5885,15 @@ $as_echo "#define HAVE_CAST_TO_UNION 1" >>confdefs.h fi + ac_fn_c_check_header_mongrel "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" "$ac_includes_default" +if test "x$ac_cv_header_stdbool_h" = xyes; then : + +$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h + +fi + + + # FIXME: This subst was left in only because the TCL_DL_LIBS # entry in tclConfig.sh uses it. It is not clear why someone # would use TCL_DL_LIBS instead of TCL_LIBS. @@ -7650,8 +7662,8 @@ $as_echo "$enable_xft" >&6; } XFT_LIBS=`xft-config --libs 2>/dev/null` || found_xft="no" if test "$found_xft" = "no" ; then found_xft=yes - XFT_CFLAGS=`pkg-config --cflags xft 2>/dev/null` || found_xft="no" - XFT_LIBS=`pkg-config --libs xft 2>/dev/null` || found_xft="no" + XFT_CFLAGS=`pkg-config --cflags xft fontconfig 2>/dev/null` || found_xft="no" + XFT_LIBS=`pkg-config --libs xft fontconfig 2>/dev/null` || found_xft="no" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $found_xft" >&5 $as_echo "$found_xft" >&6; } @@ -8141,7 +8153,7 @@ if test "${SHARED_BUILD}" = "1" -a "${SHLIB_SUFFIX}" != ""; then TCL_STUB_FLAGS="-DUSE_TCL_STUBS" fi -TK_LIBRARY='$(prefix)/lib/tk$(VERSION)' +test -z "$TK_LIBRARY" && TK_LIBRARY='$(prefix)/lib/tk$(VERSION)' PRIVATE_INCLUDE_DIR='$(includedir)' HTML_DIR='$(DISTDIR)/html' TK_PKG_DIR='tk$(VERSION)' diff --git a/unix/configure.ac b/unix/configure.ac index c485652..0853809 100644 --- a/unix/configure.ac +++ b/unix/configure.ac @@ -456,8 +456,8 @@ if test $tk_aqua = no; then XFT_LIBS=`xft-config --libs 2>/dev/null` || found_xft="no" if test "$found_xft" = "no" ; then found_xft=yes - XFT_CFLAGS=`pkg-config --cflags xft 2>/dev/null` || found_xft="no" - XFT_LIBS=`pkg-config --libs xft 2>/dev/null` || found_xft="no" + XFT_CFLAGS=`pkg-config --cflags xft fontconfig 2>/dev/null` || found_xft="no" + XFT_LIBS=`pkg-config --libs xft fontconfig 2>/dev/null` || found_xft="no" fi AC_MSG_RESULT([$found_xft]) dnl make sure that compiling against Xft header file doesn't bomb @@ -649,7 +649,7 @@ if test "${SHARED_BUILD}" = "1" -a "${SHLIB_SUFFIX}" != ""; then TCL_STUB_FLAGS="-DUSE_TCL_STUBS" fi -TK_LIBRARY='$(prefix)/lib/tk$(VERSION)' +test -z "$TK_LIBRARY" && TK_LIBRARY='$(prefix)/lib/tk$(VERSION)' PRIVATE_INCLUDE_DIR='$(includedir)' HTML_DIR='$(DISTDIR)/html' TK_PKG_DIR='tk$(VERSION)' diff --git a/unix/installManPage b/unix/installManPage index 4d615bf..935bbcd 100755 --- a/unix/installManPage +++ b/unix/installManPage @@ -92,12 +92,20 @@ case $ManPage in exit 2 ;; esac +Name=`basename $ManPage .$Section` SrcDir=`dirname $ManPage` ######################################################################## ### Process Page to Create Target Pages ### +Specials="FindPhoto FontId MeasureChar" +for n in $Specials; do + if [ "$Name" = "$n" ] ; then + Names="$n $Names" + fi +done + First="" for Target in $Names; do Target=$Target.$Section$Suffix @@ -106,7 +114,7 @@ for Target in $Names; do First=$Target sed -e "/man\.macros/r $SrcDir/man.macros" -e "/man\.macros/d" \ $ManPage > $Dir/$First - chmod 444 $Dir/$First + chmod 644 $Dir/$First $Gzip $Dir/$First else ln $SymOrLoc$First$Gz $Dir/$Target$Gz diff --git a/unix/tcl.m4 b/unix/tcl.m4 index 93efb49..d617259 100644 --- a/unix/tcl.m4 +++ b/unix/tcl.m4 @@ -77,7 +77,6 @@ AC_DEFUN([SC_PATH_TCLCONFIG], [ for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ - `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" @@ -94,6 +93,7 @@ AC_DEFUN([SC_PATH_TCLCONFIG], [ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ + `ls -d /usr/lib/tcl8.7 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/local/lib/tcl8.7 2>/dev/null` \ @@ -210,7 +210,6 @@ AC_DEFUN([SC_PATH_TKCONFIG], [ for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ - `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" @@ -227,6 +226,7 @@ AC_DEFUN([SC_PATH_TKCONFIG], [ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ + `ls -d /usr/lib/tk8.7 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/local/lib/tk8.7 2>/dev/null` \ @@ -814,6 +814,9 @@ AC_DEFUN([SC_CONFIG_SYSTEM], [ if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi + if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then + tcl_cv_sys_version=NetBSD-Debian + fi fi fi ]) @@ -1870,6 +1873,8 @@ dnl # preprocessing tests use only CPPFLAGS. [Defined when compiler supports casting to union type.]) fi + AC_CHECK_HEADER(stdbool.h, [AC_DEFINE(HAVE_STDBOOL_H, 1, [Do we have <stdbool.h>?])],) + # FIXME: This subst was left in only because the TCL_DL_LIBS # entry in tclConfig.sh uses it. It is not clear why someone # would use TCL_DL_LIBS instead of TCL_LIBS. @@ -1930,7 +1935,7 @@ dnl # preprocessing tests use only CPPFLAGS. # NO_SYS_WAIT_H # NO_DLFCN_H # HAVE_SYS_PARAM_H -# +# HAVE_STDBOOL_H # HAVE_STRING_H ? # #-------------------------------------------------------------------- diff --git a/unix/tkUnixFont.c b/unix/tkUnixFont.c index 3c1ce65..9a8d1f7 100644 --- a/unix/tkUnixFont.c +++ b/unix/tkUnixFont.c @@ -63,7 +63,7 @@ typedef struct FontFamily { /* Two-level sparse table used to determine * quickly if the specified character exists. * As characters are encountered, more pages - * in this table are dynamically alloced. The + * in this table are dynamically allocated. The * contents of each page is a bitmask * consisting of FONTMAP_BITSPERPAGE bits, * representing whether this font can be used diff --git a/unix/tkUnixKey.c b/unix/tkUnixKey.c index cbba7bb..fa93edc 100644 --- a/unix/tkUnixKey.c +++ b/unix/tkUnixKey.c @@ -208,7 +208,7 @@ TkpGetString( Tcl_DStringValue(&buf)[len] = '\0'; if (len == 1) { - len = Tcl_UniCharToUtf((unsigned char) Tcl_DStringValue(&buf)[0], + len = TkUniCharToUtf((unsigned char) Tcl_DStringValue(&buf)[0], Tcl_DStringValue(dsPtr)); Tcl_DStringSetLength(dsPtr, len); } else { diff --git a/unix/tkUnixRFont.c b/unix/tkUnixRFont.c index bca193a..e69dab0 100644 --- a/unix/tkUnixRFont.c +++ b/unix/tkUnixRFont.c @@ -74,6 +74,15 @@ static Tcl_ThreadDataKey dataKey; *------------------------------------------------------------------------- */ + +static int utf8ToUcs4(const char *source, FcChar32 *c, int numBytes) +{ + if (numBytes >= 6) { + return TkUtfToUniChar(source, (int *)c); + } + return FcUtf8ToUcs4((const FcChar8 *)source, c, numBytes); +} + void TkpFontPkgInit( TkMainInfo *mainPtr) /* The application being created. */ @@ -897,7 +906,7 @@ Tk_DrawChars( XftFont *ftFont; FcChar32 c; - clen = FcUtf8ToUcs4((FcChar8 *) source, &c, numBytes); + clen = utf8ToUcs4(source, &c, numBytes); if (clen <= 0) { /* * This should not happen, but it can. @@ -1037,7 +1046,7 @@ TkDrawAngledChars( XftFont *ftFont; FcChar32 c; - clen = FcUtf8ToUcs4((FcChar8 *) source, &c, numBytes); + clen = utf8ToUcs4(source, &c, numBytes); if (clen <= 0) { /* * This should not happen, but it can. @@ -1141,7 +1150,7 @@ TkDrawAngledChars( XftFont *ftFont, *ft0Font; FcChar32 c; - clen = FcUtf8ToUcs4((FcChar8 *) source, &c, numBytes); + clen = utf8ToUcs4(source, &c, numBytes); if (clen <= 0) { /* * This should not happen, but it can. diff --git a/unix/tkUnixWm.c b/unix/tkUnixWm.c index f9cf4e7..490a1ea 100644 --- a/unix/tkUnixWm.c +++ b/unix/tkUnixWm.c @@ -2444,6 +2444,10 @@ WmIconphotoCmd( photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i])); if (photo == NULL) { ckfree((char *) iconPropertyData); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "failed to create an iconphoto with image \"%s\"", + Tcl_GetString(objv[i]))); + Tcl_SetErrorCode(interp, "TK", "WM", "ICONPHOTO", "IMAGE", NULL); return TCL_ERROR; } Tk_PhotoGetSize(photo, &width, &height); @@ -3265,6 +3269,8 @@ WmStackorderCmd( ckfree(windows); Tcl_SetObjResult(interp, resultObj); return TCL_OK; + } else { + return TCL_ERROR; } } else { Tk_Window relWin; @@ -6428,6 +6434,9 @@ TkWmStackorderToplevel( TkWmStackorderToplevelWrapperMap(parentPtr, parentPtr->display, &table); window_ptr = windows = ckalloc((table.numEntries+1) * sizeof(TkWindow *)); + if (windows == NULL) { + return NULL; + } /* * Special cases: If zero or one toplevels were mapped there is no need to diff --git a/win/configure b/win/configure index 7e63a81..3bb8570 100755 --- a/win/configure +++ b/win/configure @@ -4664,6 +4664,15 @@ $as_echo "#define HAVE_WINNT_IGNORE_VOID 1" >>confdefs.h fi + ac_fn_c_check_header_mongrel "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" "$ac_includes_default" +if test "x$ac_cv_header_stdbool_h" = xyes; then : + +$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h + +fi + + + # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. diff --git a/win/makefile.vc b/win/makefile.vc index 99aa6c1..311be18 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -316,7 +316,7 @@ PRJ_INCLUDES = -I"$(BITMAPDIR)" -I"$(XLIBDIR)" CONFIG_DEFS =/DSTDC_HEADERS=1 /DHAVE_SYS_TYPES_H=1 /DHAVE_SYS_STAT_H=1 \
/DHAVE_STRING_H=1 /DHAVE_MEMORY_H=1 \
- /DHAVE_STRINGS_H=1 /DHAVE_INTTYPES_H=1 /DHAVE_STDINT_H=1 \
+ /DHAVE_STRINGS_H=1 /DHAVE_INTTYPES_H=1 \
/DSUPPORT_CONFIG_EMBEDDED /DUNICODE /D_UNICODE \
!if $(HAVE_UXTHEME_H)
/DHAVE_UXTHEME_H=1 \
diff --git a/win/rules.vc b/win/rules.vc index 2b11b01..50911d4 100644 --- a/win/rules.vc +++ b/win/rules.vc @@ -24,7 +24,7 @@ _RULES_VC = 1 # For modifications that are not backward-compatible, you *must* change
# the major version.
RULES_VERSION_MAJOR = 1
-RULES_VERSION_MINOR = 4
+RULES_VERSION_MINOR = 5
# The PROJECT macro must be defined by parent makefile.
!if "$(PROJECT)" == ""
@@ -976,6 +976,19 @@ VERSION = $(DOTVERSION:.=) !endif # $(DOING_TCL) ... etc.
+# Windows RC files have 3 version components. Ensure this irrespective
+# of how many components the package has specified. Basically, ensure
+# minimum 4 components by appending 4 0's and then pick out the first 4.
+# Also take care of the fact that DOTVERSION may have "a" or "b" instead
+# of "." separating the version components.
+DOTSEPARATED=$(DOTVERSION:a=.)
+DOTSEPARATED=$(DOTSEPARATED:b=.)
+!if [echo RCCOMMAVERSION = \> versions.vc] \
+ || [for /f "tokens=1,2,3,4,5* delims=." %a in ("$(DOTSEPARATED).0.0.0.0") do echo %a,%b,%c,%d >> versions.vc]
+!error *** Could not generate RCCOMMAVERSION ***
+!endif
+!include versions.vc
+
################################################################
# 10. Construct output directory and file paths
# Figure-out how to name our intermediate and output directories.
@@ -1490,7 +1503,7 @@ GUIEXECMD = $(link32) $(guilflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) RESCMD = $(rc32) -fo $@ -r -i "$(GENERICDIR)" -i "$(TMP_DIR)" \
$(TCL_INCLUDES) \
/DDEBUG=$(DEBUG) -d UNCHECKED=$(UNCHECKED) \
- /DCOMMAVERSION=$(DOTVERSION:.=,),0 \
+ /DCOMMAVERSION=$(RCCOMMAVERSION) \
/DDOTVERSION=\"$(DOTVERSION)\" \
/DVERSION=\"$(VERSION)\" \
/DSUFX=\"$(SUFX:t=)\" \
@@ -948,6 +948,8 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ [Defined when cygwin/mingw ignores VOID define in winnt.h]) fi + AC_CHECK_HEADER(stdbool.h, [AC_DEFINE(HAVE_STDBOOL_H, 1, [Do we have <stdbool.h>?])],) + # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. diff --git a/win/tkWinFont.c b/win/tkWinFont.c index 11385ed..e4f0624 100644 --- a/win/tkWinFont.c +++ b/win/tkWinFont.c @@ -2232,7 +2232,7 @@ FontMapLoadPage( end = (row + 1) << FONTMAP_SHIFT; for (i = row << FONTMAP_SHIFT; i < end; i++) { if (Tcl_UtfToExternal(NULL, encoding, src, - Tcl_UniCharToUtf(i, src), TCL_ENCODING_STOPONERROR, NULL, + TkUniCharToUtf(i, src), TCL_ENCODING_STOPONERROR, NULL, buf, sizeof(buf), NULL, NULL, NULL) != TCL_OK) { continue; } diff --git a/win/tkWinKey.c b/win/tkWinKey.c index c3816bf..8a83874 100644 --- a/win/tkWinKey.c +++ b/win/tkWinKey.c @@ -124,7 +124,7 @@ TkpGetString( if (((keysym != NoSymbol) && (keysym > 0) && (keysym < 256)) || (keysym == XK_Return) || (keysym == XK_Tab)) { - len = Tcl_UniCharToUtf(keysym & 255, buf); + len = TkUniCharToUtf(keysym & 255, buf); Tcl_DStringAppend(dsPtr, buf, len); } } diff --git a/win/tkWinPointer.c b/win/tkWinPointer.c index 2b8656b..e7e041f 100644 --- a/win/tkWinPointer.c +++ b/win/tkWinPointer.c @@ -362,8 +362,8 @@ void TkSetCursorPos( int y) { INPUT input; - unsigned xscreen = (GetSystemMetrics(SM_CXSCREEN) - 1); - unsigned yscreen = (GetSystemMetrics(SM_CYSCREEN) - 1); + int xscreen = (int)(GetSystemMetrics(SM_CXSCREEN) - 1); + int yscreen = (int)(GetSystemMetrics(SM_CYSCREEN) - 1); input.type = INPUT_MOUSE; input.mi.dx = (x * 65535 + xscreen/2) / xscreen; diff --git a/win/tkWinWm.c b/win/tkWinWm.c index d273b4c..e6a0a4b 100644 --- a/win/tkWinWm.c +++ b/win/tkWinWm.c @@ -4379,9 +4379,9 @@ WmIconphotoCmd( if (!iconInfo.hbmColor) { ckfree(lpIR); Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "failed to create color bitmap for \"%s\"", + "failed to create an iconphoto with image \"%s\"", Tcl_GetString(objv[i]))); - Tcl_SetErrorCode(interp, "TK", "WM", "ICONPHOTO", "BITMAP", NULL); + Tcl_SetErrorCode(interp, "TK", "WM", "ICONPHOTO", "IMAGE", NULL); return TCL_ERROR; } @@ -5189,18 +5189,18 @@ WmStackorderCmd( if (objc == 3) { windows = TkWmStackorderToplevel(winPtr); - if (windows == NULL) { - Tcl_Panic("TkWmStackorderToplevel failed"); - } - - resultObj = Tcl_NewObj(); - for (windowPtr = windows; *windowPtr ; windowPtr++) { - Tcl_ListObjAppendElement(NULL, resultObj, - TkNewWindowObj((Tk_Window) *windowPtr)); + if (windows != NULL) { + resultObj = Tcl_NewObj(); + for (windowPtr = windows; *windowPtr ; windowPtr++) { + Tcl_ListObjAppendElement(NULL, resultObj, + TkNewWindowObj((Tk_Window) *windowPtr)); + } + Tcl_SetObjResult(interp, resultObj); + ckfree(windows); + return TCL_OK; + } else { + return TCL_ERROR; } - Tcl_SetObjResult(interp, resultObj); - ckfree(windows); - return TCL_OK; } else { TkWindow *winPtr2, **winPtr2Ptr = &winPtr2; int index1 = -1, index2 = -1, result; @@ -6807,8 +6807,6 @@ TkWmStackorderToplevel( (LPARAM) &pair) == 0) { ckfree(windows); windows = NULL; - } else if (pair.windowPtr != (windows-1)) { - Tcl_Panic("num matched toplevel windows does not equal num children"); } done: diff --git a/xlib/X11/Xlib.h b/xlib/X11/Xlib.h index e1ae7f1..44f556f 100644 --- a/xlib/X11/Xlib.h +++ b/xlib/X11/Xlib.h @@ -589,7 +589,7 @@ typedef struct _XDisplay { #endif #ifndef _XEVENT_ -#define XMaxTransChars 4 +#define XMaxTransChars 7 /* * Definitions of specific events. @@ -610,7 +610,7 @@ typedef struct { Bool same_screen; /* same screen flag */ char trans_chars[XMaxTransChars]; /* translated characters */ - int nbytes; + unsigned char nbytes; } XKeyEvent; typedef XKeyEvent XKeyPressedEvent; typedef XKeyEvent XKeyReleasedEvent; |